Lambdas

Top  Previous  Next

Lambda expressions are a popular shorthand syntax for anonymous methods. In SmartMS, you can use Lambda Expressions and anonymous methods together! Lambda Function are used when the code expects an anonymous function and when the code implementing this function is short.

 

Given a function like this:

Code example: anonymous methods reference to function type

type

  TIntegerConvertFunc = reference to function(s: string): integer;  // Has a return type

 

procedure TForm1.W3Button18Click(Sender: TObject);

var

  myFunction: TIntegerConvertFunc;

 

begin

  myfunction :=

    function(s: string): integer

    begin

      result := StrToInt(s);

    end;

 

myfunction('abcd');

end;  

 

There are three main parts of the function.

·The parameter list: (s: string)

Parameters are enclosed in parentheses. Multiple statements and parameters can be used, but much of the simplification goes away.

Parameterless functions and procedures can also be used.  Usually, an empty parameter list is provided with a pair of parentheses.

 

 

·The return type:  integer

While functions are usually used with Lambda expressions, procedures can be used too.  If the expression does not evaluate to anything, it generally requires that the result not be assigned to anything.

In C# and to some extent in SmartMS, the type of the parameters and the function result can be determined very effectively by the compiler based on context, alleviating the need to specify these types.  This is called "Type Inference" and further simplifies the code.

       

·The method body: StrToInt(s)

Because there is only one line and it is the result assignment, the assignment to result can be omitted, leaving just an expression to be evaluated.  Hence, the "result :=" is removed.

 

 

Here are examples in SmartMS.

 

 

Code example: Anonymous methods with lambdas

type

  TProc = reference to procedure;

type

  TIntegerConvertFunc = reference to function(s: string): integer;  // Has a return type

 

{---------------}

 

procedure TForm1.W3Button19Click(Sender: TObject);

var

  myAnonymousMethod: TProc;

  myFunction: TIntegerConvertFunc;

begin

 myAnonymousMethod :=

    lambda

    begin

      writeln('This was written from an anonymous method');

    end

 end;

myAnonymousMethod;  // Invoking an anonymous method

 

{-----------------------------------------}

  myfunction :=

    lambda (s: string)

    begin

      WriteLn( StrToInt(s) );

    end

  end;

 

myfunction('123456');

 

end;  

 

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;

 end,

 lambda

  //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. 

 

Code example: Anonymous functions with lambdas

 

client := TSQLRestClientHTTP.Create(ServerAddress.Text, 888, model, false);

 

client.Connect(

  lambda

  if client.ServerTimeStamp = 0 then

    ShowMessage('Impossible to retrieve server time stamp')

  else

    writeln('ServerTimeStamp=' + IntToStr(client.ServerTimeStamp));

  if not client.SetUser(TSQLRestServerAuthenticationDefault, LogonName.Text,

    LogonPassWord.Text) then

    ShowMessage('Authentication Error');

  writeln('Safely connected with SessionID=' +

    IntToStr(client.Authentication.SessionID));

  people := TSQLRecordPeople.Create(client, 1); 

  assert(people.ID = 1);

  writeln('Disconnect from server');

  client.Free;

end,

lambda

ShowMessage('Impossible to connect to the server');

 

end );

 

 

 

Lambdas are also very helpful when defining event handlers.

 

procedure TForm1.W3Button24Click(Sender: TObject);

begin

W3Button21.OnClick :=

   lambda

    Application.ShowDialog('Welcome','select something',aoYesNo);

   end

end;

 

 

 

Code example: anonymous method version 1

procedure MyProc;

begin

 showmessage('You clicked the back button 2 seconds ago');

end;

 

procedure TForm1.W3Button20Click(Sender: TObject);

var proc : TProcedureRef;

begin

 

W3Button21.onClick := Procedure (sender:TObject)

         Begin

            w3_callback(MyProc, 2000);

         end;

end;

 

Code example: anonymous method version 2

W3Button21.onClick := Procedure (sender:TObject)

         Begin

            w3_callback(procedure()

                    begin

                       showmessage('You clicked the back button 2 seconds ago');

                    end2000);

         end;

 

 

Code example: anonymous method with lambdas ver 1

 

W3Button21.onClick := Procedure (sender:TObject)

         Begin

            w3_callback(lambda

            Begin

              showmessage('You clicked the back button 2 seconds ago')

            End;

            end2000);

         end

 

 

Code example: anonymous method with lambdas ver 2

 

W3Button21.onClick := lambda(sender)

begin

  w3_SetTimeout(lambda

    begin

      showmessage('You clicked the back button 2 seconds ago');

    end

end2000);

end;

end;

 

 

 

 

   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);

 

 

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);