Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > new Java lambda syntax

Reply
Thread Tools

new Java lambda syntax

 
 
Arne Vajh°j
Guest
Posts: n/a
 
      09-13-2011
On 9/12/2011 8:00 PM, Daniele Futtorovic wrote:
> On 12/09/2011 00:07, Joshua Cranmer allegedly wrote:
>>
>> List<Runnable> runners = new LinkedList<Runnable>();
>> for (int i = 0; i< 10; i++) {
>> runners.add(() => { System.out.println("Value of i is " + i); });
>> }
>> for (Runnable r : runners) {
>> r.run();
>> }

>
> Beg your pardon, I haven't followed this issue as closely as I probably
> have should, but does this all mean lambdas are always Runnables? Never
> Callable<T>s? IOW, no return values?


Lambdas can be anything.

In this example they are Runnable's because they are
being run later.

Arne


 
Reply With Quote
 
 
 
 
Joshua Cranmer
Guest
Posts: n/a
 
      09-13-2011
On 9/12/2011 7:00 PM, Daniele Futtorovic wrote:
> On 12/09/2011 00:07, Joshua Cranmer allegedly wrote:
>>
>> List<Runnable> runners = new LinkedList<Runnable>();
>> for (int i = 0; i< 10; i++) {
>> runners.add(() => { System.out.println("Value of i is " + i); });
>> }
>> for (Runnable r : runners) {
>> r.run();
>> }

>
> Beg your pardon, I haven't followed this issue as closely as I probably
> have should, but does this all mean lambdas are always Runnables? Never
> Callable<T>s? IOW, no return values?


No, I just opted for Runnable here because it was simple.


--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
Reply With Quote
 
 
 
 
Daniele Futtorovic
Guest
Posts: n/a
 
      09-13-2011
On 13/09/2011 04:24, Joshua Cranmer allegedly wrote:
> On 9/12/2011 7:00 PM, Daniele Futtorovic wrote:
>> On 12/09/2011 00:07, Joshua Cranmer allegedly wrote:
>>>
>>> List<Runnable> runners = new LinkedList<Runnable>();
>>> for (int i = 0; i< 10; i++) {
>>> runners.add(() => { System.out.println("Value of i is " + i); });
>>> }
>>> for (Runnable r : runners) {
>>> r.run();
>>> }

>>
>> Beg your pardon, I haven't followed this issue as closely as I probably
>> have should, but does this all mean lambdas are always Runnables? Never
>> Callable<T>s? IOW, no return values?

>
> No, I just opted for Runnable here because it was simple.
>


Okay, so you can have a lambda returning a value? Steve Simpson's statement:

> There's no (...) long jumps (break, continue, return, throw)


seemed to contradict that, as did Tom's about the "Gafterist nonsense"
(<3), seeing how Gafter et al.'s proposal contained return values, IIRC.

I mean, if they cannot return values, I'm a bit at a loss understanding
how they'll be the nec plus ultra for parallel computing... you'd
publish results to a shared queue, I suppose, but that's a bit unhandy.

--
DF.
Determinism trumps correctness.
 
Reply With Quote
 
Joshua Cranmer
Guest
Posts: n/a
 
      09-13-2011
On 9/13/2011 2:04 PM, Daniele Futtorovic wrote:
> Okay, so you can have a lambda returning a value? Steve Simpson's statement:
>
>> There's no (...) long jumps (break, continue, return, throw)

>
> seemed to contradict that, as did Tom's about the "Gafterist nonsense"
> (<3), seeing how Gafter et al.'s proposal contained return values, IIRC.


What this is referring to is that lambdas do not have non-local control
flow (the so-called "long jump" -- think about C's setjmp/longjmp
feature [1]). Lambdas are effectively "mini-functions", so I could have
a lambda that looked like this:

(int[] x, int y) => {
for (int i = 0; i < x.length; i++)
if (x[i] == y) return i;
return -1;
};

which would effectively be a method that looked like:
int searchList(int[] x, int y) {
for (int i = 0; i < x.length; i++)
if (x[i] == y) return i;
return -1;
}

In other words, what was not accepted was the thing that ****ed me off
about some of the proposals, namely that any block of statements should
do the exact same thing if you wrapped it with ((){/*insert stmt*/})() [2].

So this would return true:
boolean foo() {
((){ return true; })();
return false;
}

Obviously, if you want to have more complex logic in the lambda for
returning multiple values other than what you can do in a simple
expression, you'd need some sort of syntax. The compromise then being
discussed would make this method return false:
boolean foo() {
((){ return true })();
return false;
}

....

It was at that point that I personally hated non-local control flow in
closures, er, lambdas. [3]

[1] Actually, don't. It breaks so many things.
[2] This is, supposedly, Tennent's Correspondence Principle. I say
supposedly since a google search only reveals results that are
specifically brought up in reference to the closures debate in JS and Java.
[3] Actually, doing some more research for this posting, it struck me
that the primary rationale for non-local control flow comes from the
heritage of lambdas. Most of the time, lambdas are used in reference to
functional programming paradigms, and in the purer functional languages,
control flow is not done via explicit constructs but rather via specific
function calls. So it's a list.forEach( { body of loop }) as opposed to
a for (Element e : list) { body of loop }; in such languages, non-local
control flow is more important. However, given that Java is more
imperatively structured than functionally structured, non-local control
flow is by means no natural, nor is it necessary to implement, so I
would still stand by my claim that non-local control flow is not a
feature that should be implemented in Java's version of lambdas. For
example, C++11 appears to omit it in their version of lambdas...

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
Reply With Quote
 
Tom Anderson
Guest
Posts: n/a
 
      09-13-2011
On Tue, 13 Sep 2011, Daniele Futtorovic wrote:

> On 13/09/2011 04:24, Joshua Cranmer allegedly wrote:
>> On 9/12/2011 7:00 PM, Daniele Futtorovic wrote:
>>> On 12/09/2011 00:07, Joshua Cranmer allegedly wrote:
>>>
>>>> List<Runnable> runners = new LinkedList<Runnable>();
>>>> for (int i = 0; i< 10; i++) {
>>>> runners.add(() => { System.out.println("Value of i is " + i); });
>>>> }
>>>> for (Runnable r : runners) {
>>>> r.run();
>>>> }
>>>
>>> Beg your pardon, I haven't followed this issue as closely as I
>>> probably have should, but does this all mean lambdas are always
>>> Runnables? Never Callable<T>s? IOW, no return values?

>>
>> No, I just opted for Runnable here because it was simple.

>
> Okay, so you can have a lambda returning a value? Steve Simpson's statement:
>
>> There's no (...) long jumps (break, continue, return, throw)

>
> seemed to contradict that, as did Tom's about the "Gafterist nonsense"
> (<3), seeing how Gafter et al.'s proposal contained return values, IIRC.


Brachaism-Gafterism is the CANCER THAT IS KILLING JAVA!!

> I mean, if they cannot return values, I'm a bit at a loss understanding
> how they'll be the nec plus ultra for parallel computing... you'd
> publish results to a shared queue, I suppose, but that's a bit unhandy.


A lambda can return a value. It just can't return it from another method.

You will be able to say (something like):

Callable<String> one = () => {return "uno";};
String s = one.call();
assert s.equals("uno");

You will not be able to say:

String thisIsWhatBGGAWanted() {
Callable<String> one = () => {return "uno";};
one.call();
return "ein";
}
String s = thisIsWhatBGGAWanted();
assert s.equals("uno");

Basically, lambdas can be either method-like (they return values from
themselves) or statement-like (they return values from their enclosing
methods). Lambdas are method-like in all the current dynamic languages
(AFAIK - they certainly are in Smalltalk, Python and Javascript). The BGGA
proposal (and i remember this coming from Gafter in particular, BICBW)
would have made them statement-like.

The rationale was that enclosing any given wodge of code in a lambda
definition immediately followed by an invocation of that lambda would not
change the behaviour of the code. This seemed dubious to me, and would
have led to very weird programming experiences. It would, though, have
enabled a wider range of funky control structures implemented on top of
lambdas, which some people are very keen on.

tom

--
Oh well, one plays these games and the scones did look rather
delicious. -- Stephen Fry
 
Reply With Quote
 
Daniele Futtorovic
Guest
Posts: n/a
 
      09-13-2011
On 13/09/2011 22:22, Joshua Cranmer allegedly wrote:
> On 9/13/2011 2:04 PM, Daniele Futtorovic wrote:
>> Okay, so you can have a lambda returning a value? Steve Simpson's
>> statement:
>>
>>> There's no (...) long jumps (break, continue, return, throw)

>>
>> seemed to contradict that, as did Tom's about the "Gafterist nonsense"
>> (<3), seeing how Gafter et al.'s proposal contained return values, IIRC.

>
> What this is referring to is that lambdas do not have non-local control
> flow (the so-called "long jump" -- think about C's setjmp/longjmp
> feature [1]). Lambdas are effectively "mini-functions", so I could have
> a lambda that looked like this:
>
> (int[] x, int y) => {
> for (int i = 0; i < x.length; i++)
> if (x[i] == y) return i;
> return -1;
> };
>
> which would effectively be a method that looked like:
> int searchList(int[] x, int y) {
> for (int i = 0; i < x.length; i++)
> if (x[i] == y) return i;
> return -1;
> }
>
> In other words, what was not accepted was the thing that ****ed me off
> about some of the proposals, namely that any block of statements should
> do the exact same thing if you wrapped it with ((){/*insert stmt*/})() [2].
>
> So this would return true:
> boolean foo() {
> ((){ return true; })();
> return false;
> }
>
> Obviously, if you want to have more complex logic in the lambda for
> returning multiple values other than what you can do in a simple
> expression, you'd need some sort of syntax. The compromise then being
> discussed would make this method return false:
> boolean foo() {
> ((){ return true })();
> return false;
> }
>
> ....
>
> It was at that point that I personally hated non-local control flow in
> closures, er, lambdas. [3]
>
> [1] Actually, don't. It breaks so many things.
> [2] This is, supposedly, Tennent's Correspondence Principle. I say
> supposedly since a google search only reveals results that are
> specifically brought up in reference to the closures debate in JS and Java.
> [3] Actually, doing some more research for this posting, it struck me
> that the primary rationale for non-local control flow comes from the
> heritage of lambdas. Most of the time, lambdas are used in reference to
> functional programming paradigms, and in the purer functional languages,
> control flow is not done via explicit constructs but rather via specific
> function calls. So it's a list.forEach( { body of loop }) as opposed to
> a for (Element e : list) { body of loop }; in such languages, non-local
> control flow is more important. However, given that Java is more
> imperatively structured than functionally structured, non-local control
> flow is by means no natural, nor is it necessary to implement, so I
> would still stand by my claim that non-local control flow is not a
> feature that should be implemented in Java's version of lambdas. For
> example, C++11 appears to omit it in their version of lambdas...
>


Lovely. I welcome that decision, then, and humbly thank you and Tom for
your elaborations.

--
DF.
Determinism trumps correctness.
 
Reply With Quote
 
Daniele Futtorovic
Guest
Posts: n/a
 
      09-13-2011
On 13/09/2011 22:29, Tom Anderson allegedly wrote:
> On Tue, 13 Sep 2011, Daniele Futtorovic wrote:
>> Okay, so you can have a lambda returning a value? Steve Simpson's
>> statement:
>>
>>> There's no (...) long jumps (break, continue, return, throw)

>>
>> seemed to contradict that, as did Tom's about the "Gafterist nonsense"
>> (<3), seeing how Gafter et al.'s proposal contained return values, IIRC.

>
> Brachaism-Gafterism is the CANCER THAT IS KILLING JAVA!!


It's "teh".

--
DF.
Determinism trumps correctness.
 
Reply With Quote
 
supercalifragilisticexpialadiamaticonormalizeringelimatisticantations
Guest
Posts: n/a
 
      09-14-2011
On 13/09/2011 4:29 PM, Tom Anderson wrote:
> Basically, lambdas can be either method-like (they return values from
> themselves) or statement-like (they return values from their enclosing
> methods).


Smalltalk blocks can do both. The usual return operator ^foo returns foo
from the enclosing method, but the if the block doesn't do a nonlocal
return or exception throw of any kind it evaluates to a value which is
equal to that resulting from the last expression inside of it. So:

[:a | ^(a + 1)] value: 3

returns 4 from the enclosing method;

[:a | (a + 1)] value: 3

returns 4 into the enclosing scope; and

[:a :b | b ifTrue: [^a] ifFalse: [a]] value: 3 value: x

returns 3 from the enclosing method if x is true and evaluates to 3
otherwise.

Yes, this can be confusing. But blocks are used to implement ifs, loops,
and other control structures so this ability seems necessary,
particularly to have any way to break out of a loop early, say because
you found something. It also means that Smalltalk methods and blocks are
fundamentally different things, whereas the Java lambda proposal
generates methods under the hood, rather than some new, separate
freestanding-function category of thing.

> Lambdas are method-like in all the current dynamic languages
> (AFAIK - they certainly are in Smalltalk, Python and Javascript).


Um, not really; see above. Smalltalk blocks are objects, and the value:,
value: value:, etc. methods can be called on them to run their code, but
they aren't themselves methods. In particular, they are different
classes in the Smalltalk object system: BlockContext vs. CompiledMethod.

If you meant though that they can evaluate to a value, that's true. On
the other hand if you meant they can't also nonlocal-return, that's not
true.

Incidentally, you can implement the behavior of Smalltalk blocks in even
Java 1.1, with a class something like:

public class BlockReturn extends RuntimeException {
public final Object value;
public BlockReturn (x) { value = x; }
}

public interface Block {
Object do (Object x);
}

....

public static Vector forEach (Vector i, Block b) {
Vector res = new Vector();
for (Enumeration e = v.elements(); e.hasMoreElements() {
res.addElement(b.do(e.nextElement()));
}
return res;
}

....

public Object nullOrHashCodes (Vector v) {
try {
return forEach(v, new Block() { public Object do (Object x) {
if (x == null) throw new BlockReturn(null);
return Integer.valueOf(x.hashCode());
}}
} catch (BlockException b) { return b.value; }
}

That last should end up taking a vector and returning null if it
contains nulls and otherwise a vector of Integers equal to the hash
codes, in order, of the objects in the input vector. Obviously, it's not
idiomatic Java 1.1, let alone idiomatic Java SE 6 where you'd just use a
foreach loop over a List, but it is isomorphic to how you'd do something
like that in Smalltalk, where it would be something like

coll collect: [ | x ifNil: [^nil] ifNotNil: [x hash]]

> The rationale was that enclosing any given wodge of code in a lambda
> definition immediately followed by an invocation of that lambda would
> not change the behaviour of the code. This seemed dubious to me, and
> would have led to very weird programming experiences. It would, though,
> have enabled a wider range of funky control structures implemented on
> top of lambdas, which some people are very keen on.


Smalltalkers, probably. Possibly Lispers too, though in Lisp lambdas
can't nonlocally return; Lispers implement new control structures using
macros instead, at least in the case that they need short-circuiting
behavior under some circumstances, such as loops in the bodies of which
there's some kind of break statement analogue possible. But both
Smalltalkers and Lispers are used to being able to implement new control
structures inside of their language.

It's not the first thing they'd probably miss in Javaland, though; the
lack of an interactive transcript would probably top the list, and the
limited reflection/introspection capabilities would come a close second.
It's easy to create new functions, methods, or classes on the fly at
runtime, for example, in those but not in Java. In fact, this is related
to Java's lack of an interactive transcript, in that that degree of
runtime reflection capability is needed to implement such a transcript
if it's to be possible to enter new code or bugfixes at it and not just
run ad hoc tests of existing code. (Not to mention, Windows-based
Lispers tend to use their Lisp repl as a command line shell in
preference to Windows's crummy cmd.exe. But inability to define new
functions at the repl would make it much less useful for such, since you
couldn't write ad hoc scripts and thus couldn't do the equivalent of
sed, awk, and perl hacking at it. For that matter, you'd lack lambdas
too, since using a lambda at the repl implicitly defines a new function,
so even doing something as simple as get a list of files in some
directory, sort descending by size, and return that list would become
impossible given that Lisp sort functions tend to expect the less-than
relation to use to be provided via lambda and tend not to already have a
built-in function that implements a less-than relation on files that is
based on file size.)
 
Reply With Quote
 
Joshua Cranmer
Guest
Posts: n/a
 
      09-14-2011
On 9/13/2011 3:29 PM, Tom Anderson wrote:
> Basically, lambdas can be either method-like (they return values from
> themselves) or statement-like (they return values from their enclosing
> methods). Lambdas are method-like in all the current dynamic languages
> (AFAIK - they certainly are in Smalltalk, Python and Javascript).


As I recall, Smalltalk lambdas were actually discrete blocks (Smalltalk
has (almost? [1]) no control structure primitives, and I distinctly
recall them allowing non-local control flow, since actual structures as
we know them in Java and its ilk don't exist. Python's lambdas are
single expressions (in a language that distinguishes between expressions
and statements), so it can't really be classified as statement-like or
method-like easily. JavaScript actually doesn't have lambdas [2], it
just has first-class functions that can be defined anywhere.

A more natural breakdown of lambdas, or at least clearer, is on whether
or not the lambdas are designed primarily for thunking expressions
(e.g., the parameter to a sort method), or if they are designed for
implementing control structure.

[1] My only exposure to Smalltalk was in my software engineering class
(don't ask), so we never really discussed any implications of its
functional paradigm.
[2] Actually, distinguishing between a lambda and a function is
sometimes difficult and perhaps pointless. The basic definition I'm
using here is meaningful only for object-oriented languages, and it's
the question of does `this' (or equivalent) refer to the same `this' as
in the enclosing scope or not. JS doesn't support OO in the classical
way, and how `this' gets resolved is actually handled by the way you
call the method. Another metric is whether or not the syntax of defining
a lambda is the same as a regular method call.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
Reply With Quote
 
supercalifragilisticexpialadiamaticonormalizeringelimatisticantations
Guest
Posts: n/a
 
      09-14-2011
On 13/09/2011 10:36 PM, Joshua Cranmer wrote:
> On 9/13/2011 3:29 PM, Tom Anderson wrote:
>> Basically, lambdas can be either method-like (they return values from
>> themselves) or statement-like (they return values from their enclosing
>> methods). Lambdas are method-like in all the current dynamic languages
>> (AFAIK - they certainly are in Smalltalk, Python and Javascript).

>
> As I recall, Smalltalk lambdas were actually discrete blocks (Smalltalk
> has (almost? [1]) no control structure primitives,


I seem to recall it having exactly one: method dispatch. Even blocks are
invoked by calling value:, value:value:, valueWithArguments:, etc.
methods on them. (The low level guts are ultimately accessed by methods
declared primitive, something like Java methods that are declared
native. Obviously the native code has its own control structures,
typically those of C. And ultimately it's the various branch and
compare-and-branch instructions of the hardware that implement
everything at the level of the metal.)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Type of lambda function returning a lambda function... Haochen Xie C++ 4 03-17-2013 11:23 PM
lambda vs non-lambda proc Steve Dogers Ruby 1 03-30-2009 10:11 PM
Special keyword argument lambda syntax Beni Cherniavsky Python 1 03-14-2009 05:48 PM
1.9 -> lambda syntax with & Farrel Lifson Ruby 1 11-18-2008 09:48 AM
Re: Lambda as declarative idiom (was RE: what is lambda used for inreal code?) Roman Suzi Python 13 01-07-2005 09:33 PM



Advertisments