Факторинг кода, сохранение читабельности и улучшение жизни :)

Я только начинаю изучать язык программирования D и с удовольствием играю с ключевыми словами делегата и функции. Я пытаюсь реализовать (только для собственного учебного процесса) знаменитый класс Deferred из твиста (написанного на Python).

Мне просто интересно, есть ли какие-то хитрости, чтобы выделить такой код:

class Deferred(ResultType)
{
    alias ResultType delegate(ResultType) CallbackType;

    private CallbackType[2] _callbacks[];

    private bool _running;
    private uint _paused;

    void addCallback(CallbackType cb)
    {
        this._callbacks ~= [cb, cast(CallbackType) null];
    }

    void addCallback(void function() f)
    {
        this.addCallback(
            (ResultType res) { f(); return res; }
        );
    }

    void addCallback(void function(ResultType) f)
    {
        this.addCallback(
            (ResultType res) { f(res); return res; }
        );
    }

    void addCallback(ResultType function() f)
    {
        this.addCallback(
            (ResultType res) { return f(); }
        );
    }

    void addCallback(ResultType function(ResultType) f)
    {
        this.addCallback(
            (ResultType res) { return f(res); }
        );
    }

}

Цель состоит в том, чтобы разрешить пользователю передавать не делегат CallbackType, а некоторую функцию с правильным типом аргумента/возврата или без него. Я пропустил какой-то важный момент здесь?

[EDIT]: с советами Mehrdad ответ может быть примерно таким:

class Deferred(ResultType)
{
    alias ResultType delegate(Deferred, ResultType) CallbackType;

    private CallbackType[2] _callbacks[];

    void addCallback(T)(T cb)
    {
        this._callbacks ~= [this._makeConvenient(cb), cast(CallbackType) null];
    }

    private CallbackType _makeConvenient(T)(T f)
    {
        alias traits.ReturnType!(f) ReturnType;
        alias traits.ParameterTypeTuple!(f) Params;

        return (Deferred d, ResultType res)
        {
            ReturnType wrapper()
            {
                static if (Params.length == 2)
                {
                    static if (is(Params[0] == Deferred!(ResultType)) && is(Params[1] == ResultType))
                        return f(this, res);
                    else
                        static assert(false, "Cannot wrap given callback: Wrong arguments types");
                }
                else static if (Params.length == 1)
                {
                    static if (is(Params[0] == Deferred!(ResultType)))
                        return f(this);
                    else static if (is(Params[0] == ResultType))
                        return f(res);
                    else
                        static assert(false, "Cannot wrap given callback: Wrong argument type");
                }
                else static if (Params.length == 0)
                    return f();
                else
                    static assert(false, "Cannot wrap given callback: Wrong argument number");
            }

            static if (is(ReturnType == void)) { wrapper(); return res; }
            else static if (is(ReturnType == ResultType)) { return wrapper(); }
            else static assert(false, "Cannot wrap given callback: Wrong return type");
        };
    }
}

Я на правильном пути? Есть ли заметные проблемы с производительностью?


d
person Raphaël Londeix    schedule 02.05.2011    source источник
comment
Название этого поста было бы лучше, если бы оно было более конкретным. Я сам не уверен, как именно это улучшить, эти инструменты не моя сумка.   -  person eric    schedule 22.08.2014


Ответы (1)


Это должно сделать это:

class Deferred(ResultType)
{
    alias ResultType delegate(ResultType) CallbackType;

    private CallbackType[2] _callbacks[];

    private bool _running;
    private uint _paused;

    void addCallback(CallbackType cb)
    {
        this._callbacks ~= [cb, cast(CallbackType) null];
    }

    void addCallback(TFn)(TFn f) //Put template restrictions here if you want
    {
        this.addCallback((ResultType res)
        {
            static if (is(typeof(f(res)) == void)) { f(res); return res; }
            else static if (is(typeof(f()) == void)) { f(); return res; }
            else static if (is(typeof(f(res) == ResultType))) { return f(res); }
            else { return f(); }
        });
    }
}

Это не намного лучше, но все в порядке, я думаю.

person user541686    schedule 02.05.2011
comment
Большое спасибо ! Является ли попытка is(typeof(f()) == void) лучшим способом узнать, действительно ли f принимает параметр или нет? - person Raphaël Londeix; 02.05.2011
comment
@Raphael: правильный способ сделать это — изучить результат ParameterTypeTuple!(f) , но этот был короче, поэтому я его и использовал. Если вам нужна дополнительная информация, используйте ее вместо этого. - person user541686; 02.05.2011
comment
Я отредактировал свой первый пост, используя лучший способ :) На самом деле, я прочитал, что выражение is(typeof(f(res) == ResultType) проверяет равенство типов, а is(typeof(f(res)) : ResultType) проверяет преобразование типов, что в этом случае может будь более гибким :P - person Raphaël Londeix; 04.05.2011