Using : for Lambda Syntax [was # considered harmful [was C++11 lambdas]]
Collin Fagan
collin.fagan at gmail.com
Tue Mar 16 17:35:35 PDT 2010
Hi Everyone,
I've been listening for a while and thought maybe I could contribute a
few ideas.
Can we use : in the lambda syntax? Off the top of my head I think it's
only used in the for-each loop and the ternary operator.
If : is up for grabs then my next question is: can we infix this
operator instead of prefixing it?
Examples: (borrowed from an earlier post by Rémi Forax)
A function that takes an int and returns an int:
int(int)
becomes
int:(int)
and ...
A function that takes an int and returns nothing:
void:(int)
A function that takes two ints and returns an int:
int:(int, int)
A function that throws an Exception:
int:(int) throws Exception
A function that takes a function that throws an Exception:
int:(int:(int) throws Exception)
Grammar:
ResultType :( TypeList ) throws ExceptionList
This syntax reads left to right in a way that is similar to method
signatures, with the method name replaced by a ':' .
Now when we get to the curry examples I would like to customize the
assignment operator. Since I chose ':' how about using ':=' as the
"curry operator" ?
Examples: (borrowed from an earlier post by Bob Foster)
class A {
void foo(int x) { ... }
void :(int) fun = { ... }
}
// curry examples
A a = new A();
void:() f1 := a.foo(2);
void:() f2 := a.foo();
void:() f3 := A.fun(2);
Finally, to stay with the theme, invoking a lambda would use '::'
f1::();
f2::();
f3::();
Optionally this syntax could be: f1.:(); or f1:.(); but I found
neither of those particularly compelling.
I *think* the : is no harder to type then the #. (At least on the
English keyboards I'm used to.)
The := construct is used in other languages (like Pascal, Eiffel and
Smalltalk) but admittedly not for curring.
The :: construct is used in C++, but again, not in the way I plan on using it.
I could continue to flesh this out into a real proposal if people
found the syntax compelling. If I've committed any egregious sin in my
post I apologize.
Thank you,
- Collin
On Mon, Mar 15, 2010 at 10:55 PM, Reinier Zwitserloot
<reinier at zwitserloot.com> wrote:
> So, postfix dots are bad, but when your favourite proposal ends up being
> ambiguous, it's okay to add double prefix dots. Hm. Doesn't seem fair.
>
> It's just not that simple. Shadowing a field with a local variable
> declaration is, well, local. It occurs within the method itself. For closure
> invoke vs. method invoke this granularity level all of a sudden becomes the
> class.
>
> It doesn't really make the no-dot proposal any simpler than the dot
> proposal, and you haven't addressed any of the other concerns (closure
> invokes are a different concept compared to method invokes, and a visual cue
> is nice).
>
>
> It's insulting when nobody agrees with closures mean? The folks that are
> actually writing the proposal seem to agree. It also seems a bit odd to hold
> lambda-dev responsible for the fact that the 'closure' term has been watered
> down so much due to usage that goes back many years, well before lambda-dev
> was set up.
>
> You seem to be mistaken about how the status quo proposal closes around
> local variables. It does close around *ALL* of them. The one difference with
> most other languages is that the compiler, while it fully understands what
> you meant, refuses to compile it until you tell the compiler that you really
> did intend for the compiler to declare that variable on the heap, accept
> that thread synchronization issues can now crop up, and other such issues.
>
> This, too, has been covered, at length. The JVM memory model cannot be
> adapted to let closures access and mutate local variables of their outer
> scope trivially, and not even after some thought, so without some
> breakthrough proposal to show how this is doable this remains off the table.
> Which leaves the compiler generating a bunch of sugar to make it happen.
>
> Does this mean "volatile" can be put on any local variable, or only on local
> variables that are secretly heap-hosted? Does this mean that heap-hosted
> local variables are initialized to null/false/0 the way fields are, or is
> all usage in closures restricted to require definitive assignment prior to
> the closure even being defined, with a further restriction that no closure
> can set a final unset local?
>
> You're also going to create surprise code:
>
> Runnable[] runnables = new Runnable[3];
> for (int i = 0; i < 3; i++) runnables[i] = #() {System.out.print(i);};
> for (int i = 0; i < 3; i++) runnables[i].run();
>
> This will print "333" in your proposal - quite the surprise. It'll not
> compile in the status quo as the closure is accessing mutated local
> variables. How do you suggest this is handled? Let it pass and decide that
> the masses that are going to stumble on this will just have to become
> smarter, and perhaps tell Oracle to hire a dedicated guy to respond to the
> avalance of reports at bugs.sun.com? Perhaps an exemption should be made for
> local variables declared in a basic for's init, and we should say _those_
> variables cannot be closed over to avoid this problem. But then the proposal
> isn't as simple and straightforward as you seem to think, and it would help
> a great deal if you could produce a thorough list of exactly how your
> proposal works that includes such corner cases.
>
> NB: I take it you're aware that the status quo proposal allows closures to
> access *final* locals, just like this is legal in Anonymous Inner Classes in
> today's java? It's also (IIRC) on the fence leaning towards allowing access
> to effectively final locals (locals that aren't marked final but are
> nevertheless set exactly once, and this set occurs before the closure is
> defined) by treating the local declaration as implicitly final. You're
> getting awfully worked up about postfix dot and the need to mark *mutated*
> local variable declarations that are accessed in a closure, given that for
> both of those, there's no simple answer.
>
> --Reinier Zwitserloot
>
>
>
> On Tue, Mar 16, 2010 at 3:07 AM, Bob Foster <bobfoster at gmail.com> wrote:
>
>> On Mon, Mar 15, 2010 at 4:33 PM, Reinier Zwitserloot
>> <reinier at zwitserloot.com> wrote:
>> > Do you have *ANY* comments at all about the many many problems that this
>> > mailing list uncovered with your 'preferences', or are you just whining?
>>
>> One person's opinions are another's whining, whatever. I have a day
>> job, so I get the digest and don't follow this list moment by moment.
>> If someone copies me, I reply.
>>
>> I've already apologized for coming late to the party. Once is enough.
>>
>> > A small and incomplete rehash:
>> > 1. No '.'
>> > Java has an almost unique take on namespaces, in that in java types,
>> methods
>> > and variables all have their own namespace. Without that dot, the meaning
>> of
>> > "foo()" is ambiguous. Are you invoking the method named 'foo', or are you
>> > invoking the closure pointed at by variable foo?
>>
>> Agreed that within a class a reference to a method and a call through
>> a variable of function type with the same number and type of arguments
>> would be ambiguous. Using . as a prefix operator for indirect function
>> calls with that issue is as good a device as any. You still have a
>> problem with references to static function variables within a class
>> and references outside the class, unless the proposal is to double up
>> the dots, like:
>>
>> A..foo()
>> a..foo()
>>
>> Regardless, such notation should be required _only_ if the call would
>> be actually ambiguous, a fairly minor use case. Inside a class, a
>> field name is not required to be qualified by 'this' unless necessary
>> to disambiguate the reference; a static method name is not required to
>> be qualified by the class name unless necessary to disambiguate from a
>> non-static method. This should be treated the same.
>>
>> The example I was looking at, however, involved only function type
>> arguments, and I see no reason to saddle references to argument names
>> or local variables with gratuitous dots. As long as "inner functions"
>> can only be defined through variables, there is no namespace issue and
>> the scope rules handle the rest.
>>
>> > The primary proposal
>> > started out without that dot, as per the strawman. In other words, we
>> > covered this. At extreme length. There's no point re-raising this issue
>> > unless you come up with different solutions for the namespace issues.
>> IIRC,
>> > the dot has going for it:
>> > - No need for arbitrary ordering of namespaces in case foo is both a
>> method
>> > and a variable.
>> > - Closures in java are to a smallish extent shoehorned in. They are
>> unique
>> > things that aren't exactly like methods, so their invocation should look
>> a
>> > little different.
>> > These advantages were deemed superior to the advantage that dotless
>> > invocation has, which one dot less clutter at the cost of syntax
>> ambiguity.
>>
>> Ah, deemed.
>>
>> > 2. "Actual closures"
>> > The word 'closures' is pretty meaningless. It has a well defined term in
>> the
>> > academic sense, and, frankly, its definition is pretty well defined in
>> the
>> > dictionary sense too, *but*, the vast majority of java programmers have
>> been
>> > abusing the term to mean something different. At any rate, whining about
>> > "actual closures" misses the point completely. Project Lambda's aim is to
>> > create syntax that makes it easy to write a bunch of code that's bundled
>> up
>> > into a reference so that you need not execute it on the spot, but can
>> > instead hand it off to for example another method, with as primary use
>> case
>> > extra-jsr166y a.k.a. ParallelArrays. From the outset (the outset being
>> Mark
>> > Reinhold's strawman at Devoxx '09) Project Lambda did not aim to add
>> > concepts like keeping control statements such as 'break', 'continue' and
>> > 'return' transparent. The aims of Project Lambda have not changed since
>> its
>> > inception. Possibly you were just confused as to what they were.
>>
>> I agree it's pretty meaningless in this forum, and I wish you would
>> stop referring to functions as closures. If nobody agrees what a
>> closure is, it's insulting.
>>
>> If you care, though, I mean closures as they are meant, according to
>> Wikipedia, in computer science: "a closure is a first-class function
>> with free variables that are bound in the lexical environment." When I
>> say that the proposal doesn't do real closures what I mean is it does
>> lexically closed named constants. Better than nothing but a bit
>> tedious to work around by hand.
>>
>> (Even considering break, etc. must mean someone confuses closures with
>> Smalltalk blocks and their spawn.)
>>
>> Bob
>>
>> >
>> >
>> > On Mon, Mar 15, 2010 at 11:57 PM, Rémi Forax <forax at univ-mlv.fr> wrote:
>> >>
>> >> Le 15/03/2010 23:27, Bob Foster a écrit :
>> >> > Harmful because it's unpleasant to look at and leads to indecipherable
>> >> > code. Every time someone proposes adding another #, the syntax gets
>> >> > uglier and less readable.
>> >> >
>> >> > I apologize for coming to this point rather late, but frankly once I
>> >> > read the # proposal and realized no one intended to implement actual
>> >> > closures, I decided the whole project was a plot to convert Java
>> >> > programmers to Scala and my mind turned to more pleasant things. This
>> >> > was a mistake, and Remi Forax's excellent counter-proposal has
>> >> > inspired me. Why _not_ try something simpler?
>> >> >
>> >>
>> >> Yes, a supporter.
>> >>
>> >> > I have a (very) few nits to pick with Remi's proposal:
>> >> >
>> >> > - int(int) is a function type, not a function.
>> >> >
>> >> > - the . has no place in function call syntax; functions are not
>> methods.
>> >> >
>> >>
>> >> It will be cool to be able to call a function only by its name
>> >> but it doesn't seem possible to twist the JLS invocation rules
>> >> to do that (see the archive of this list for more info).
>> >>
>> >> > - I quite like the ( expr ) syntax when a function body is only a
>> >> > single expression, but it's not essential and if it were adopted
>> >> > should be extended to methods for consistency.
>> >> >
>> >> > - Java doesn't have type inference elsewhere, so it seems inconsistent
>> >> > to have it for functions. However, if it was going to be part of the #
>> >> > syntax, it should be allowed here, too, as Remi originally proposed,
>> >> > and extended to methods, as well.
>> >> >
>> >>
>> >> Java has type inference when resolving generic method calls and
>> >> when using the diamond operator.
>> >>
>> >> > The whole proposal works syntactically because currently the
>> >> > construction Type() never appears in a valid program except after new.
>> >> > So as long as new doesn't pollute anonymous functions (a separate
>> >> > thread), function types are unambiguous to both the compiler and
>> >> > readers.
>> >> >
>> >>
>> >> [...]
>> >>
>> >> Rémi
>> >>
>> >
>> >
>>
>
>
More information about the lambda-dev
mailing list