Delurking comments on the 0.1.5 specification

Jim Mayer jim at pentastich.org
Thu Apr 1 21:30:11 PDT 2010


Thanks Neal,

On Thu, Apr 1, 2010 at 12:33 PM, Neal Gafter <neal at gafter.com> wrote:
> A throws clause is not necessary in the lambda syntax.  For the same
> reason that the type resulting from invoking a lambda isn't usually
> made explicit in the syntax for a lambda expression, there is no need
> for the programmer to specify a throws clause; the body throws
> whatever the body throws.

Agreed.  I intended my "example" to be universally unacceptable, but
not wrong :-)

> There is more to the distinction between expression and statement
> lambdas than mere syntax sugar.  Expression lambdas can be
> "transparent", in the sense of satisfying Tennent's Correspondence
> Principle, while statement lambdas are not.

If I understand correctly, the importance of "transparency" is that it
enables composition of code in ways that gives developers, and
especially library writers, a lot of power and flexibility.  So, for
example, much of the motivation for the BGCA closure work (which I
have not looked at closely), seems to be to provide a mechanism by
which libraries can provide advanced locking, iteration, collection,
etc. mechanisms in a form that can be used conveniently and that
doesn't rely on clients following elaborate conventions.  I skimmed
through the video in your message, and one example that stood out for
me was:

    myStaticallyImportedLockType(lock) {
        doSomething();
    }

which would, roughly, convert to (in Project Lambda syntax):

    myStaticallyImportedLockType(lock, #() { doSomething(); });

In the code bas I'm working with, we have a global lock/property/thing
that was originally invoked (the names have been changed to protect
the innocent) as:

    domain.enter();
    try {
        doSomething();
    } finally {
        domain.exit();
    }

The first time someone forgot the "exit" call it took so long to find
the cause of the problem that I went and changed every use to:

    int token = domain.enter();
    try {
        doSomething();
    } finally {
        domain.exit(token);
    }

At least with this as the "normal" usage we failed "fast" when an
"enter" call wasn't matched by an "exit".  Of course, this wouldn't
help at all if someone forgot the "try/finally" wrapper and an
exception got thrown.

Taking the idea further, if we had "break", "continue", and "return"
transparency (and BGCA) I could have written code like the following:

    for (Domain d : myDomains) {
        d.enter() {
            if (...) return d;
        }
    }

If I've got that right, I think I'd rather enjoy the resulting
programming language.  A fair number of my "top ten" bugs probably
wouldn't have happened if Java had a mechanism like that.

Unfortunately, I don't know how to get to a closure mechanism that
supports full transparency from Java as it exists today.  I don't mean
technically, because I think you've demonstrated pretty convincingly
that it can be done.  I think there are issues of cultural change, of
expectations, of business models, and of application spaces.  In the
end, the best bet may be to try to make sure that nothing gets added
to the byte codes or JVM that would make a language that DID support
all of this impossible or horribly inefficient.

Maybe such a language could have a single, lexical, name space and we
could write closure invocations without a "." :-)

So, for the full case, I don't know how to do it.

On the other hand, I see no reason why we can't grab as much
transparency as we can.  As I said in my note, I've been bitten many
times by the fact that anonymous inner classes introduce a new
definition of "this" and I'd like to avoid that here if at all
possible.

> ... See
> <http://www.youtube.com/watch?v=0zVizaCOhME> for a discussion of the
> importance of transparency, and
> <http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html>
> for how this impacts the syntax.  Although project lambda will likely
> not specify full transparency in jdk7, it would be better if the
> chosen syntax can be extended to full transparency in the future.

<geek-mode>

If "E" is a Java expression (not statement), then, assuming that we
changed the way the proposal handle's 'this', aren't the following all
equivalent?

    E
    #(){return E;}
    #(){return #(){return E;};}

I think this follows from the fact that expressions can't contain
'break', 'continue', or 'return' except insofar as they show up in a
lambda expression (which acts like a function body).

</geek-mode>

> Having a separate syntax for self-invocation doesn't solve the
> problems that prevent recursive lambdas when "this" is defined as
> referring to the innermost lambda expression.  Since the result type
> is not explicit, recursive invocations in a return statement (or in an
> expression lambda) would still have to be forbidden.

You're right, though I wonder what the root cause of the problem is.
Does anyone have a pointer to the analysis?

In the factorial example

    #(int n)(n == 0? 1 : n * #this(n-1))

It seems that something like the logic used to determine the type of a
conditional expression ought to be applicable.  I really don't like
the restriction for some reason.

-- Jim


More information about the lambda-dev mailing list