Java is deliberately not programmer-orientated. That's the point of using it — it was designed to restrict the kind of trouble programmers can get themselves into. If you're stuck with the JVM, I guess the question is: how much rope do you want to give your programmers? Scala is essentially the opposite answer to Java.
This was an interesting read but I disagree with this assertion. Java's lack of power as a language hasn't meant that people haven't written huge, complex, unmaintainable messes with it. Indeed, I think all the crazy dependency injection frameworks, configuration-by-XML, and other general insanity is due in part to the language's lack of power. Things that are simple in other languages (say, dependency injection, which can be replaced with runtime stubbing in Ruby or mixing in traits in Scala) often require painful and complicated ad-hoc solutions in Java.
That said, it is possible to write code in Scala that requires a PhD in category theory to understand (see Scalaz), but there are also many examples of simple, functional, easy to understand code (see stuff that has come out of Twitter, like Kestrel or Nagatti).
I think in practice, working with the modern Java ecosystem gives one at least as much rope to hang oneself as using Scala does.
My observation is that no matter what language it is written in software tends to evolve towards a level of complexity that is determined by the culture of the people writing it rather than the language. Every project uses up its complexity budget one way or another. The budget is not determined by the language, but by the culture and skill of the people doing the work.
As a simple language, Java tends to result in complicated frameworks. This is a problem because every framework is complicated and different - you can't infer what one is doing by knowing another. Given this, I like having the complexity supported in the language. I'm going to have to deal with it anyway, but at least I can count on the language being the same where ever I go, so I can learn it once and have a reusable skill.
I've found that the best thing you can do with a bad programmer is to let them write the code in whatever potentially inferrior way they think it should be written, in contrast to trying to force them to write it in some better way that they don't understand. It's always better for them to understand what they are coding and why they are coding it that way.
Java forces bad programmers to use patterns that they don't understand. Inevitably, this results in those patterns being applied incorrectly, which is worse than not applying the pattern at all. It's worse still if the programmer thinks they understand the pattern, but doesn't. No type system can guarantee that an API is used correctly on more than a superficial level, nor can it guarantee good architecture or correct behavior.
The best language for a bad programmer to use is a flexible and expressive one. The more easily they can express themselves, the better chance you have of understanding their misconceptions. Forcing their broken ideas into a restrictive language will just mangle them further, producing dailywtf material.
Monkeys are dumb, but a monkey doing calculus is even dumber.
You may disagree, but the assertion is correct. Java was deliberately designed to restrict what programmers could do. The belief was that this would help maintainability, and particularly when trying to get large teams to cooperate.
That Java users have found ways to get around deliberate limitations does not change the fact that this was the original intent of the language design.
The part I was disagreeing with is that Scala gives programmers more "rope to hang themselves with". You may be correct that restricting what programmers could do was a goal of Java, but writing Java in practice gives a tremendous number of opportunities to hang oneself. Apologies for not being more clear.
Further, it's not like this complexity is something that arose independently of Java itself. One of the most frequently cited examples of super-complicated insanity in the Java world is J2EE, which is a standard and set of libraries created by Sun itself. If the creators of language have managed to create and propagate one of the biggest tarpits available in Java, that reflects poorly on the overall Java ecosystem.
I've witnessed this first hand at place I've worked! When all you know is Java, somehow an XML-based solution starts to look really appealing. I wouldn't know. It's been such a long time since all I knew was Java. But apparently, when you want a a more flexible language but don't want to spend the effort actually learning one, coding up a brand new DSL with XML syntax seems like a great idea! Hopefully the proliferation of better languages on the JVM will end this practice gradually, but in the end it will depend on a new generation of programmers being more educated on basic principles in computer science.
Scala's traits come nowhere near the functionalities offered by dependency injection frameworks such as Guice. When Scala encounters the need for DI, it's very likely that it will roll out a framework that will look a lot like Guice.
Your point regarding the rope is well taken, the difference being that with Java, the rope lies in the frameworks, while in Scala, it lies both in the frameworks (take a look at Lift) and in the language.
Well, for a big enough project something like Guice will become necessary sooner or later. However, for smaller programs traits are simpler to use and get one 80% of Guice's functionality--and it's all built into the language. Traits are relatively easy to understand that any reasonably competent developer should be able to easily reason about. I don't see why a Scala-native DI framework wouldn't be able to leverage this existing, simple solution to build the last 20%.
Guice is the result of smart Google engineers who had probably tried all sorts of DI frameworks before and finally developed something nice. It's the result of more than a decade of painful experiences with existing solutions to a real problem.
In conclusion, I think you can hang yourself when using any language. In Scala, when I needed to mock out a dependency for a project, I settled on a fairly simple trait-based approach that was simple and elegant. In Java, I could have rolled by own Factory scheme that would be ugly and unmaintainable, or picked a DI framework that hopefully wouldn't have sucked. In this case I was presented with many fewer opportunities to make a mess than if I had been using Java.
All fair points, but I'm really curious to see what you did with traits that has anything to do with dependency injection. DI is essentially a runtime activity while traits are just a more granular way of assembling your objects together at compile time. I just don't see the intersection between the two concepts.
I have the feeling that you might be confused about what DI is exactly, but I'll happily eat my words if you can point me to a description of what you did, some source code, a blog post or whatever.
My approach was thus: basically, define an abstract trait that specifies methods that return given dependencies. Any class that required dependencies extends this trait and is itself abstract. Then, when you want a real working instance of the class you mix in a concrete implementation of the trait. It's simple, declarative, and it got the job done. Here's an example of the pattern:
abstract class Foo {
def addToMe(i: Int):Int
}
abstract trait FooService { def foo: Foo }
class RealFoo(j: Int) extends Foo {
def addToMe(i: Int) = i + j
}
trait RealFooService extends FooService { def foo = new RealFoo(42) }
abstract class NeedsFoo extends FooService {
def doSomething = foo.addToMe(100)
}
(new NeedsFoo with RealFooService).doSomething
// Int = 142
class TestFoo extends Foo {
def addToMe(i: Int) = i + 1
}
trait TestFooService extends FooService { def foo = new TestFoo }
(new NeedsFoo with TestFooService).doSomething
// Int = 101
Now, this is all done at compile-time, but it really seems to accomplish most of what the first few examples in the Guice documentation do, with similar amounts of boilerplate. Again, I'm sure this approach would fall short in many more complicated scenarios, but it gets you a hell of a lot farther than Java does in solving this problem without adding any extra frameworks. Traits are also not very difficult to reason with.
Scala is finally giving Java programmers a grown up language.
Java is the "oh this is explicit, I just wrote a program the size of the federal register!" language. It is overly simplistic in several areas thereby causing complex workarounds to be implemented to solve real world issues.
It's not just a better Java, if you ask me. Scala, like Clojure, aren't really pure Java replacements, fixing some of the bugs and awkward syntax details. Both try to steer the programmer towards different ways of programming. They're better, and more.
As I'm currently taking a look at Android development, I wish there was a simply "better Java". Something that doesn't stray too much from imperative C/Algol/Pascal-like programming, but doesn't require me to use a huge, bloated IDE just to cope with the language features. Better variable declaration, better modules, uniform access principle etc. Fantom looks interesting but -- again -- tries to be more than that (own library, multi-VM etc.).
Scala is actually a better Ruby. All the messy fun stuff that we all love with Ruby like duck typing and monkey patching can be done easily with Scala, except it's all statically typed so it keeps the whole mess under control.
For instance, you can have a duck type as a function argument that's contract is it implements a particular method signature. In Ruby there is no type type enforcement so you can get runtime errors when you pass in an object that doesn't have the right method, while in Scala the compiler catches it.
You can monkey patch by doing implicit conversions in Scala to a rich type, allowing one to add methods to the Integer class, for example, but if you have to libraries that do the same monkey patch Scala will alert you to ambiguous situations. In Ruby this depends on load order and can cause all kinds of screwy bugs.
Scala is brilliant in a way in that it hides all the incredible complexity you incur when you try to statically type a programming style evolved in dynamic languages. That is, it hides it to a point. It's easy enough to get started writing simple scripts and sprucing up old Java code but before long you get a compiler error that sends you scurrying away to the reference books and then it hits you that you really are going to have to come to grips with the type system and it's a doozy.
I'm still not persuaded that all the gymnastics Scala has to do to allow Ruby-like flexibility really result in a more productive language overall. I need to spend more time with it to be sure but at first blush it really feels like the faustian bargain Scala has had to strike to merge expressive, Ruby-like syntax with strong, static type-checking and java compatibility has resulted in a language too complex for most working programmers.
Clojure seems a lot more elegant and comprehensible.
I agree that Scala will never be a good replacement for languages Ruby both because of its complexity and the fact that dynamic languages are always going to be more flexible than statically typed languages. The fact that majority of new languages are in fact dynamic ones is also a good indication of the inherent difficulty in designing a good statically typed language. Scala is a much grander project in scope than Clojure, Ruby, Python, Groovy, or pretty much any of the dynamic languages sprouting up on the JVM probably ever will be. For instance, because these languges are dynamic, they don't care to deal directly with things like the cost of autoboxing, the price of type erasure, the ugly hackery that is java arrays, and so on. Life is simple when everything is of type Object! Of course, this grander scope comes with a cost, and that cost is language complexity.
In my opinion, Scala's aim is to take on Java by providing a much more overall productive language than Java while still maintaining Java's performance. I feel it's very much akin to the goals of C++ versus C. Fortunately, the people behind Scala are well versed in PL theory and make sensible language design decisions, so at this point Scala is in little danger of someone writing an FQA on it any time soon.
Sorry, but this comment is pretty misinformed. Clojure has numerous facilities to address the performance issues you mentioned. You can, for example, annotate parameters to a function with type information to use primitives, java arrays, and remove the need for reflection.
Additionally, JRuby has had a JIT that attempts to do smart things to avoid unnecessary boxing and reflection. They've been rather impeded by the JVM on this front, but JVM 7 looks to open a lot of doors for the JRuby team to remove a lot of unnecessary dynamic dispatch in the execution of Ruby code.
The problem I see with Scala is it reeks of Perl 6's "everything and the kitchen sink" language feature-a-thon. Having learned Clojure and started Scala recently I'm constantly asking myself why Scala code has so much incidental complexity compared to the equivalent Clojure code. Often, it is due to the type system or the excessive number of constructs and syntax available in the language.
"All arguments are passed to Clojure fns as objects, so there's no point to putting non-array primitive type hints on fn args. Instead, use the let technique shown to place args in primitive locals if they need to participate in primitive arithmetic in the body.".
Also, I'm not an expert on JRuby's attempted optimizations, but if I understand correctly they are very limited, much in the same way that Java's escape analysis is. The post By Charles Nutter less than a year ago is illuminating in that regard(http://groups.google.com/group/jvm-languages/browse_thread/t...). Have things changed that significantly since then? I follow his blog regularly and in most benchmarks I can remember him talking about he still compares JRuby to Java running boxed math.
A language can be both static and dynamic. C# introduced the 'dynamic' keyword, and perhaps they'll go further with that idea in the next version. The Java 7 JVM will have the 'invokedynamic' instruction, plus a new Java API to manage it. Perhaps Scala will extend the language syntax at that time to allow dynamic typing, with that API underneath, for those few cases where dynamic typing's better.
A language that was dynamic first, then added the static, is Groovy and Groovy++.
When I get a compiler error in Scala it's almost always something that would cause a runtime error in a non statically typed language. The downside is that the error messages can be difficult to parse and resolve for beginners. Once I got over the learning curve, I realized that in almost all cases the compiler was trying to tell me something very useful. I do get a little annoyed at all the Haskell/OCaml type nerds trying to do things with the type system that are not particularly practical, for instance: http://apocalisp.wordpress.com/2010/06/16/type-level-program...
Annoyed? These are just fun things to do. Just like Quines. Of course anyone trying to introduce type-level computations into production code should be shot on sight (unless you're using a language where type-level "computations" are somehow expected... like Haskell), but that doesn't mean we shouldn't do it just for amusement. Just as the linked article ends: "Match is the only operation that we need for HLists. We’ll continue by defining comparisons, addition, multiplication, modulus, and exponentiation just for fun anyway."
Scala's DSLs are internal DSLs, made through the use of higher order functions, closures and implicit conversions. That's very different from external DSLs, written in a separate language (macros in C and C++). There are also DSLs that straddle the line e.g., C++ templates ("generic meta programming") and Lisp macros (application of Lisp but at a different stage, resulting in new s-exps). That's a big distinction.
Inventing good languages within other languages is a good thing. Just look a Rails. Inventing bad languages, well, bad code is always going to be bad. I disagree that Scala is not better than Java. Any language which adds additional mechanisms to make my life easier as a developer is a good thing.
I'm not sure the article asserted that Scala was "not better" than Java. It was asserting that Scala is not "a better Java"; that is that the design philosophies between the two languages are such that it's not right to treat Scala as an evolutionary "next step" from Java, as some have. I think there's some truth to that point of view.
> Any language which adds additional mechanisms to make my life easier as a developer is a good thing.
What if they make life easier for you but harder for everyone else on your team?
I'm not saying I disagree with your philosophy, just that there is merit in the other side of the argument as well. I want tools to build powerful abstractions, but I want those powerful abstractions to be easy for everyone to read and, when necessary, explore in detail.
There is a productivity valley between small teams (up to 5-8 people) and large teams (20+). In that valley you get less done than on either side, so it makes no sense to be there.
What this means is that organizations need to make a choice between maximizing what can be done with at most 5-8 people, or else making teams of 20+ people work together smoothly. And the sets of features that are good for either of those goals are frequently bad for the other goal.
> There is a productivity valley between small teams (up to 5-8 people) and large teams (20+).
Sorry, but I don't agree with that at all. As soon as you have more than one person working on the same part of your code, you incur some degree of overhead. I don't see why the numbers 8 or 20 are special. Are you really claiming that a competent development team of 18 people cannot do more than a competent development team of 8 people?
To co-ordinate teams of many developers, we divide projects into manageable chunks, each with a relatively small number of developers working on them. This requires good abstraction tools, so that developers can see how their contribution fits into the larger picture, can work with the code written by others without having to know it in intimate detail, and can combine all the components into a complete product. Again, I don't see how this picture differs whether you have 8 people or 20 people, unless you're following some sort of surgical team model where you really are trying to get all of the smaller team working on the same code but most of them aren't actually writing that code at all.
See page 229 in Software Estimation for references to research that a medium size project will be produced in the same number of calendar months by a team of 5-8 people or a team of 20-25 people. And it will take LONGER if your team is between those two sizes. Beyond that larger threshold, development also speeded up.
In this case a medium sized project was 10-100 thousand lines of code, and for all the team sizes looked at across all of the projects examined averaged 50-60 thousand lines. I would expect that the small team likely had less code duplication within their project, which would indicate that when measured by functionality, the small team had an even bigger advantage.
Note that this is calendar months to finish the project. If you measure in terms of dollars spent to finish, the most productive team size is 1.
And yes, this is with the larger teams using standard practices such as being divided into smaller, more focused groups. The reason is that the process of doing that requires completely changing how you work, and that results in a significant productivity impact. Once you take that hit you can scale, but you have to take that hit first.
I'm all for evidence-based debate, but as I don't have that particular book, could you please provide specific citations?
I am willing to accept that I am wrong if the evidence really says I am, but I remain deeply suspicious of these conclusions on the basis of the data you have provided so far. A typical 50-60 KLOC project is the sort of thing I would expect one or two decent developers to put together in less than a year. I don't know why even a team of 8 people would be working on a project that small under most circumstances, never mind a team of 20-25 people. Of course if you go into the low end of the tail then the communications overheads will dominate development time with that sort of team size, but that's hardly typical of a realistic project with a competent development team.
(I keep using qualifiers like "competent", because I don't think this level of performance requires exceptional developers and managers, but I am ruling out clueless management or developers who aren't good enough to function effectively in a team at all. Of course with such people your supervision and communication overheads go through the roof.)
Edit: Never mind. I found the relevant excerpt of the book you mentioned. You are making a completely unfounded generalisation, extrapolating from data taken in a very specific context, with no logical basis whatsoever. I stand by my previous posts.
Why yes, giving you difficult to check XML files as a bad replacement for introspection, decent conventions, and complex class hierarchies (with tons of casts in the middle) to account for absence of features is just so much better.
I mainly know OO through Python. I had a Java programmer try and explain why Dependency Injection frameworks were great and I went off and googled around and there are a few for Python.
I still can't grok why I'd need one though. Is DI for Python the product of damaged minds or do they provide some real benefit?
Even in Python, you benefit from structuring an object to accept its dependencies as inputs, rather than calling to them by their global names. It lets you test each class independently with mock objects that support the same interface.
By writing XML config files? (or is that just a Struts wart rather than an intrinsic part of DI?)
Anyway - if mocking for tests is the major benefit of DI then there some other simpler ways to that. Everything I've read on DI makes it sound like a fairly complex beast.
Java beats Scala, and many other languages, in readability and maintainability. Java has a lot of best-practice conventions developed over many years of pain on how to make the code as readable as possible. The functional languages need these guidelines even more than Java does, but they seem to lack them. It's really easy to write insanely convoluted unreadable code in Scala.
"Java beats Scala, and many other languages, in readability and maintainability."
The readability and maintainability of software isn't only dependent on the complexity of the language, but also on the complexity of the implementation of a concrete problem.
Yes, the language Java is easy to read and maintain, but their frameworks aren't.
You are missing my point: that the language isn't the key part here, its the programmer. If a programmer doesn't adhere to some sane formating and code structure, it won't matter what language they write in, the result will be spaghetti.
No you're missing the point, the point is that the "formatting and code structure" conventions haven't been developed for scala the way they have for java over many years.
Before you jump into Scala I'd recommend being familiar with Java and (at the least) being comfortable with the basics of an ML-like language or Haskell. Having had experience with a scripting language like Ruby or Python helps too.
Knowing Java, Haskell, Ruby, and Python already, I found it really easy to jump into Scala with the references listed on the Scala site. If you do have experience with Java/statically-typed FP (or if you're just feeling brave) that's where I'd recommend looking.
Seems a superficial argument, C++'s features have not been added into Java to create Scala. Even the Java community is pushing Java7 in a direction with richer features, except the language is beginning to get in the way. Generics are not implemented too well, closures are likely to complicate matters further.
That said, it is possible to write code in Scala that requires a PhD in category theory to understand (see Scalaz), but there are also many examples of simple, functional, easy to understand code (see stuff that has come out of Twitter, like Kestrel or Nagatti).
I think in practice, working with the modern Java ecosystem gives one at least as much rope to hang oneself as using Scala does.