7

I've first asked this question about the use of final with anonymous inner classes in Java: Why do we use final keyword with anonymous inner classes?

I'm actually reading the Scala book of Martin Odersky. It seems Scala simplifies a lot of Java code, but for Scala closures I could notice a significant difference.

While in Java we "simulate" closures with an anonymous inner class, capturing a final variable (which will be copied to live on the heap instead of the stack) , it seems in Scala we can create a closure which can capture a val, but also a var, and thus update it in the closure call!

So it is like we can use a Java anonymous innerclass without the final keyword! I've not finished reading the book, but for now i didn't find enough information on this language design choice.

Can someone tell me why Martin Odersky, who really seems to take care of function's side effects, choose closures to be able to capture both val and var, instead of only val?

What are the benefits and drawbacks of Java and Scala implementations?

Thanks

Related question: With Scala closures, when do captured variables start to live on the JVM heap?

Community
  • 1
  • 1
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
  • Another thought on this. Powerful closures are at the heart of many idioms that Scala programmers make use of. Actors is one. The ability to create your own control structures is another. – Theodore Norvell Oct 14 '12 at 16:39

2 Answers2

8

An object can be seen a bag of closures that share access to the same environment and that environment is usually mutable. So why make closures generated from anonymous functions less powerful?

Also, other languages with mutable variables and anonymous functions work the same way. Principle of lease astonishment. Java is actually WEIRD in not allowing mutable variables to be captured by inner classes.

And sometimes they're just darn useful. For example a self modifying thunk to create your own variant of lazy or future processing.

Downsides? They have all the downsides of shared mutable state.

James Iry
  • 19,367
  • 3
  • 64
  • 56
  • 4
    When I was an undergraduate, I implemented an OO language. It was the first OO language I had access to. (This before C++ made OO popular.) Like Scala, the language had lexical scoping, assignment to local vars, closures that could capture local vars, and objects. Having done that, I realized that objects and classes were definable in terms of the other language features and promptly lost interest in OO programming for a few years. – Theodore Norvell Oct 11 '12 at 18:04
1

Here are some benefits and drawbacks.

There is a principle in language design that the cost of something should be apparent to the programmer. (I first saw this in Holt's Design and Definition of the Turing Language, but I forget the name he gave it.) Two things that look the same should cost the same. Two local vars should have similar costs. This is in Java's favour. Two local vars in Java are implemented the same and so cost the same regardless of whether one of them is mentioned in an inner class. Another point in Java's favour is that in most cases the captured variable is indeed final, so there is little cost to the programmer to be prevented from capturing nonfinal local vars. Also the insistence on final simplifies the compiler, since it means that all local variables are stack variables.

There is another principle of language design that says be orthogonal. If a val can be captured why not a var. As long as there is a sensible interpretation, why put in restrictions. When languages are not orthogonal enough, they seems perverse. On the other-hand, languages that have too much orthogonality may have complex (and hence buggy and/or late and/or few) implementations. For example Algol 68 had orthogonality in spades, but implementing it was not easy, meaning few implementations and little uptake. Pascal (designed at about the same time) had all sorts of inelegant restrictions that made writing compilers easier. The result was lots of implementations and lots of uptake.

Theodore Norvell
  • 15,366
  • 6
  • 31
  • 45
  • 2
    Instances of Java's non-static inner classes retain a reference to their containing object. I'd argue that already pushes them into a realm where cost isn't totally apparent to the programmer. – James Iry Oct 11 '12 at 04:51
  • 1
    Another point in favour of Java's approach is that it implies that there is no aliasing of local variables. If I write "int i=0 ; foo.bar() ; assert i==0;" I can be sure that the assertion will hold. This is good for reasoning about programs and also makes things easier for optimizers. – Theodore Norvell Oct 11 '12 at 17:30
  • That's right. Closures can elevate mutable local variables to have all the same power and problems that mutable object fields have. In other words you can take your example and make i a field of the object and that assertion may or may not hold depending on exactly what foo.bar() does. For instance, if foo.bar() calls a method on this object that mutates i then the assertion won't hold. – James Iry Oct 11 '12 at 17:50