Late Binding Macro - vilinski/nemerle GitHub Wiki

Late Binding Macro changes nemerle syntax to allow use of so called duck typing.

Table of Contents

Availability

Implementation initially available from Snaury's page is now commited and maintained in Nemerle's standard distribution. The next release will allow you to use it without any additional code.

Summary

After adding using Nemerle.Late to your code you will get two statements which you can use in your code: late and nolate.

Basic Usage

Using macros is as simple as:

 late(''late-expr'')
 late late-expr
 nolate(''expr'')
 nolate expr

Where late-expr and expr are any valid Nemerle expressions, with the exception that late-expr is processed in a special way.

def create_some_application() {
  System.Activator.CreateInstance(System.Type.GetTypeFromProgID("Some.Application"))
}

def app = create_some_application();
def file = late app.OpenFile("somefile.txt", openmode = "rw");
late {
  def updated = file.Record[0].Update() :> bool;
  file.Record[1].MarkedForDeletion = updated;
}

Syntax

late macro scans deeply inside late-expr and in most cases treats late-expr as a normal nemerle expression. However, in some special cases it does late binding. Here are these cases:

ref_or_out = 'ref' | 'out'
parameter = [ IDENTIFIER '=' ] [ ref_or_out ] late-expr
parameters = [ parameter [ { ',' parameter } ] ]
set_property = late-bound-expr '.' IDENTIFIER '=' late-expr
set_named_indexer = late-bound-expr '.' IDENTIFIER '[' parameters ']' '=' late-expr
set_default_indexer = late-bound-expr [ '.' ] '[' parameters ']' '=' late-expr
get_property = late-bound-expr '.' IDENTIFIER
get_named_property = late-bound-expr '.' IDENTIFIER '[' parameters ']'
get_default_property = late-bound-expr [ '.' ] '[' parameters ']' '=' late-expr
invoke_method = late-bound-expr '.' IDENTIFIER '(' parameters ')'
do_not_process = 'late' '(' late-expr ')' | 'late' late-expr | 'nolate' '(' expr ')' | 'nolate' expr

Where late-bound-expr is any expression except this, base or existing class name.

Note: Optional dot for default_indexer is a feature to make constructs like this possible:

def o = System.Windows.Forms.Form();
def r = late o.Name.[0]; // obtains first letter of property Name

Because if you write late o.Name[0] it means you want to access indexer Name on Form (which does not exist), not default indexer on property Name on Form.

Note: When late macro sees a do_not_process expression it does not look inside of it and uses it as is. This allows one to write embedded late expressions, as well as temporarily turning off late-binding:

late {
  // here the first Count is retrieved using late binding, second Count retrieved statically
  printf("%d - %d\n", this.Controls.Count, nolate this.Controls.Count);
}

About named parameters

Named parameters are always substituted for parameters of target call. However one must note, that because of this, unnamed parameters do not have a specific place bound to them, i.e.:

public class SomeClass {
  public SomeMethod(a : int, b : int, c : int, d : int) : void { ... }
}

def o = SomeClass()
_ = late(o).SomeMethod(1, a = 2, 3, c = 4); // note, it called: SomeMethod(2, 1, 4, 3)

Warning: There is a bug in DefaultBinder on MS.NET which sometimes binds named parameters in wrong places. The advise here will be to avoid using named parameters if you are specifying more than two named parameters and when you are doing late-binding on CLI classes (i.e. this bug does not happen on MarshalByRef and ComObject targets). An example when you can encounter this bug:

#pragma indent

using Nemerle.IO
using Nemerle.Late

public class TestClass
  public Method(a : int, b : int, c : int) : int
    printf("TestClass.TestMethod(%d,%d,%d)\n", a, b, c)
    a + b + c

def o = TestClass() : object
def n = late o.Method(c = 1, a = 2, b = 3)

In the above example TestClass.Method(3,1,2) was called on MS.NET.

Known Problems

  • Operators are not made dynamic, so using them on late bound methods will probably yield error from compiler about using operator on object types. We are still considering feasibility of searching the proper op_Addition - like methods in given types for execution.
⚠️ **GitHub.com Fallback** ⚠️