Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I solve 'Duplicate Constructor' error in Haxe?

In Haxe, I created a class named MyClass like:

class MyClass {

    var score: String;

    public function new (score: Int) {
        this.score = Std.string(score);
    }

    public function new (score: String) {
        this.score = score;
    }
 }

I need multiple constructors but Haxe does not allow me to do. It throws this error from building phase:

*.hx:*: lines * : Duplicate constructor
The terminal process terminated with exit code: 1

How can I solve this problem?

like image 687
Enes F. Avatar asked Jan 01 '23 16:01

Enes F.


1 Answers

This is known as method overloading, which is not supported by Haxe apart from externs (but might be in the future). There's multiple ways you could work around this.

A common workaround in the case of constructors would be to have a static "factory method" for the second constructor:

class MyClass {
    var score:String;

    public function new(score:String) {
        this.score = score;
    }

    public static function fromInt(score:Int):MyClass {
        return new MyClass(Std.string(score));
    }
}

You could also have a single constructor that accepts both kinds of arguments:

class MyClass {
    var score:String;

    public function new(score:haxe.extern.EitherType<String, Int>) {
        // technically there's no need for an if-else in this particular case, since there's
        // no harm in calling `Std.string()` on something that's already a string
        if (Std.is(score, String)) {
            this.score = score;
        } else {
            this.score = Std.string(score);   
        }
    }
}

However, I wouldn't recommend this approach, haxe.extern.EitherType is essentially Dynamic under the hood, which is bad for type safety and performance. Also, EitherType is technically only intended to be used on externs.

A more type-safe, but also slightly more verbose option would be haxe.ds.Either<String, Int>. Here you'd have to explicitly call the enum constructors: new MyClass(Left("100")) / new MyClass(Right(100)), and then use pattern matching to extract the value.


An abstract type that supports implicit conversions from String and Int might also be an option:

class Test {
    static function main() {
        var s1:Score = "100";
        var s2:Score = 100;
    }
}

abstract Score(String) from String {
    @:from static function fromInt(i:Int):Score {
        return Std.string(i);
    }
}

Finally, there's also an experimental library that adds overloading support with macros, but I'm not sure if it supports constructors.

like image 126
Gama11 Avatar answered Jan 13 '23 13:01

Gama11