6 ms·
> 2006-2010 [...] a new crop of JVM-based languages emerged. [...] JRuby was soon followed by Groovy, Scala, Clojure and many others. Each language introduced f
by vorg 11y ago
> 2006-2010 [...] a new crop of JVM-based languages emerged. [...] JRuby was soon followed by Groovy, Scala, Clojure and many others. Each language introduced features that were unique and unavailable in Java
Languages that are JVM versions of already existing languages were out long before JRuby (JVM' Ruby) and Clojure (JVM's Lisp). I remember Jython (JVM's Python) was first released around 1997, then called JPython. At that time there was also the Jacl language (JVM's TCL).
Beanshell's also an older language, which Groovy cloned and added closures (since made obsolete by Java 8's lambdas) and a meta-object protocol to. As for Scala, it's like a more statically-compiled and functional version of Groovy, about which Groovy's creator said he'd never have created Groovy if he'd known about Scala.
- WalterGR 11y agoGroovy cloned and added closures (since made obsolete by Java 8's lambdas) Java's lambdas aren't real closures, though. Are Groovy's? Edit: "Real" is, I suppose, arguable. By that I meant: Java's lambdas don't support mutation of captured variables.
- speakeron 11y ago> Java's lambdas don't support mutation of captured variables A variable has to be declared 'final' to be visible from a Java closure (anonymous inner class in pre-1.8 Java). This means you can't mutate a primitive or an object reference, but it's possible to change the contents (instance variables) of an instantiated object captured by the closure. (And, indeed, this is exactly what you do in this situation).
- WalterGR 11y agoAh, I see. Thanks.
- vorg 11y ago> Java's lambdas don't support mutation of captured variables I've never used Java 8 lambdas but that sounds the same as Java's inner classes which I'm now guessing lambdas are syntactic sugar for. I remember the common trick with inner classes to enable mutation was to declare and initialize a size 1 array of the required type instead of the type itself, and refer to, say, myvar[0] instead of myvar inside the class. I'm guessing this would then work with Java 8 lambdas also. > Java's lambdas aren't real closures, though. Are Groovy's? I last used Groovy at version 1.8 so don't remember for sure but think they did allow mutation. Groovy's closures also have the delegate lookup flag to enable dynamic scoping of names within closure code passed around and executed later, which I don't imagine lambdas have. Such a trick is done with macros in lisps like Clojure.
- danieldk 11y agoEdit: "Real" is, I suppose, arguable. By that I meant: Java's lambdas don't support mutation of captured variables. Then Haskell doesn't have closures either ;). I think the definition of a closure is: a lambda abstraction / anonymous function that uses a free variable in its definition. So, Java's lambdas are real closures.
- WalterGR 11y agoMaybe I'm just biased because I was first introduced to closures by SICP, and so Scheme's take became my personal Platonic Ideal. :)
- deleted 11y ago[deleted]
- m_mueller 11y ago> lambdas (that support) mutation of captured variables. is that really a good idea?
- deckiedan 11y agoIt's quite a cool trick for avoiding mutable global state, or clobbering the global namespace. It's used a lot in javascript projects. function make_counter() { var i = 0; return (function() { return i++; }); } var blah = make_counter(); every time you call `blah()` now, it will return the next number in the series, but there's no way for anywhere else in the application to modify `i`. This can be useful as an iterator, so giving you effectively the same as `yield`-ish generators in python.
- WalterGR 11y agoI think the counter-argument is that all mutable state is bad, and the equivalent thing could be accomplished if invoking `blah` returned the next number in the series as well as a new closure that does the same thing.
- deckiedan 11y agoSure, everything as immutable does make certain guarantees about the code a lot easier. Also certain algorithms become very nice. Purity is pretty awesome. I really like conceptual Haskell (actual real Haskell tends to become too abstract for my brain to remember important details when I come back to a project...). The (sad) fact is that mutating a bit of state is actually often much faster, or a lot cleaner to read / understand than implementing a fully pure functional version. And by limiting access to state, you make sure you don't accidentally introduce dependencies. Using closures like this, can end up being very similar to object-oriented code (in the best-case, strictly limited sense) whereby each area of concern in the code can only modify what you expect it to be able to modify, and you can be sure nowhere else in the code can access it.