March 22, 2013

New in Smart 1.1: Lambdas

Version 1.1 introduced more compact syntax for closures, similar to the C#'s syntax with an extra lambda keyword thrown at the front. Two different types of `lambda` closures are supported -- functions and statements.

Lambda Functions

Lambda functions are used when the code expects an anonymous function and when the code implementing this function is short. The syntax for lambda functions is:

lambda (parameter_list) => expression

The lambda keyword is followed by an optional parameter list, => and an expression returning a result of the appropriate type.

For example, the following code creates an event that is called every five seconds.

var repeater := TW3EventRepeater.Create(
  function (Sender: TObject): boolean
  begin
    Result := MyFunction;
  end,
  5000);

Anonymous method calls some function in the code and returns its result. (False will trigger another event after the timeout (5000 ms) and True will stop the repeater.)

Let's rewrite this code using a lambda function.

var repeater := TW3EventRepeater.Create(lambda (Sender) => MyFunction, 5000);

As you can see, there's no need to declare the parameter (Sender) type and the function result type; Smart will detect them automatically. Even more, as we don't use the Sender parameter, we can drop the parameter list and use an even shorter form.

var repeater := TW3EventRepeater.Create(lambda => MyFunction, 5000); 

Lambda Statements

The statement form is used when you want to put more than one statement inside the lambda. The syntax for lambda statement is:
lambda (parameter_list)  statement;  [statement;]  [...]
  [statement;]
end

A lambda statement can also implement a function; in that case you should return the result in a normal Delphi way by assigning to a Result pseudo-variable.

Following example sets up a repeater that calls a method MyProc every three seconds.

var repeater := TW3EventRepeater.Create(lambda => MyProc; Result := false; end, 5000);

You can use variables inside a lambda statement, but only if they are declared inline.

Lambdas are an excellent addition to the language, as they provide for a more compact code. For example, in Smart 1.0 the W3Layout unit used the following code:

ResizeChildren(FClientArea.Height, [TAlign.Top, TAlign.Bottom],
  function (layout: TLayoutImpl): Variant
  begin
    Result := layout.GetConfig.GetHeight;
  end,
  procedure (layout: TLayoutImpl; value: integer)
  begin
    layout.GetConfig.Height(value);
  end);

In Smart 1.1, this was simplified to:

ResizeChildren(FClientArea.Height, [TAlign.Top, TAlign.Bottom],
  lambda (layout) => layout.GetConfig.GetHeight,
  lambda (layout, value) layout.GetConfig.Height(value) end);

Lambdas are also very helpful when defining event handlers.

W3btnOK.OnClick := lambda Application.HideModal(mrOK); end;

No comments:

Post a Comment