Параметры не типового типа - PullRequest
0 голосов
/ 11 октября 2018

Что если у меня есть классы, которые отличаются только некоторой константой, используемой в коде.Можно ли иметь одну универсальную реализацию без затрат времени выполнения?

Вот пример (это немного слишком долго ...)

@:enum abstract Param(Int) {
    var foo = 0;
    var bar = 1;
}

class WorkBase {

    public function new() {}

    private inline function work_impl(p: Param): Void {

        if(p == foo) {
            trace('foo');
        }
        else {
            trace('bar');
        }
    }

    public function work(): Void {

    }
}

class WorkFoo extends WorkBase{
    override public function work(): Void {
        work_impl(foo);
    }
}

class WorkBar extends WorkBase {
    override public function work(): Void {
        work_impl(bar);
    }
}

class Test {

    public static function main() {
        var workFoo = new WorkFoo();
        var workBar = new WorkBar();
        workFoo.work();
        workBar.work();
    }
}

После компиляции с -D analyzer-optimize мы будемобратите внимание, что функции WorkFoo.work() и WorkBar.work() были оптимизированы и содержат только одну ветвь кода, которая соответствует одному из значений Param.В реальной жизни в 1010 * таких сравнений много, и все они оптимизированы.Это хорошо.

Но что, если я не хочу создавать WorkFoo и WorkBar вручную.Можно ли сделать что-то вроде этого:

@:generic
class WorkBase<PARAM> {
    private inline function work_impl(p: Param): Void {
        ...
    }

    public function work(): Void {
        work_impl(PARAM);
    }
}

Самая близкая вещь, которую я знаю, это const-type-параметр .Но я не считаю, что универсальная сборка - это хороший выбор.

1 Ответ

0 голосов
/ 11 октября 2018

Самая близкая вещь, которую я знаю, это const-type-параметр.Но я не считаю, что универсальная сборка - хороший выбор здесь.

Параметры типа const можно использовать без @:genericBuild - параметра типа const в сочетании с @:generic достаточно для получения желаемой оптимизации:

@:enum abstract Param(Int) from Int {
    var foo = 0;
    var bar = 1;
}

@:generic class Work<@:const PARAM:Int> {
    public function new() {}

    public function work():Void {
        if (PARAM == foo) {
            trace('foo');
        } else {
            trace('bar');
        }
    }
}

class Main {
    public static function main() {
        var workFoo = new Work<0>();
        var workBar = new Work<1>();
        workFoo.work();
        workBar.work();
    }
}

Из-за @:generic для каждого значения константы генерируется один класс, например, на JS выходные данные выглядят так:

var Work_$0 = function() {
};
Work_$0.prototype = {
    work: function() {
        console.log("source/Main.hx:11:","foo");
    }
};
var Work_$1 = function() {
};
Work_$1.prototype = {
    work: function() {
        console.log("source/Main.hx:13:","bar");
    }
};

Обратите внимание, что в этом примере происходит сбой с«Ошибка проверки ограничения» в Haxe 3.4.7 по какой-то причине, но отлично работает с Haxe 4 preview 4 и более поздними версиями.Другое ограничение заключается в том, что ни new Work<Param.foo>(), ни new Work<foo>() не работают - вам нужно передать фактическое постоянное значение.

...