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 -
>> 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. And a third
>> "father of Java", Bill Joy, also wanted full support for closures since day
>> one: 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/**
>>>> msg/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.
>>
>> 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 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.