Hacker News new | ask | show | jobs
by jvandenbroeck 5194 days ago
On a serious note, is anything true from the post - if so, what parts? I find the post funny but, I've started to learn Scala (I think it has some pretty awesome features!) but if some of it is true, I might cancel my Scala-learning mission.. :p
7 comments

Scala is awesome–you should definitely learn it.

Scala does provide you with enough rope to hang yourself with. What's the solution to this? A. Don't hang yourself. New Scala shops should definitely abide by the style guide that is provided at scala-lang.org to help with this.

Also, use implicits and multiple inheritance very judiciously. One thing that is quite true from the OP, is that the "cake pattern" is indeed "the bakery of doom". If you have to use dependency injection, use something sane, like Guice. Or just ol' constructor injection.

My only big gripe with Scala is that OO syntax is a blight on the world. They should have provided multi-methods instead, so everything could be done with functional syntax.

>My only big gripe with Scala is that OO syntax is a blight on the world. They should have provided multi-methods instead, so everything could be done with functional syntax.

I actually disagree. Functional syntax means that you need to start using qualified names or polluting your namespace (think of module/import usage in Python, but without OOP dot-notation). I like being able to say:

    val herp: Option[Derp] = hurr()
    herp.getOrElse(Darpity)
Leaving aside the awful metasyntactic variables, the `getOrElse` method could exist on any number of classes (stuff like `map` sure does!), but I never have to use a qualified name to get the right one. I use dot-notation on the object itself to qualify the method name.
Do you find that's a problem with CLOS or Clojure multimethods? Because I never noticed much of what you seem to be talking about.
As I said above, think about a method like map.

    map :: [a] -> (a -> b) -> [b]
Well, actually, any functor has a map method, by definition! So we'd have to write a type-class:

    class Functor f where
      fmap :: f a -> (a -> b) -> f b
Now how would we represent this as a generic function?

    method fmap<a,b>(as: Functor<a>,f: a -> b): Functor<b>
And then implement specialized methods for each actual functor?

    override fmap<a,b>(as: List<a>,f: a -> b): List<b>
Now everything involving functors performs a dynamic dispatch and might lose type information at its call-site, and we now have to deal with Functor<a> being some kind of superclass, a superclass without data slots of its own just to accommodate our need for this "interface".

In Scala, rather than doing that, we would just define Functor[A] as a trait:

    trait Functor[A] self => {
      def map[B](f: A => B): self[A]
    }
And now every time I call the map method on a Scala object, it statically dispatches via dot-notation. So my compiler knows that calling map on a List[A] gives me back a List[B], and that calling map on an Option[A] gives me back an Option[B], and I didn't need any implicits to get it done.
I do not see why your worries cannot be addressed. In fact, IIRC (it's been a while), the programming language Cecil does just that.

http://www.cs.washington.edu/research/projects/cecil/www/cec...

Well, let me take a deeper look at the material. I've based most of my own language work on multimethod systems like those of Cecil, but there's a few things I immediately see on the page:

* Cecil divides its type system from its object-inheritance-overriding system. Huh?

* Cecil is dynamically typed with static sprinkles on top. So we have dynamic vtables, and also F-bounded polymorphism.

* Methods are referred to as being attached to objects, even though they are multimethods. This appears to imply asymmetric multimethods. Again, huh? What a strange design decision to make!

* Cecil offers nothing for dealing with ad-hoc polymorphism (ie: operator overloading). Admittedly, when Cecil was published, type-classes didn't even exist yet.

think of module/import usage in Python, but without OOP dot-notation

I don't find that to be a problem. In fact, I love Python's module and import system. And the worst thing about Python is it's OO dot notation. I wish that Python had multi-methods too, and no OO-style method calls.

So instead of writing herp.getOrElse(Darpity) you'd write getOrElse(herp, Darpity)

Polymorphism doesn't need to be tied to the first argument's type, it can depend on any number of properties of any number of arguments (see CL's and Clojure's multimethods).

I'm not talking about polymorphism at all. I'm just talking about namespacing, name look-up for the method. Think of a world in which any number of classes might have a `getOrElse()` method, and they don't all do the same thing (so they're not just all methods of a single generic function). Now, how does the compiler know which one you're calling?

We could use some form of static overload resolution (like type-classes). However, it really does seem (to me) to be easier to just resolve the static overload based on the static type of the first argument, and then throw the rest of the overloading problems at dynamic dispatch.

When you think of a class as both a type and a module, it gets clearer. Many classes in the Scala collections library have a `map()` method. We could code `map()` as a single, universal generic function that dynamically dispatches on its first argument type... but nobody ever cared to override map as a virtual method anyway and that doesn't give us a consistent return-type at all. All we really want to say is that calling map over a `[a]` with a function `a -> b` returns a `[b]`.

So, what you're saying is that we all of parametric polymorphism, ad hoc polymorphism, and subtype polymorphism, right?

You'll get no argument from me, but that doesn't mean that there should be an unfortunate syntactic distinction between the three.

The above should read, "So, what you're saying is that we need all of [...]".

Sorry about that!

I'm saying, what happens if more than one module provides a getOrElse() method?

In "classical" OOP, the type of the "dotted" parameter, the this pointer, the method receiver, tells the compiler to look in its own module/namespace for the method name.

If we just write getOrElse(herp,Darpity), then we now have to either make getOrElse a type-class method (type-classes are equivalent to certain usages of modules) to recover the same functionality of looking up the appropriate method, or we have to write herpModule::getOrElse(herp,Darpity).

I enjoy Scala but I would say there is truth to 3 (phantom menace). Although tool support has improved markedly over the last couple of years I still get cases where the IDE is complaining about an error and I go nuts trying to fix it only to give up, run it anyway, and have the error just disappear.

If you spend too much time reading Scala blogs, you may get the impression that 6 (the type babel) is how many people write scala. A lot Scala bloggers like to write articles that exploit or examine clever aspects of the type system but it can be pretty impenetrable at times. At least to a blub like me.

Scala is definitely worthwhile learning, particularly if you're coming from a Java background. If you're using it as a "better" Java it can make your code much more succinct through type inference, pattern matching, traits etc and short code is usually easier to understand and debug. It's also a great way to start learning about functional programming since Scala supports both imperative and function programming styles.

The things to be careful of are the advanced features such as implicit conversions, they seem like a great feature and in a small code base they work great. But if your code base grows at all it can be next to impossible to be sure what your code is going to do.

Not trying to repeat a cliche but as with most things, "With great power comes great responsibility," and Scala gives you a lot of power but it also puts the onus on you to know how and when to use it.

Scala is definitely worth learning. Learned it as a (much) better Java and have never looked back.
One thing is true: implicits. Do not let new scalable programmers use them. When used with type classes, magic. When used as "helper" or "convenience" convertions, disaster.
Pretty much. I've honestly never seen why implicit conversions are even in the language, but implicit parameters are a godsend. They're type-classes done right for an OOP language.
Its an April Fools joke.

3) was true until a few months ago. Or maybe its because I switched from a remote source repo mounted via Samba to a local flash HDD :-) I have been using Eclipse trouble free for a few months now, no issues whatsoever, except for some magic required during the initial maven setup.

4) Is an issue Scala outsiders complain about, but I have never seen this as an issue with people actually using Scala.

Build times are high compared to Java projects, though this could simply be because I am using scalac instead of fsc to build projects via maven. However, compilaton is incremental, so crazy build times should never occur in practice and the IDE highlights mistakes in less than a second.

For all means — learn the language — you can only profit from it whether you decide to use it or not.

In my experience, the language is built by people who really want to make things work. They do all the painful work to make even the most exotic corner cases work as people would expect it. So developers can be confident that the language doesn't break down suddenly, like when you overuse Generics in Java and just hit the wall where the compiler decides that it won't let you do that for no good reason.

The best thing about Scala imho is that they deliver. People are constructive and when valid issues are brought up, they will be fixed. (Better IDE support, more documentation, faster compilation, smaller standard library, better performance ...)