Contents

Pointers to instance methods

Method pointers

When a static method field is accessed, the result is a procedure value. For example :-

import io

class X()
   public static f()
   end
end

procedure main()
   local m
   m := X.f
   write("type=", type(m))
   write("image=", image(m))
end

This program writes :-

type=procedure
image=method X.f

The value of m is just a procedure that can be invoked when desired.

For an instance method, the situation is a little more involved, because the instance needs to be kept to hand so that it can be passed to the method as the value of the self parameter. To achieve this, when an instance method field is accessed, a small structure is created which holds two things, namely the instance and the method’s procedure. This structure is called a “methp” (short for “method pointer”).

To illustrate this, consider the following :-

import io

class X()
   public g()
   end
end

procedure main()
   local i, m
   i := X()
   m := i.g
   write("type=", type(m))
   write("image=", image(m))
end

The output in this case is :-

type=methp
image=methp#1(object X#1(0),method X.g)

The value m can now be used just like a procedure to invoke the method :-

m(1, 2, 3)

and the effect of this is to call the method g with the given parameters, as well as the self parameter, which will have the value of the instance i.

One other general point to note about methods is that access permissions are checked when the field is accessed, not when the method is called, which can be done at any later time from any location in the program.

Method pointers like closures

In functional programming languages, anonymous, or lambda, functions, capture a “closure” over the local variables in scope, so that a function carries with it an additional, hidden reference. As mentioned above, method pointers do the same thing, but instead of a hidden reference to a set of local variables, there is a reference to an object instance.

This similarity allows method pointers to do the same sort of things that can be done in functional languages with lambda functions, so long as we think in terms of classes and objects, instead of closures over local variables. For example, consider the problem of writing a function which takes a parameter n, and returns another function which adds n to its argument. This can be done as follows :-

Download adder.icn

import io

class X()
   private n

   private f(x)
      return x + n
   end

   private new(n)
      return self.n := n
   end

   public static adder(n)
      return X(n).f
   end
end

procedure main()
   local f
   f := X.adder(20)
   write(f(4))
   write(f(6))

   f := X.adder(100)
   write(f(5))
   write(f(10))
end

The output is

24
26
105
110

This technique is used in the ipl.functional package to provide various high-order procedures commonly found in functional programming languages.

This page describes how, together with co-expressions, method pointers can be used to provide simple lambda-style anonymous functions.

Efficiency

In order to keep garbage collection operations to a minimum, methp objects are not created unless absolutely necessary. For example, although the expression obj.f(100) could be implemented by creating a methp for obj.f, and then applying that to the parameter 100, it is more efficient to gather both of these steps into a single operation that avoids the creation of the intermediate methp. This is implemented in the interpreter with two special virtual machine instructions (invokef and applyf).

One point to note is that in an expression like

obj.f(obj := expr)

then it is the value of obj after the assignment from which the field f will be evaluated. This is because the whole expression is treated as a unit, and obj is only dereferenced after the arguments have been evaluated.

Contents