On 17/04/2021 5:34 pm, fredvs wrote:
> There was some work done to make it work:
> https://github.com/mse-org/mselang/releases
> 
> I was able to do some console application on Linux (the version of LLVM for
> Windows was not yet working when I try it 3 years ago).

Thank you Fred for all the information. I'm looking at the MSELang repo
as we speak.

The reason I ask, I was comparing Delphi's Anonymous Methods (lambdas) + 
Generics
to how Java does it. It is crazy how verbose Embarcadeco made the syntax. The 
compiler
is supposed to be inteligent, yet with the Delphi syntax, you are spoon-feeding
the compiler with things it could have figured out from the code itself, and 
often
duplicating information. You really don't save much typing that way.

I'm toying with the idea of experimenting with the Free Pascal Compiler, and
was looking at maybe contributing to FPC (if they don't want it - most
likely outcome - as they only like to copy Embarcadero), then the other option
might be MSELang. But I don't know anything about MSELang and what its
goals were. But I've got a better idea now - thanks to all your links.


The rest of this message is optional... ;-)

Here is a simple example:
========[ As done in Delphi ]========================
type
  TSimpleProcedure = reference to procedure;
  TSimpleFunction = reference to function(x: string): Integer;

var
  x1: TSimpleProcedure;
  y1: TSimpleFunction;

begin
  x1 := procedure
    begin
      Writeln('Hello World');
    end;
  x1;   //invoke anonymous method just defined

  y1 := function(x: string): Integer
    begin
      Result := Length(x);
    end;
  Writeln(y1('bar'));
end.
==================[ end Delphi ]=====================


Now for my idea...

There are some standard "functional interfaces" defined in the RTL like,
but in your own code, you can define your own ones too. The compile will
treat them in the same way is I describe here:

type
  // Represents a function that accepts one argument and produces a result.
  IFunction<T,R> = interface
    function apply(T): R;
  end;

  // Represents a predicate (boolean-valued function) of one argument.
  IPredicate<T> = interface
    function test(T): boolean;
  end;

  // Represents an operation that accepts a single input argument and returns 
no result.
  IConsumer<T> = interface
    procedure accept(T);
  end;

  // Represents a supplier of results.
  ISupplier<T> = interface
    function get: T;
  end;

  // Represents a prodecute that takes no argument and produces no result.
  IRunnable = interface
    procedure run;
  end;


You can then use those in anonymous methods like this:

========[ Mine ]===================================
var
  x1: IRunnable;
  y1: IFunction<string, integer>;

begin
  x1 := () -> Writeln('Hello World');               (1)
  x1;   //invoke anonymous method just defined

  y1 := s -> Result := Length(s);                 (2)
  Writeln(y1('bar'));
end.
==================[ end Mine ]=====================


(1) - The () syntax lists any parameters. It's empty, so no parameters
      are used. They are only required if the parameter list is empty.
    - The -> syntax borrows from Java and lets the compiler know this
      is a lambda (anonymous method)
    - IRunnable's method takes no parameters and has no return type
    - The code after the -> is the body of the method. This is a 1 line
      body, so doesn't require the verbose begin/end pair.

IRunnable is a "functional inteface" with only one method that needs
to be implemented. From that the compiler knows the name and signature
of the method, by looking it up from the interface definition. The
compiler can construct a anonymous class to implement the anonymous
method. That could automatically result in something like this - all
done by the compiler itself:

type
  TInternalAnonymousClassName = class(TInterfaceObject) implements IRunnable
  public
    function run;
  end;

  TInternalAnonymousClassName.run;
  begin
    Writeln('Hello World');
  end;

(2) - The process is pretty much the same as (1), but this time the
      functional inteface signater is different.
    - IFunction takes one parameter and returns a result.
    - The definition of y1 tells the compiler that the parameter
      is of type String and the return type is of type Integer.
      So when you define the lambda, you don't have to repeat the
      data type information
    - s is the name of the parameter, and the compiler already knows
      is must be of type String.
    - agian it's a one line method, so no need for the begin/end pair.

type
  TInternalAnonymousClassName = class(TInterfaceObject) implements IFunction
  public
    procedure apply(s: String): Integer;
  end;

  TInternalAnonymousClassName.apply(s: String): Integer;
  begin
    Result := Length(s);
  end;



Regards,
  Graeme


_______________________________________________
mseide-msegui-talk mailing list
mseide-msegui-talk@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mseide-msegui-talk

Reply via email to