Path: csiph.com!x330-a1.tempe.blueboxinc.net!aioe.org!.POSTED!not-for-mail From: supercalifragilisticexpialadiamaticonormalizeringelimatisticantations Newsgroups: comp.lang.java.programmer Subject: Re: new Java lambda syntax Date: Tue, 13 Sep 2011 20:25:35 -0400 Organization: supercalifragilisticexpialadiamaticonormalizeringelimatisticantations Lines: 121 Message-ID: References: <9j3vj8-aqe.ln1@news.simpsonst.f2s.com> NNTP-Posting-Host: A2uecqCQlmj3ebU0+CkZsQ.user.speranza.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: WinVN 0.99.12z (x86 32bit) X-Notice: Filtered by postfilter v. 0.8.2 Xref: x330-a1.tempe.blueboxinc.net comp.lang.java.programmer:7998 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 | 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.)