Optional brackets around lambda expression (was: Expected distribution of lambda sizes)
Pavel Minaev
int19h at gmail.com
Fri Jun 17 00:36:02 PDT 2011
>From the examples that I've seen so far, it only elides parens for 1-arg
case. So x->x+1, but (x,y)->x+y. And note that this is only for expression
lambdas; statement ones would still be x -> { return x; } and (x,y) -> {
return x + y; } respectively.
All in all, this variant seems to be identical to the actual C# lambda
syntax, except that it uses -> instead of =>.
On Thu, Jun 16, 2011 at 11:52 PM, Reinier Zwitserloot <
reinier at zwitserloot.com> wrote:
> Just so I understand these suggestions properly, the only difference
> between
> your redmond variant and the paren-less strawman is that strawman has a
> prefix # and stuffs the arguments inside of parens, whereas redmond variant
> has an infix -> and elides the parens?
>
> --Reinier Zwitserloot
>
>
>
> On Thu, Jun 16, 2011 at 10:54 PM, Jonathan Halterman
> <jhalterman at gmail.com>wrote:
>
> > This approach (Redmond) seems the cleanest of the bunch.
> >
> > Jonathan
> >
> > On Thu, Jun 16, 2011 at 3:19 AM, Ali Ebrahimi <
> ali.ebrahimi1781 at gmail.com
> > >wrote:
> >
> > > Hi, how about this one:
> > >
> > > process( x -> x + 1 );
> > > process( x -> { return x + 1; } );
> > > process( x -> {
> > > if (x == 0) {
> > > return 0;
> > > }
> > > return x + 1;
> > > });
> > >
> > >
> > > Ali Ebrahimi
> > >
> > > On Thu, Jun 16, 2011 at 1:33 PM, Stephen Colebourne <
> > scolebourne at joda.org
> > > >wrote:
> > >
> > > > I believe I agree with Steven and Reinier that the strawman syntax
> > > > family would be best with only one paren for expressions:
> > > >
> > > > process( #(x) x + 1 )
> > > > process( #(x) { return x + 1; } );
> > > > process( #(x) {
> > > > if (x == 0) {
> > > > return 0;
> > > > }
> > > > return x + 1;
> > > > });
> > > >
> > > > The one less paren helps me read the code, compared to this:
> > > >
> > > > process( #(x) (x + 1) )
> > > >
> > > > (Of course, users might choose to add the parens themselves, as thats
> > > > legal for any expression)
> > > >
> > > >
> > > > I have mixed feelings on supporting a lone expression within the
> > > > block. Thats because I'm unconvinced that the equivalent for a method
> > > > is as readable as using a "return":
> > > >
> > > > process( #(x) {x + 1} ); // reads well enough to me
> > > > public String getSurname() {surname} // doesn't read quite as well
> to
> > me
> > > >
> > > >
> > > > For other syntax families, I also suspect that I prefer that the
> > > > expression itself does not require being surrounded by parens.
> > > >
> > > > Stephen
> > > >
> > > >
> > > > On 16 June 2011 07:55, Reinier Zwitserloot <reinier at zwitserloot.com>
> > > > wrote:
> > > > > My gut instinct was: That's a really bad idea. But I decided to
> play
> > > > around
> > > > > with it anyway and it actually resulted in easier to scan code (to
> > me,
> > > > > anyway). The use cases I've worked on before indeed usually boil
> down
> > > to
> > > > > passing the closure straight into a method as an argument, and in
> > such
> > > > cases
> > > > > it's better. As Pavel said, if you treat the closure preamble (the
> =>
> > > or
> > > > the
> > > > > #() or whatever the syntax calls for) as an operator with low
> > > precedence,
> > > > it
> > > > > works out.
> > > > >
> > > > > This way the strawman syntax almost seems to have that best of both
> > > > worlds
> > > > > scenario: It looks good both for long and one-liner closures.
> Passing
> > > > > closures inline as argument to a method, i.e. the map/filter
> usecase,
> > > > looks
> > > > > a lot cleaner when you lose a closing brace/paren.
> > > > >
> > > > > Precedence-wise, if you want to exit the closure scope, you have to
> > > > resort
> > > > > to this:
> > > > >
> > > > > int ageOfJoe = (#(Person x) x.getAge()).invoke(joe);
> > > > >
> > > > > which is different from what traditional strawman wanted you to do:
> > > > >
> > > > > int ageOfJoe = #(Person x) (x.getAge()).invoke(joe);
> > > > >
> > > > > Personally I found it easier to scan the new form vs. the old one
> > (i.e.
> > > > its
> > > > > easier to see in the top version that the toString applies just as
> > much
> > > > to
> > > > > the #(Person x) part as the x.getAge() part), so this is not
> > > necessarily
> > > > a
> > > > > bad thing.
> > > > >
> > > > > I don't think its necessary but this proposal can be extended by
> > > allowing
> > > > > braces for single expressions, i.e:
> > > > >
> > > > > int ageOfJoe = #(Person x) {x.getAge()}.invoke(joe);
> > > > >
> > > > > though I'm not sure how easy it is to implement this in an LL(k)
> > > parser
> > > > > (you'd have to conflate the first statement/expression as 'its one
> of
> > > > those
> > > > > two', then scan for either a semicolon or the closing brace, at
> which
> > > > point
> > > > > you have to go back and doublecheck that the statement or
> expression
> > > you
> > > > > parsed is actually an expression if there wasn't one, or actually a
> > > > > statement if there was. That's different than what javac currently
> > > does;
> > > > it
> > > > > always knows if it wants a statement or an expression, it never
> needs
> > > to
> > > > > parse an 'it's one of those'. ecj will have any problem with this
> as
> > it
> > > > > already junks statements and expressions into the same pile.
> > > > >
> > > > >
> > > > > --Reinier Zwitserloot
> > > > >
> > > > >
> > > > >
> > > > > On Wed, Jun 15, 2011 at 10:42 PM, Pavel Minaev <int19h at gmail.com>
> > > wrote:
> > > > >
> > > > >> Note that this applies also to "Redmond syntax" in general; e.g.:
> > > > >>
> > > > >> new User().use(x => x + "a string");
> > > > >>
> > > > >> However, I do not recall it ever being a problem in C# in
> practice,
> > > nor
> > > > did
> > > > >> I ever hear of complaints about that in C#. In general, lambda
> > syntax
> > > is
> > > > >> treated as a sort of "lambda operator" =>, with a certain
> > > "precedence",
> > > > and
> > > > >> said "precedence" is lower than any other operator - in this case,
> > > lower
> > > > >> than "+". In that sense, it's not much different than correctly
> > > parsing
> > > > >> expressions such as a || b && c.
> > > > >>
> > > > >> On Wed, Jun 15, 2011 at 1:35 PM, Yuval Shavit <yshavit at akiban.com
> >
> > > > wrote:
> > > > >>
> > > > >> > What would happen with something like:
> > > > >> >
> > > > >> > public interface Sam {
> > > > >> > String doSomething(String arg);
> > > > >> > }
> > > > >> > public class User {
> > > > >> > public void use(Sam sam) { System.out.println("saw a sam"); }
> > > > >> > public void use(String string) { System.out.println("saw a
> > > > string"); }
> > > > >> > }
> > > > >> >
> > > > >> > new User().use( #(x) x + "a string" );
> > > > >> >
> > > > >> > In that context, which are we passing?
> > > > >> > - lambda that takes a String, concatenates "a string" to it
> and
> > > > returns
> > > > >> > the result
> > > > >> > - a string consisting of (lambda x -> x).toString()
> concatenated
> > > > with
> > > > >> "a
> > > > >> > string"
> > > > >> >
> > > > >> > This is just one simple and somewhat contrived example, but the
> > > point
> > > > is
> > > > >> > that without braces or something similar, it's not too hard to
> > come
> > > up
> > > > >> with
> > > > >> > a situation where it's not clear where the lambda ends and the
> > rest
> > > of
> > > > >> the
> > > > >> > expression begins.
> > > > >> >
> > > > >> > On Wed, Jun 15, 2011 at 4:18 PM, Steven Simpson <
> > > ss at comp.lancs.ac.uk>
> > > > >> > wrote:
> > > > >> >
> > > > >> > > On 13/06/11 21:10, Pavel Minaev wrote:
> > > > >> > > > Statement lambdas would typically be thus wrapped, yes
> > > > >> (coincidentally,
> > > > >> > > it's
> > > > >> > > > also why I'd prefer to have a separate form for expression
> > > lambdas
> > > > >> > which
> > > > >> > > > does not include the {} so as to be visually distinct from
> > > > statement
> > > > >> > > > blocks).
> > > > >> > >
> > > > >> > > Yes, I think I'd appreciate that visual distinction too. Is
> it
> > > > >> possible
> > > > >> > > to have an unambiguous expression syntax not requiring any
> form
> > of
> > > > >> > > brackets around either the whole lambda or its body?:
> > > > >> > >
> > > > >> > > #() 3
> > > > >> > > #() 3 + 4
> > > > >> > > #(x) x + 1
> > > > >> > > #(x, y) x + y
> > > > >> > >
> > > > >> > > When used like this, they will likely be in argument lists, so
> > > they
> > > > are
> > > > >> > > naturally delimited by commas and the list-terminating
> bracket,
> > > and
> > > > >> need
> > > > >> > > no brackets of their own. IOW, #() would have quite a low
> > > > precedence,
> > > > >> > > and any brackets put around it would be part of existing
> syntax
> > > > (e.g.
> > > > >> > > for normal expressions and argument lists).
> > > > >> > >
> > > > >> > > If you had one lambda in the body of another, it will likely
> > have
> > > to
> > > > be
> > > > >> > > inside an enclosed call, whose brackets will naturally delimit
> > it:
> > > > >> > >
> > > > >> > > #(a) a + process(#(b) b * b) + 10
> > > > >> > >
> > > > >> > > If it wasn't so embedded, you could always put normal
> expression
> > > > >> > > brackets around it:
> > > > >> > >
> > > > >> > > #(a) a + (#(b) b * b).invoke(a)
> > > > >> > >
> > > > >> > > (And that's a little contrived. And possibly quite difficult
> to
> > > > >> > > type-infer…?)
> > > > >> > >
> > > > >> > > I don't think you could drop the parameter-list brackets too,
> as
> > > > that
> > > > >> > > would make parsing much more complex (e.g. #a + a). Looking
> at
> > > that
> > > > >> > > more positively, it would keep lambda syntax and appearance
> > > > obviously
> > > > >> > > distinct from method literals. ("#(" => Bam! I'm a lambda!)
> > The
> > > > >> > > presence of braces would then further distinguish lambda
> > > expressions
> > > > >> > > from lambda statements.
> > > > >> > >
> > > > >> > > In summary, we require brackets around neither the lambda
> > > expression
> > > > >> nor
> > > > >> > > its body. We are then forced to used some around the
> parameter
> > > > list,
> > > > >> > > but take advantage of this as the constant discriminant of
> > lambda
> > > vs
> > > > >> > > method literal.
> > > > >> > >
> > > > >> > > Applied to some other expressions seen on the list lately:
> > > > >> > >
> > > > >> > > list.filter( #(t) t.length() > 3 )
> > > > >> > > .map( #(t) t.barCount )
> > > > >> > > .max();
> > > > >> > >
> > > > >> > > students.filter(#(s) s!=null && "Smith".equals(s.getName()))
> > > > >> > >
> > > > >> > > List men = personList.filter(#(p) p.isMale());
> > > > >> > >
> > > > >> > > List<Double> adjustedPrices =
> > > > >> > > prices.map(#(price) price + getShipping());
> > > > >> > >
> > > > >> > > Cheers,
> > > > >> > >
> > > > >> > > Steven
> > > > >> > >
> > > > >> > >
> > > > >> > >
> > > > >> >
> > > > >> >
> > > > >>
> > > > >>
> > > > >
> > > > >
> > > >
> > > >
> > >
> > >
> >
> >
>
>
More information about the lambda-dev
mailing list