[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon May 15 11:01:28 2001 
Subject:Re: filenames, argument list separators + gsl extension 
From:Jonathan L Cunningham 
Volume-ID:1010515.02 

On Mon, 14 May 2001 22:50:29 GMT, hedgehog@electric-hedgehog.net
(Chris Dollin) wrote:

>Part of that is syntax; part of it is the Poplog VM. The latter controls
>what kind of things can be said; the former controls how *easily* they
>may be said. For example, Pop's syntax for closures is pretty easy to
>write and read; it gets used a *lot*. It's not perfect (I think Spice
>"holes" will turn out better, but they've not been used in anger), but
>it's easier than explicit lambda-expressions. If it's clumsy to write,
>*it doesn't get used*.

Pop's closures (partial application) are very useful, and much more
convenient than lambda-expressions as in Lisp.

There was a discussion on this group a few years back (probably even
before LIB objectclass) about the advantages of object-oriented
programming. Somehow the question got raised about how you would
get the same effect as pop closures in an OO language.

It can be done, without using anything like closures or
lambda expressions. And it's messy: you need to define a new class.

As an interesting corollary, one of the few "big" changes to the
syntax of Java, after its first release, was the provision of a
mechanism for defining anonymous classes. (In the same way that
the pop11 "procedure" syntax lets you define anonymous procedures.)
IMO, one main purpose of anonymous classes was precisely those
cases where, in pop, we would use closures.

Most of the Java effort has gone into providing
libraries of higher level constructs, such as java beans, with
very few changes to the syntax of the language. This is, of
course, in line with Aaron's comments, and what we would expect
in pop. But should we, for example, want to add the concept
of anonymous classes to lib objectclass? Pop11 is so rich,
syntactically, that I don't suppose anyone has felt any need
for them, but going one step further than Chris's remark above:
if it ain't in the language *it sure as hell doesn't get used*.

OK, I shouldn't be spending time on this, but to provide a
few examples, suppose we have a function called "triple" as follows:

define triple(x, y, z);
  [first ^x second ^y third ^z]=>
enddefine;

It is fairly obvious what this does:

triple("one", "two", "three");
** [first one second two third three]

And closures can freeze in the last argument(s), as in

triple(% "jump" %) -> double;

so that

double("hop", "skip");
** [first hop second skip third jump]

Suppose we now want to freeze in the middle argument instead?

This is where lambda expressions, or pop procedures, are more
powerful but syntactically clumsier. This will freeze in
the second argument of a three argument function:

define midclosure(f, arg);
    procedure x, y;
        f(x, arg, y);
    endprocedure
enddefine;

(It's actually a bit more general than that, but let's not
get too pedantic here.)

We can use it as follows:

midclosure(triple, "beta") -> doublet;

doublet("alpha", "gamma");
** [first alpha second beta third gamma]

doublet("bet", "best");
** [first bet second beta third best]

Ok, how would you do this in a language which doesn't have
procedures as objects which can be manipulated in this way?
In an object oriented language, you can pass around objects
instead.

Using objectclass (which I'm not very familiar with, so
maybe this can be cleaned up), you will need an object
which will represent the three arg function "triple".
(Remember, from now on, we are pretending that we can't
pass around functions are arguments to other functions.)

First we declare the class of the object for the triple
function:

define :class three_arg_func;
enddefine;

There is nothing in it, because we don't really need a
whole new class. It is only there so that we can create
an object. The only thing about this object is that it
represents a three argument function, so let's declare
that next:

define :method apply_three_arg(f:three_arg_func, x, y, z);
   [first ^x second ^y third ^z]=>
enddefine;

This is our old friend "triple" -- or rather, it is the
declaration of what triple will do. We still have to
create the actual object:

consthree_arg_func() -> triple;

Now we can use the object like a function:

apply_three_arg(triple, "alpha", "beta", "gamma");
** [first alpha second beta third gamma]

Now we are in a position to create the equivalent of
a closure, or lambda expression. We will need to
inherit the apply_three_arg function, so we will
need a new class:

define :class midclosure is three_arg_func;
    slot middlearg;
enddefine;

This new class will represent a two argument function:

define :method apply_two_arg(f:midclosure, x, z);
    apply_three_arg(f, x, middlearg(f), z);
enddefine;

and lastly, having defined the behaviour of our new
object, we need to actually create it:

instance midclosure middlearg = "psi" endinstance -> doublet;

and we can use this in a similar way:

apply_two_arg(doublet, "chi", "omega");
** [first chi second psi third omega]

If you put all that example code together you will agree, I
think, that when pop closures can be used, they certainly
encapsulate a lot of functionality!! But don't, for one
minute, think they are *simpler*. All that the objectclass
stuff is doing, is making explicit, and bringing to the
surface, something very similar to what is actually going
on inside the poplog virtual machine for pop closures. The
difference is that the "class" of pop functions is already
implicit in the language, as is the "class" of closures.

There are some other ways in which the objectclass stuff
looks ugly because of syntactic restrictions. For example,
in C++ I could have used the same name "apply" for both
the apply methods, instead of the clumsier "apply_two_arg"
and "apply_three_arg". In Java, I needn't have declared
the class "midclosure" -- I could have used an anonymous
class. And so on.

But the bottom line is that an apparently "simple" mechanism --
the pop closure -- is actually a very powerful abstraction,
which hides a lot of behind-the-scenes complexity. And that
is part of what makes it so useful.

Jonathan

-- 
Jonathan L Cunningham