4 ms·
I've been playing around inside the closure-compiler in my free time recently and the thing that struck me most after years of working in other languages (Ruby,
by johnbender 15y ago
I've been playing around inside the closure-compiler in my free time recently and the thing that struck me most after years of working in other languages (Ruby, JavaScript, C#) is that Java is relatively simple. While it's obviously a very small sample set, I have yet to find myself spending any significant amount of time wondering at what a given snippet of code does.
I don't have any Scala experience but in general simplicity has major and obvious benefits (as noted many times in the letter).
- 6ren 15y agoIsn't the counter-argument that Java code is harder to understand at a slightly higher level, of how classes interact? And that in more expressive languages, that complexity is pushed down to the code level, so the total complexity is the same, just in different places. Of course, there's an advantage to being able to understand a snippet locally, in isolation from the rest of the project, if that's all you need to understand (e.g. when making a local change).
- johnbender 15y agoDo you mean that, because code is more expressive/terse, less project level (class, factory, etc) juggling is required? What you're saying seems to make sense but I'm trying to conjure an example to help me understand it.
- 6ren 15y agoYes. There's a family of examples with design patterns, where what is a design pattern in a less expressive language like Java requiring a standard arrangement of classes, is absorbed into the language in a more expressive language. The "design pattern" is a kind of redundant overhead. Describing examples is a bit involved, because you have to describe both the pattern and the expressive alternative. One concrete example is the visitor pattern, which is more simply written with multi-methods (a multi-method is one that is dynamically selected by the type of its arguments - though Java can have methods with the same name but different arguments, they are selected statically, based on compile-time types rather than runtime classes). I actually can't think of any other examples off the top of my head, but "design patterns are language features in more expressive languages" is a common idea, so I'm sure others can suggest other examples (or google). EDIT here we go (includes a list of examples) http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatures http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatu...
- teyc 15y agoHere's an example: In the days of assembler, you need a convention of who is responsible for cleaning up the stack, caller or callee. People writing assembly which calls out to functions would essentially have to write the same boilerplate code each time. With C, it becomes a non-issue.
- scott_s 15y agoThat's another good one. I think people tend to apply this principle to concepts from functional languages, but forget that there are many abstractions in imperative languages that simplify styles of programming in the same way.
- orangecat 15y agoI actually can't think of any other examples off the top of my head, but the "design patterns are language features in more expressive languages" is a common idea, so I'm sure others can suggest other examples (or google). As a specific case, Python has many design patterns built into the language. Iterator pattern: generators and iter/next. Factory pattern: have class objects override __new__, callers don't need to know the details. Singleton: just use module-level functions; modules are themselves objects if you need to replace/stub/mock them. And as with any language that has first class functions/methods/callables, the command and strategy patterns mostly go away.
- scott_s 15y agoThat's one of the main points of pg's "Beating the Averages" essay, where most people got the term "Blub programmer": http://www.paulgraham.com/avg.html http://www.paulgraham.com/avg.html The visitor pattern is a good example, but I think another good one are classes. You can write object-oriented programs in C, but it requires that you, the programmer, enforce all of the concepts of classes (member functions, instantiation, inheritance, etc.) yourself. I think that is a clear example where more expressive/terse code (that is, language-level support for OO) requires significantly less juggling across the code base.
- daniel_solano 15y agoYes, Java is generally fairly simple. I generally find that the most difficult part of Java is generics. On the other hand, anything that you want to work at a slightly higher level, such as closures or higher-order functions, Java just gets in your way since you have to it all by hand. Thinking about Scala, there are a couple of problems with its simple/complexity balance: 1. Some things that appear fairly simple actually explode into a huge mess of complexity under the hood. Often, that's not a problem. However, sometimes it becomes a problem because you don't really know what's going on. 2. Some things that should be simple and straightforward, like iterating through an array, are impossible. These are cases were the language is actually removing some of the power of the underlying platform.
- extempore 15y ago> Some things that should be simple and straightforward, like iterating through an array, are impossible. Impossible? array foreach f array map f Or if you miss java enough: var i = 0 while (i < array.length) { f(array(i)) ; i += 1 } I can't even imagine what it is you think is impossible.
- daniel_solano 15y agoYou're right, it's not quite impossible. However, the idiomatic ways of doing things in Scala tend to be very bad for performance if you're in a tight loop. For example, if you have two arrays that you need to iterate through simultaneously, you need to zip them together. In order to regain the performance, you end up having to do something like the while loop or use recursion. This is similar to the problem of doing heavily numeric code in Clojure before release 1.3. You could get Java-like numeric performance out of Clojure, but you'd have to abandon doing it in any sort of ideal way. One example where something was impossible in Scala is that to implement a Parcelable for Android. This requires the creation of a static field, which Scala doesn't allow. Now, I won't argue that an API that requires such a construct is good, but it might be necessary for your application. I believe Scala now contains special code in the compiler just to support this peculiarity in the Android API.