мая 31, 2010

dpp: лямбда-функции

Занялся написанием лямбда-функций.

Когда нужно написать очень небольшую функцию, в одну-две строчки, и вызвать ее только в одном месте, то не хочется прописывать метод у класса, потом реализовывать код в implementation-части, и только после этого его вызывать. Хотелось бы эту жалкую строку с кодом прописать сразу в месте вызова.

Именно эту проблему и решают мои лямбда-функции:
FButton.OnClick := #l(Button: TButton) FWindow.Close;

Конструкция #l создает метод у класса, внутри которого она вызывается. Так записывается вызов процедуры и функции соответственно:
ObjectUpdate := #l(Obj: TMyObject) Obj.Update;
ObjectFilter := #l(Obj: TMyObject): Boolean = Obj is TSuperObject;

Внутри можно писать и несколько операторов, разделенных символом ;

Есть так же возможность создать лямбду на классовый метод или даже просто функцию, делается это заменой l на lsimple.

lsimple уже реализовано и работает.

При реализации сразу же я столкнулся с множеством проблем.

Во-первых, сигнатуру функции: параметры и возвращаемое значение, - в теории можно опустить, т.к. они очевидно восстанавливаются по левой части выражения. На практике же, определить какой тип имеет левая часть выражения - весьма трудоемкая задача и в рамках моей небольшой утилитки dpp ее реализация не представляется возможной.

Во-вторых, есть более серьезная проблема при использовании локальных переменных. Например, сейчас такой код не заработает:
for I := 0 to 3 do
    FButtons[I].OnClick := #l(Button: TButton) FWindows[I].Show;
хотя очень хотелось бы.

Даже если отбросить тот факт, что это сложно реализовать технически (нужно создавать промежуточный класс, который запомнит значение переменной I в момент вызова, и у этого класса могут начаться трудности в получении доступа к приватному полю FWindows, да и вообще к FWindows нужно будет каким-то макаром приписать что-то типа FOwner.FWindows), даже отбросив - совершенно непонятно сколько этот класс должен жить в памяти. Узнать когда кнопка перестанет ссылаться на метод этого класса невозможно.

Кроме того, хочется в дальнейшем делать встроенные лямбы, а не только в конце строк:
RegistHandler($10, $32, #l(Packet: TPacket) DoSomething#);
А в этом плане символ # очень неудачен, трудно определить кто из них открывающий, а кто закрывающий, и при вложенностях получится путаница.

Поэтому, наверно, будет введена конструкция [# ... #] для встроенных в строки команд.


Комментариев нет:

Отправить комментарий

Постоянные читатели

Обо мне

Моя фотография
Мой e-mail: vitek_03(at)mail(dot)ru