L supports what might be called variously function pointers, bound method references and closures via values of proc type. Values of proc type are created from a method name or a literal procedure and can then later be 'deprocedured' using the normal method call syntax of parentheses plus an option list of parameters. Proc refs are structurally typed.
Source:
Expand


namespace Proc is
    class Main is
        void init() is
            // create a random binary search tree:
            var r = Tree.RandomTree;

            // static proc ref:
            // visit each node in pre-order calling a static method of
            // this class at each node. This is roughly equivalent to a
            // function pointer in C:


            var p = void proc(Tree)(static_visit);
            IO.Std.out.println( "visit " + r + " with static proc ref in pre-order" );
            IO.Std.out.println( "proc is: " + p );
            r.visit(p, Order.PRE);

            // bound proc ref:
            // visit each node in post-order calling a virtual method of
            // this class at each node. Virtual method resolution is performed
            // here when the proc ref is created. 'this' in the called procedure
            // will reference the same object as 'this' at proc ref creation time.

            p = void proc(Tree)(bound_visit);
            IO.Std.out.println( "visit " + r + " with bound proc ref in post-order" );
            IO.Std.out.println( "proc is: " + p );
            r.visit(p, Order.POST);

            // bound proc ref, procedure literal:
            // visit each node in-order calling a literal procedure
            // at each node. A literal procedure can be static or virtual
            // depending on whether the method it is nested in is static or
            // virtual. In this case the method is virtual:
            p = void proc(Tree t) is
                   IO.Std.out.println( "literal visit from " + this + ": " + t.Value );
                si;

            IO.Std.out.println( "visit " + r + " with proc literal in order" );
            IO.Std.out.println( "proc is: " + p );

            r.visit(p, Order.IN);


            // closure proc ref:
            // visit each node in pre-order calling a literal proc with
            // additional associated (read only) variables. This is a
            // form of closure which is efficient when a small number of
            // read only captured values is wanted:

            // create some variables that will be captured by the closure:
            var a = "A", b = "B", c = "C";

            IO.Std.out.println( "visit " + r + " with closure proc ref in pre-order: " );
            IO.Std.out.println( "proc is: " + p );
            p = void proc(Tree t) use a, b, c is
                    IO.Std.out.println( "literal visit from " + this + "(" + a + "," + b + "," + c + "): " + t.Value );
                si;

            r.visit(p, Order.PRE);

            // bound proc ref, object of different class:
            // visit each node in pre-order calling a virtual method on an
            // object of a different class. Virtual method resolution is
            // performed here based on the the class of the supplied object and
            // 'this' in the called procedure is bound to that object. This
            // is an alternate form of closure suitable where captured state
            // is larger or needs to be altered across calls
            p = void proc(Tree)(new Other("A", "B", "C").visit);
            IO.Std.out.println( "visit " + r + " with bound proc ref in post-order: " );
            IO.Std.out.println( "proc is: " + p );
            r.visit(p, Order.POST);
        si

        static void static_visit(Tree t) is
            IO.Std.out.println( "static visit: " + t.Value );
        si

        void bound_visit(Tree t) is
            IO.Std.out.println( "bound visit from " + this + ": " + t.Value );
        si       

        String toString() is
            return "Proc.Main";
        si
    si

    class Other is 
        String a, b, c;

        void init( String a, String b, String c ) is
            this.a = a;
            this.b = b;
            this.c = c;
        si

        void visit( Tree t ) is
            IO.Std.out.println( "visit from " + this + ": " + t.Value );
        si

        String toString() is
            return "Other(" + a + "," + b + "," + c + ")";
        si
    si

    enum Order is
        PRE,
        IN,
        POST
    si

    class Tree is
        int value;
        Tree left, right;
        
        void init( int v ) is
            this.value = v;
        si

        static void insert( Tree ref into, int value ) is
            if into == null then
                into = new Tree(value);
            elif value < into.value then
                insert(into.left,value);
            else
                insert(into.right,value);
            fi
        si

        void visit( void proc(Tree) p, Order o ) is
            if o == Order.PRE then
                p(this);
            fi

            if left != null then
                left.visit(p, o);
            fi

            if o == Order.IN then
                p(this);
            fi

            if right != null then
                right.visit(p, o);
            fi

            if o == Order.POST then
                p(this);
            fi
        si

        get int Value is
            return value;
        si

        String toString() is
            var b = new StringBuffer();
            b
                .append( '(' )
                .append( value );

            if left != null then
                b
                    .append( ',' )
                    .append( left );
            fi

            if right != null then
                b
                    .append( ',' )
                    .append( right );
            fi

            b.append( ')' );
            return b;
        si

        static get Tree RandomTree is
            Tree result;
            foreach var i; 1..5 do
                insert(result, cast int(native.rand()) % 100);
            od

            return result;
        si
    si
si
Output:
Expand
visit (35,(21),(86,(49),(92))) with static proc ref in pre-order
proc is: void proc(LSPPage.P_29533_78.Proc.Tree) @7F53930FE430
static visit: 35
static visit: 21
static visit: 86
static visit: 49
static visit: 92
visit (35,(21),(86,(49),(92))) with bound proc ref in post-order
proc is: void proc(LSPPage.P_29533_78.Proc.Tree) @18CC0C8
bound visit from Proc.Main: 21
bound visit from Proc.Main: 49
bound visit from Proc.Main: 92
bound visit from Proc.Main: 86
bound visit from Proc.Main: 35
visit (35,(21),(86,(49),(92))) with proc literal in order
proc is: void proc(LSPPage.P_29533_78.Proc.Tree) @18CEC58
literal visit from Proc.Main: 21
literal visit from Proc.Main: 35
literal visit from Proc.Main: 49
literal visit from Proc.Main: 86
literal visit from Proc.Main: 92
visit (35,(21),(86,(49),(92))) with closure proc ref in pre-order: 
proc is: void proc(LSPPage.P_29533_78.Proc.Tree) @18CEC58
literal visit from Proc.Main(A,B,C): 35
literal visit from Proc.Main(A,B,C): 21
literal visit from Proc.Main(A,B,C): 86
literal visit from Proc.Main(A,B,C): 49
literal visit from Proc.Main(A,B,C): 92
visit (35,(21),(86,(49),(92))) with bound proc ref in post-order: 
proc is: void proc(LSPPage.P_29533_78.Proc.Tree) @18D0E88
visit from Other(A,B,C): 21
visit from Other(A,B,C): 49
visit from Other(A,B,C): 92
visit from Other(A,B,C): 86
visit from Other(A,B,C): 35
site design and content copyright (C) jeek 1995-2010     [ 13132 ]