Hacker News new | past | comments | ask | show | jobs | submit login
Scala == Effective Java? (grahamhackingscala.blogspot.com)
133 points by fogus on Jan 11, 2011 | hide | past | favorite | 55 comments



It's not that Scala is Effective Java, it's that "Effective Java" (the book) is a good set of patterns of software developments in many other object oriented languages. You'll note much of the same discussed in Design Patterns (unfortunately, in a more rigid and less accessible form) and visible in well written pieces of software in Java, C++ and many other languages. That's why I highly suggest reading Effective Java even if you hate Java the language / Java the culture, the latter symbolized by horridly designed and implemented frameworks like Spring which have turned design patterns into a set of buzzwords to liberally sprinkle.


I agree that the Java culture is significantly poisoned by the 'enterprise architect' culture, but Spring if anything has been the saviour of Java.

Compare IoC (Spring setter injection), with J2EE+EJB2.x - it's night and day - and I know which I would prefer to code using. Spring introduced POJO programming and explicitly called out the crappy J2EE design patterns in favour of simplicity.

Now, Spring has accumulated so much cruft (and become much more commercial with the vmware buyout), that it is becoming the new J2EE.

I've been doing some android programming recently, and working with Java without IoC is simply unbearable.


> Compare IoC (Spring setter injection), with J2EE+EJB2.x - it's night and day - and I know which I would prefer to code using. Spring introduced POJO programming and explicitly called out the crappy J2EE design patterns in favour of simplicity.

Agree. J2EE is an even worse example of "Java the culture". For a much better alternative, see Guice. I personally prefer "it's okay to call new sometimes" Design Pattern to IoC containers (but occasionally I find myself using Guice).


> I've been doing some android programming recently, and working with Java without IoC is simply unbearable.

Can't you use Guice with Android? I'd be surprised if you can't.


I'm looking into Guice + Roboguice (which seems to be the way to go), but I really need to understand Guice semantics first - Guice != Spring and I have a fair bit of 'unlearning' to do


related: Norvig's presentation on how many design patterns are unnecessary in dynamic languages http://norvig.com/design-patterns


Isn't this a bit of an unfair comparison?

Java the language is at least 8 years older than Scala the language. Scala had the benefit of learning from previous language's mistakes.


> Isn't this a bit of an unfair comparison?

No, because it's not like Java was the first language to ponder about these, and it did not learn from previous languages (mistakes or successes). Pretty much all of Scala's improvements over Java predate Java itself by decades.

Java simply refused to learn from previous language's mistakes.

To some extent, C# did as well by starting out as a slightly improved Java instead of an actually good language, which means even with all the improvement they're doing since they're not deprecating and removing old crud the language is now chock-full of crap and far more complex than it could (and used to) be.


> Java simply refused to learn from previous language's mistakes.

You probably never programmed in C++ before. Trust me on that, Java was a breath of fresh air and it was obvious to everyone that it learned a lot from past languages.

> No, because it's not like Java was the first language to ponder about these, and it did not learn from previous languages (mistakes or successes). Pretty much all of Scala's improvements over Java predate Java itself by decades.

Maybe, but if these features had been put in Java in 1995, it's very unlikely it would have met the success it knows today.

Sometimes, the hard part in language design is knowing what feature not to add. Java did great in that respect.

Scala... not so much, if the language complexity is any indication.


You're a little unfair in regards to C#.

Since C# 1.1 they've only added features that are mostly orthogonal to the existing ones. Secondly, the features they've added aren't half-baked. Sure there's room for improvement, but they behave as you expect them to, and the designers specifically leave room for improvement all the time.

Sure, I hate that everything I want to do still has to be specified within a class / static method; that's Java-related legacy done probably because of marketing reasons, but C# has 2 things I wish for whenever I'm working with Scala ...

- the ability to get the expression tree of a closure. There was a plugin for Scala at some point, but it's dead.

- dynamic typing, which structural typing cannot really replace.

You say chock-full of crap, but IMHO language designers should learn from its evolution, because it was a good one.


> Since C# 1.1 they've only added features that are mostly orthogonal to the existing ones

Yes. Like delegates (1.0), anonymous delegates (2.0) and lambdas (3.0). Or `for`, `foreach` and List.ForEach. Orthogonalith, schmortogonality.

> Secondly, the features they've added aren't half-baked.

Though I disagree with your statement (C#'s properties are crummy, its Nullables are half-assed if even that, the collections are a mess, the enumeration suck goats, arrays are covariant, implicit conversions are terrible ideas, extension methods are a half-assing of open classes, tuples are painfully awful, out parameters everywhere is a gigantic joke, and I'm not even actually looking for these things), I didn't state they were half-baked. Me thinks the lady protests too much.

> Sure there's room for improvement, but they behave as you expect them to

Which is irrelevant to the point and completely uninteresting.

> IMHO language designers should learn from its evolution, because it was a good one.

There was nothing good about it. Trying to make a small but crappy language into a good language by accretion is not "good evolution".

edit: let's make this clear: I understand the constraints of the C# team (at least some of them) and I understand they weren't (and aren't) out to create a good language, let alone a revolutionary one. Doesn't mean I have to agree with that.


Delegates (1.0) are types specifying method references, anonymous delegates (2.0) are anonymous code-blocks making usage of delegates, and lambdas (3.0) are just defined delegates with generic variables.

"for" is different than "foreach", and "for" is there because the language being named "C#" it had to have some heritage from C. Also all ForEach methods are built on top of IEnumerable.

I.e. features are built on top of each other.

For the record I think implicit conversions are a great idea, that properties are OK, and extension methods are cleaner than open classes.

Not to mention, there's stuff you can do with extension methods / implicit conversions that you cannot do with open classes (and viceversa).


> Delegates (1.0) are types specifying method references, anonymous delegates (2.0) are anonymous code-blocks making usage of delegates, and lambdas (3.0) are just defined delegates with generic variables.

Delegates are references to code blocks, anonymous delegates are references to code blocks, lambdas are references to code blocks. They're three features which do the same thing, meaning they are not orthogonal (and they could have been build from lambdas up and I'd have said the same thing).

> "for" is different than "foreach"

Yes, one has 3 more letter than the other one. Any usage pattern of `for` can be replicated by `foreach` and the right enumerables, and vice versa. Not only are they not orthogonal, they're fully redundant.

> and "for" is there because the language being named "C#" it had to have some heritage from C. Also all ForEach methods are built on top of IEnumerable.

This is completely irrelevant to my point and absolutely uninteresting.

> I.e. features are built on top of each other.

These features also fundamentally do the same thing i.e. they're not orthogonal. Your original claim was the following:

> Since C# 1.1 they've only added features that are mostly orthogonal to the existing ones

I gave you 4 features which are anything but orthogonal to preexisting features.

> that properties are OK

Goodness gracious, stockholm syndrome much?


You just reminded me to dig thru bookmarks for Skeet's vid and comment threads:

http://news.ycombinator.com/item?id=1942859

http://www.reddit.com/r/programming/comments/ec95s/jon_skeet...


Java learned a ton from previous language's mistakes. The fact that it's ubiquitous, not perfect, has traditionally been slow/judicious to adopt new features (good), and hasn't had a release in the better part of a decade (bad) , amplify the perception of it's flaws.

Compare Java to C++, for example -- the top 5 things that annoy me about C++ are mostly fixed in Java (#ifdef, STL inconsistency, .h and .cpp files for one class, destructors, bounds checking..)


> Java learned a ton from previous language's mistakes

No. It only "learned" from C++'s mistakes, if even that, and threw out the baby with the bathwater (threw out templates but tamer generics as well, threw out non-nullable references, threw out context management — RAII or other)

> The fact that it's ubiquitous, not perfect, has traditionally been slow/judicious to adopt new features (good), and hasn't had a release in the better part of a decade (bad) , amplify the perception of it's flaws.

No, the fact that it's full of flaws that have been criticized from the start does that.

> bounds checking..

Java didn't fix bounds checking, they only fixed the memory unsafety of it, because Java is a GC'd language and therefore memory safe by default.


Well, there's no pleasing some people. I bet Gosling's pretty happy with how it went over the last 15 years, though.

Personally, I think throwing out templates is exactly what should have been done. And Java has generics.

What other lessons were they supposed to learn according to you, exactly?


> Well, there's no pleasing some people. I bet Gosling's pretty happy with how it went over the last 15 years, though.

Sure, if his goal was to create a super popular enterprisey language, to create the son of Cobol and to bring mainstream language improvements to a shrieking halt for a decade, he succeeded admirably on all counts.

> Personally, I think throwing out templates is exactly what should have been done. And Java has generics.

If you can't even be arsed to read what you reply to, I don't think there's any point in me continuing.


If you're just going to make ad hom accusations, there's no way of pleasing you.

I addressed templates, which to the extent I've seen them, are a confusing nightmare. You can say that's because I'm not smart enough, but I'd retort that I don't want to debug something that smart.

Non-nullable references you can make a case for, but but it's minor and you can also say 2 types of references complicates things much more than one type of reference. Java dodges all kinds of confusion by only having one kind. And context management, which is such a relic that I had to google it, seems to be a hack to make memory management easier to deal with. Again, clever, but I'm not sure I want to debug it. How about avoiding static state and dodging the whole problem.

Java has 50 keywords total, including "void" and all primitive types, and it can do almost all of what C++ can. Yes, the OO model is a product of 1995. See smalltalk. EJB is "enterprisey", Java is not. And all organizations, regardless of hipness, need maintainable code.

Anyways, certainly nothing is perfect, so I'd love to hear more thought-out reasons why Java sucks.


I would argue that Java learned a lot from other languages, just not ML or Haskell. Parts of it are heavily based on Smalltalk, Objective-C, C++, Simula, Modula-3, and even Lisp.


> Parts of it are heavily based on Smalltalk, Objective-C, C++, Simula, Modula-3, and even Lisp.

Very small parts, and very badly implemented. Apart from C++ which is definitely the major influence on Java. The rest boils down to "hey smalltalk is object-oriented and java is object-oriented, so java is based on smalltalk amirite?"

And the answer is no.



But it is evolution. isn't it and there be better software for all of us.


Are there any plans to have the Scala compiler emit native code?

An LLVM front-end would make it much more appealing for general use. Perhaps as a sane (?) alternative to C++ in the high performance computing arena.


You'd need a pretty hefty support library to add the JVM-provided features Scala relies on. Garbage collection is obviously a major one, but there are also the pieces of the standard Java libraries that Scala builds on top of (though I'm not sure how deep those dependencies run).

GCJ attempted to do this for straight Java; I don't believe many people consider it a success.


More about his Item 11 on cloning. Writing a case class gives you a "copy" method which is an abstraction of clone where you can write something like

val newFoo = oldFoo.copy(bar = someBar)


I switched from Java to Scala and I'm not looking back.


Does scala have that many third party libraries ala java ? Because these days for web application most of us use Java with Spring or apache commons.


Scala, like most/all languages that run bolted on top of the JVM can use almost all of the libraries that Java itself can use, since the Scala code gets auto-converted to Java classes. (Typically (in the examples I've seen) one Scala class gets converted into many Java classes)

This is not entirely dissimilar from the way that JSP gets converted into a Servlet.

Scala/AlternateLanguageRunningOnJVM fans please provide corrections as appropriate, but be gentle, I'm making some broad generalisations here with all the flaws implied by that methodology. :D


There maybe exceptions to the 'you can use all Java libraries' at runtime. I'm unable to use a Scala class annotated with JPA annotations with Eclipselink. The same class works fine with Hibernate.


Yes. Anything you can use from within Java, you can use from within Scala. I'm quite happily using JGroups and Netty from within Scala. The code actually looks a hell of a lot better than the equivalent Java versions.


Anything you can use in Java is available in Scala.


Although stuff that relies heavily on reflection and runtime code generation tends to be tricky. Class files generated by the scala compiler may look different from class files generated by javac and contain additional data (while of course still being valid java bytecode), and some tools rely on accidental details of the javac code generator. Someone mentioned JPA in this discussion. But most things just work.

Another issue is using scala code from java. As long as the code implements a plain java interface, everything is fine, but if you try to use something impemented with some of the features that java doesn't have, you will soon see some very stange mangled names. trö_%¿ is not a valid java fuction name, after all.


What about annotations?


You can use them too.


I thought one of the premises of Scala was that you could use all of the Java libraries as well?


It is, and you can.


As many other replies pointed out, the answer is most definitely 'yes'.

You can easily use any Java libraries from Scala and Scala provides a number of tools including JavaConversions and JavaConverters to automatically convert to and from Scala and Java collection objects for easy interop.


What is up with the dodgy numbering? I hope he didn't get a Scala program to do the list!!!

I am always deeply suspicious of any appeal for using a language that uses as it's initial premise that the language is shorter or saves keystrokes.

Personally, I'd take one of his examples and make it 'worserer' by enbiggening it.

  new RunningReporter();

  public class RunningReporter extends Thread {
    public void run() {
      System.out.println("Running");
    }
  }
And then I'd redesign it to something useful, e.g.

  public class RunningReporter extends Thread {
    public void run() {
      System.out.println("Running");
      doSomething();
    }
    public void doSomething() {}
  }
So then subclasses of running reporter would spit out Running to System.out.println and then go and do their funky thing.

But even that isn't as useful as it could be, it should really be something like:

  public class RunningReporter extends Thread {
    String message = "";
    public RunningReporter(String s) {
      super();
      message = s;
    }
    public void run() {
      System.out.println(message);
      doSomething();
    }
    public void doSomething() {}
  }
Okay, so now you can customise the message, so that you can tell these threads apart if you're doing stuff:

e.g.

  new BluetoothRunningReporter("Spp fix"); 
So we've passed through shorter, and gotten bigger, but the line that would be used in the program conveys enormously much more information.

I find that upon examination, in a properly and well designed Java system almost all of the anonymity disappears... which makes me uncomfortable with that example of how Scala is better than Java, because in the real world, if you were doing it properly, you wouldn't do it that way in Java anyway.


The numbering is based on the "Tip" Numbers from the Effective Java book. Each tip is numbered and indexed, and it is common to use the tips during code reviews.


I'm not sure if I'm following your point. Are you suggesting that anonymous inner classes aren't useful in a well-designed Java program? If so, I'd have to disagree.

As an example, the Java Collections API (one of the most well-designed Java APIs, imho) uses Comparators extensively. It's pretty common to define the Comparator as an anonymous inner class when you need to do a one-off sort() or max() call.

Scala just makes it easier to use this pattern. There's no need to go through the effort of wrapping the function in class if you're only going to use it once.


Shouldn't the headline here be Scala.compareTo(Java)?


Or: Scala compareTo Java ? :)


I'm not familiar with Scala but I don't understand how it could eliminate the need for Item 14: Use public accessors methods rather than public fields. The point of using accessor methods is so that you can change the underlying implementation if necessary. If the getters and setters are compiled automatically for you it doesn't seem like you'll be able to change the underlying implementation without also changing the types of the methods.


Here's how it works. When I say:

  class Kitty {
    val purrVolume: Int;
  }
What Scala actually produces in Java bytecodes is something like this Java equivalent:

  public class Kitty {
    private int purrVolume;
    public void setPurrVolume(int purrVolume) {
      this.purrVolume = purrVolume;
    }
    public int getPurrVolume() { return purrVolume; }
  }
Later, if you decide that you need to change it to do some special calculations in the getters and setters, you can add that to the Scala code. External users of the class will not need to be recompiled, because under the covers Scala was never actually exposing the public member variable.


I think you mean var, not val.

If you were using val you would do:

  class Kitty(val purrVolue: Int)
which would turn out to be in Java:

  public class Kitty {
    private final int purrVolume;
    public Kitty(final int purrVolume) {
       this.purrVolume = purrVolume;
    }
    public int getPurrVolume() { return purrVolume; }
  }


On the Java version you forgot equals() and hashcode(). Scala's case classes give you that for free.


> If the getters and setters are compiled automatically for you it doesn't seem like you'll be able to change the underlying implementation without also changing the types of the methods.

You can trivially replace the auto-generated methods by manually crafted ones, keeping the same types (since they're a direct consequence of the original object's type: a String member will have an accessor of type `() => String` and one of type `String => ()`). If the compiler sees the "public" member already has accessors defined, it doesn't generate them. Could hardly be simpler.


It looks like Groovy satisfies many of these checklist items too. Any reason beyond personal preference to go with Scala vs Groovy or JRuby?


Speed. Scala beats both Groovy and JRuby pretty handily.


groovy++ seems to beat scala, at least in some tests:

http://groovy.dzone.com/articles/why-scala-actors-15-20-time...


I used Scala for some small projects. I absolutely loved much of it, although I found I got caught up in experimenting with syntax to learn "better" ways to the point of distraction.

These days I use mostly ruby and have started on node.js. Ruby programmers don't seem to understand the importance of encapsulation and typing, which is quite frustrating and leads to much head banging. I yearn for the day Scala or something similar is broadly adopted.

Interestingly, many of the best features of scala mentioned here are veey new to the language. Named parameters and built in copy for case classes were not available until a year ago. It's great to see a language implementing prudent improvements quickly - here's looking at you Java.


Ruby programmers don't seem to understand the importance of encapsulation and typing

Interesting juxtaposition. I wonder if it's a concrete benefit of static typing to make you more aware of encapsulation: that does resonate with my experience. Because functions and object methods have to have types that fit together, you're forced to think about what goes into and comes out of a given component, so you're thinking about component boundaries more often.

I know when writing a Ruby method it's all too easy to just return the first intermediate result that makes sense, subconsciously thinking "let the caller process this result, and if it's messy I'll refactor it later". In Java, I have to write the return type and also return something, and if I planned to return an Iterable<String> but I'm tempted to return a List<Object>, the redundancy catches me out. I have to consciously make the decision: should I change the contract of this method by changing the return type, or should I instead massage the results into the form I planned to return?

(I think the same holds for Scala, where I might not have to write the return type because it's inferred: if anything actually calls my method, the compiler will still remind me that the assumptions made at the call site don't line up with the assumptions made in the method. In Ruby, although I'll still have to change the caller if I change the return type, I'm more likely to do it mechanically, in a "I changed that so I have to change this" mindset, rather than stepping back a level and thinking "which one of these is actually right?".)


You are largely correct about Ruby I think, although it's broader than that. Functional programming is popular because mutable data is a major cause of bugs, is hard to debug, and creates unnecessary complication. In Ruby, all data INCLUDING the executable code itself, is mutable and regularly mutated. Integration and extension, including throughout the Rails codebase, is accomplished by changing object prototypes. This means that you can never rely on an object behaving in a certain way or following a certain code path, and your code or any third party code can easily be broken by a single line of rouge code from a library - and yes this happens often.

Regarding Scala, I don't think type inference means that you stop thinking about types, particularly when writing in a functional style where the returned value is the only thing that matters.


Regarding Scala, I don't think type inference means that you stop thinking about types

I didn't mean to imply that it did - quite the opposite in fact (that even if you didn't write the type, you'd still be encouraged to think about it, because of the compile-time checking).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: