
Scala == Effective Java? - fogus
http://grahamhackingscala.blogspot.com/2011/01/does-scala-equal-effective-java-bloch.html?utm_source=twitterfeed&utm_medium=twitter&utm_campaign=Feed%3A+blogspot%2Fvnby+%28Graham+Hacking+Scala%29
======
strlen
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.

~~~
foamdino
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.

~~~
strlen
> 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.

~~~
foamdino
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

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

------
brown9-2
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.

~~~
masklinn
> 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.

~~~
bad_user
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.

~~~
masklinn
> 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.

~~~
bad_user
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).

~~~
masklinn
> 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?

------
nimrody
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.

~~~
jonburs
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.

------
joshhart
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)

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

------
thisisananth
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.

~~~
stonemetal
Anything you can use in Java is available in Scala.

~~~
Stormbringer
What about annotations?

~~~
wheaties
You can use them too.

------
Stormbringer
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.

~~~
hamletdrc2
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.

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

~~~
weavejester
Or: Scala compareTo Java ? :)

------
guelo
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.

~~~
unoti
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.

~~~
pretzel
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; }
      }

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

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

~~~
rufugee
Speed. Scala beats both Groovy and JRuby pretty handily.

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

[http://groovy.dzone.com/articles/why-scala-
actors-15-20-time...](http://groovy.dzone.com/articles/why-scala-
actors-15-20-times)

------
aneth
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.

~~~
samstokes
_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?".)

~~~
aneth
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.

~~~
samstokes
_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).

