I disagree that the C# example is contrived, having accidentally made the mistake they show.
On Thu, Sep 15, 2011 at 9:37 AM, opinali <[email protected]> wrote: > Oh got it. I agree that return/break/continue (the so-called non-local > returns) are a problem, although they are only such a big problem if we > don't want to improve the classfile/bytecode/VM specs to have a specialized > mechanism for this in order to not depend on the exception hack. > Unfortunately, too many Java language improvements are tainted by this > criteria of desiring as few changes to the VM platform as possible. > > But I don't see this problem as a justification for the separate issue of > mutable capture. We're talking about completely distinct features. Capturing > mutable local vars has a trivial implementation (lifting the variable to a > field of the closure object, visible both from the defining scope and from > the closure code). > > I read the C# example, and it didn't impress me; it's not just contrived, > it's a VERY contrived example. You can easily build such examples to show > that every single feature of any language can be involved in some > incorrect/confusing code. In the example, the bug is not caused only by > mutable capture - it's mostly likely caused by programmer's failure to > realize that the execution of the closure will be deferred. This is the most > fundamental property of a closure if compared to a regular block or > expression inside the containing method; developers can shoot themselves in > the foot all day long if they fail to be aware of when the code of closures > is actually executed, without even needing mutable capture. Taking a page > from lambda-dev (from Neal Gafter IIRC), closures (including mutable > capture) are an ages-old feature which use is time-proven by numerous > languages. > > A+ > Osvaldo > > > On Thursday, September 15, 2011 3:10:39 AM UTC-4, Ricky Clarkson wrote: > >> What I perhaps didn't make clear is that I'm talking about taking some >> code that's part of a method, and then making it part of a lambda within >> that method. >> >> E.g., in some imaginary syntax: >> >> void foo() { >> if (Math.random() < 0.5) >> return; >> System.out.println("Foo"); >> } >> >> void foo() { >> timeHowLongThisTakes( () => { >> if (Math.random() < 0.5) >> return; >> } ); >> System.out.println("Foo"); >> } >> >> Return is one example; others are break, continue and throw. The meaning >> is not kept if you wrap that code into a new Runnable() { public void >> run()... } >> >> Gafter's original, well thought-out, argument was that wrapping code in a >> closure should not affect its meaning, which makes a lot of sense, but the >> actual mechanisms needed to do that at least before engaging the VM team are >> odd, it used exceptions under the hood to manage these things, and there >> were objections to that. And (answered) questions about what return; would >> mean if the lambda were to be executed on a different thread to the >> surrounding method. >> >> I think at this stage it makes sense to stick with a restricted lambda and >> get that in stone. The current proposal does not in any way preclude Oracle >> from adding support for capturing mutable variables, a notation for outer >> returns, enabling break and continue, and making throws able to be >> transparent. >> >> Regarding mutable variables, I'm sure you read the passage I quoted from >> the C# specification and can appreciate that it's not all roses without that >> limitation. It's not just theoretical, in my brief time on Freenode's >> ##csharp I noticed it appeared fairly often. Whether it was deliberate 14 >> years ago I don't think matters any longer. >> -- >> Skype: ricky_clarkson >> >> >> On Wed, Sep 14, 2011 at 11:12 PM, opinali <[email protected]> wrote: >> >>> On Wednesday, September 14, 2011 9:15:30 PM UTC-4, Ricky Clarkson >>> wrote: >>>> >>>> I think the problem is that whenever you start trying to make sure that >>>> all code wrapped in a lambda behaves the same as code not wrapped in a >>>> lambda (return, break, this, continue, throw all behaving the same way) you >>>> get into odd territory and someone picks up on it and reacts. >>> >>> >>> This seems to be mixing things. Code inside an inner class certainly >>> behaves exactly like all other code; specifically, you can define mutable >>> variables and you can assign to these variables. So the typesystem inside >>> the "closure" is exactly the same. Which in this case, makes inner classes >>> even more broken, it would be cleaner if inner classes had been designed as >>> a pure-functional subset of the language that couldn't do destructive >>> assignments at all. >>> >>> See Guy Steele's comments about inner classes: http://people.csail.** >>> mit.edu/gregs/ll1-discuss-**archive-html/msg04044.html<http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg04044.html> >>> - >>> Java was initially planned to have closures, including mutable capture, but >>> that was cut from JDK 1.0 and when they introduced inner classes in 1.1, it >>> didn't have mutable capture and the reason was just "users feared the >>> performance cost" - maybe reasonable concern with JDK 1.0's VM with the >>> crappiest GC ever, but an obsolete issue since HotSpot, not to mention that >>> other language features already ignore any concerns (performance or other) >>> of implicit allocations, like Steele points. Also, James Gosling referred to >>> inner classes as an `"uncomfortable compromise ... that didn't really solve >>> any problems": >>> http://blogs.**oracle.com/jag/entry/closures<http://blogs.oracle.com/jag/entry/closures>. >>> And a third "father of Java", Bill Joy, also wanted full support for >>> closures since day one: http://www.blinkenlights.** >>> com/classiccmp/javaorigin.html<http://www.blinkenlights.com/classiccmp/javaorigin.html> >>> >>> TL;DR: The mutable capture limitation of inner classes was NOT introduced >>> by design. Not one of the original Java designers are proud of inner >>> classes. Any attempt to justify this limitation as something that makes >>> sense with good language design principles, is rewriting history - "it's not >>> a bug, it's a feature". >>> >>> A+ >>> Osvaldo >>> >>> >>> >>>> >>>> Scala actually does some* of what Gafter's original proposal did >>>> regarding control, and the reality is I've only ever noticed when I >>>> explicitly tested it to see if I could observe a NonLocalReturnException. >>>> However, I don't think we're going to win that fight, and C#'s level of >>>> lambda support really is a marked improvement over what we have in Java >>>> today. >>>> >>>> * some, because Scala doesn't have continue or break. >>>> >>>> -- >>>> Skype: ricky_clarkson >>>> >>>> >>>> On Wed, Sep 14, 2011 at 8:38 PM, opinali <[email protected]> wrote: >>>> >>>>> Hi clay, >>>>> >>>>> Ok let's be more formal now. I agree with option A below (instead of >>>>> B); "closure" is very well defined in numerous classic CS books as the >>>>> pairing between a function and an environment that provides bindings to >>>>> its >>>>> free variables. The concept comes from lambda calculus where functions can >>>>> only exist in the form of functions, so I understand view B - but >>>>> practical >>>>> programming languages are very distant from pure lambda calculus; only in >>>>> the Lisp family (I think) they are really the same because functions are >>>>> just sugar for a lambda - i.e. a function is a lambda that is bound by >>>>> some >>>>> name to some environment. But there are many other languages, including >>>>> Java, where this doesn't happen, unless you interpret the concept of >>>>> "environment" as something more general, including the all scoping rules, >>>>> classloaders, etc. IMHO this is going a bit too far, I'm happy with a >>>>> definition of closures that does not depend from lambdas. >>>>> >>>>> Now back to my points 1/2, let's try to refine the discussion to its >>>>> true essentials: the major point of debate is whether Java's closures >>>>> (with >>>>> or without Java 8's lambdas) are "good enough". So let's try to define >>>>> what >>>>> constitutes good enough. I am a strong advocate of very powerful >>>>> closures; I >>>>> was rooting for BGGA with its non-local returns, control abstractions..., >>>>> but I concede that these features are only necessary to extend Java's >>>>> paradigm, allowing significant new idioms. But it's fair to require for >>>>> "good enough", an implementation of closures that is at least sufficient >>>>> to >>>>> get along with the *existing* language paradigm, idioms and other features >>>>> (typesystem, OO model etc.) - anything better that that is a bonus. If we >>>>> agree on this, then "good enough" boils down to orthogonality. And the >>>>> current support for closures (without capture of mutable variables) is >>>>> clearly NOT orthogonal, because destructive assignment is a HUGE part of >>>>> the >>>>> Java language. No amount of fancy functional-esque frameworks or >>>>> conventions >>>>> can change this simple fact. It's broken since JDK 1.1's introduction of >>>>> inner classes, and it will be broken in Java 8's even with lambdas, nice >>>>> syntax, and tons of new or retrofitted APIs to use closures/lambdas. >>>>> >>>>> A+ >>>>> Osvaldo >>>>> >>>>> >>>>> On Tuesday, September 13, 2011 7:58:02 PM UTC-4, clay wrote: >>>>>> >>>>>> From the best I can gather, the principle disagreement is definitions. >>>>>> >>>>>> There are three views in this thread: >>>>>> >>>>>> A) Java has closures. Closures, by definition, do not necessarily >>>>>> require lambdas or first class functions, which Java doesn't have. >>>>>> B) Closures, by definition require lambdas and/or first class >>>>>> functions, so since Java doesn't have those, it can't have closures. >>>>>> C) Pure closures, by definition, don't limit you to accessing only >>>>>> "final" variables, so the anonymous class functionality doesn't >>>>>> qualify as a closure. >>>>>> >>>>>> Osvaldo, >>>>>> >>>>>> Regarding point #1: First, I think you mean anonymous classes, not >>>>>> inner classes. Secondly, I'd stress that anonymous functions (lambdas) >>>>>> >>>>>> are a distinct feature from closures. A language can have one feature >>>>>> >>>>>> but not the other. Java has closures, but not lambdas. And I can't >>>>>> think of them off the top of my head, but I'm sure there are languages >>>>>> >>>>>> with lambdas that don't close over the defining environment, and >>>>>> therefore don't have closures. >>>>>> >>>>>> Regarding point #2: I'm not sure what you are getting at here. Sure, >>>>>> Java is behind the pack in terms of immutable programming and >>>>>> functional programming support, but you can use third party libraries >>>>>> like Functional Java and adopt that style as a programmer. Only a few >>>>>> languages like Haskell really force those concepts on you and >>>>>> guarantee safety from mutability issues. In Scala, immutable code and >>>>>> functional programming still requires programmer compliance and it's >>>>>> easy to write imperative mutable code. Regardless, this seems like a >>>>>> tangential issue. >>>>>> >>>>>> Kevin, >>>>>> >>>>>> I'm not arguing that Java has closures because you can achieve the >>>>>> same goals without real language level support. I'm arguing that >>>>>> closures are inner functions/methods that can access variables from >>>>>> the outer function/method scope, and the Java language syntax >>>>>> completely supports that. You are claiming that closures require >>>>>> lambdas by definition, and I disagree with you on that definition. >>>>>> Java doesn't have lambdas. Sure, you can achieve similar results with >>>>>> anonymous classes, but the Java language itself doesn't provide >>>>>> lambdas. >>>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "The Java Posse" group. >>>>> To view this discussion on the web visit https://groups.google.com/d/* >>>>> *ms**g/javaposse/-/53VocU4KYT0J<https://groups.google.com/d/msg/javaposse/-/53VocU4KYT0J> >>>>> . >>>>> >>>>> To post to this group, send email to [email protected]. >>>>> To unsubscribe from this group, send email to >>>>> [email protected]**. >>>>> >>>>> For more options, visit this group at http://groups.google.com/**group >>>>> **/javaposse?hl=en <http://groups.google.com/group/javaposse?hl=en>. >>>>> >>>> >>>> -- >>> You received this message because you are subscribed to the Google Groups >>> "The Java Posse" group. >>> To view this discussion on the web visit https://groups.google.com/d/** >>> msg/javaposse/-/Fff1UZB3f5EJ<https://groups.google.com/d/msg/javaposse/-/Fff1UZB3f5EJ> >>> . >>> >>> To post to this group, send email to [email protected]. >>> To unsubscribe from this group, send email to >>> [email protected]**. >>> For more options, visit this group at http://groups.google.com/** >>> group/javaposse?hl=en <http://groups.google.com/group/javaposse?hl=en>. >>> >> >> -- > You received this message because you are subscribed to the Google Groups > "The Java Posse" group. > To view this discussion on the web visit > https://groups.google.com/d/msg/javaposse/-/W8qWzFi4XtoJ. > > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/javaposse?hl=en. > -- You received this message because you are subscribed to the Google Groups "The Java Posse" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.
