I'll give an example of the power of Scala's type system. When I first convinced one of our founders to give Scala a try, he used it to write the first pass of our analytics service. He'd never written Scala before but once it compiled, it ran correctly on the first try, that's the power of its type system.
I mean mistakes can happen and if the type system can catch it for free, so to speak, that is great. I'm not about to argue that it is completely useless. But in terms of probabilities of what kind of bugs might be introduced, type errors seem to be on the low end.
To infer that Scala's type system is powerful enough to catch the more common types of mistakes programmers make, that is quite an impressive claim. I am curious to know more.
A more complicated example. In one scala system I worked on we had a master/slave postgres db system. We were replacing a legacy RoR system with a Scala system, and in the RoR system there were all sorts of data inconsistency errors caused by people writing to master and reading from the slaves before replication occurred.
In the Scala system which replaced it, we set up a monadic action system. A function which hit the database would have a type signature either PReader[T] or PWriter[T] - this was the only way to access a java.sql.Connection short of manually calling jdbc. Combining the two forms yields a PWriter:
for {
_ <- putObjectToDB(args)
obj <- getObjectFromDB(args)
yield (render(obj)) // is a PWriter[_]
The whole operation runs in a single transaction against the correct database, and any attempt to do the wrong thing is a compile error.(Though of course there is an escape hatch, you can use RawHeader(name, value) if you need to).
However, that is not really what's going on... though Scala type system, even without dependent types, is strictly more powerful that Java's, it really comes down to the ease of use: Scala programmers tend to use types liberally (which was one of the criticisms of the article), and that is part of the "magic".
Part of this is how easy it is to define a type: it can be as short as a single line. So you'll see way less String types in Scala, for instance, or "one type to do it all" like the article wanted for HTTP. Instead, you get many types, in which invalid states are not possible and, therefore, getting the types right is enough to ensure there are no invalid states.
Likewise, the partial type inference offered by Scala makes it possible to not worry about all these types: the compiler knows what type you got, and knows whether it can be used the way you are using it, so you don't have to keep looking up types to get things accomplished, but still get to have the types.
Another part is that Scala support higher order types, something not supported by Java, which makes them more useful. That's what allows monads & companions come in and make an appearance -- it's not that you can't write a monad in Java, it's just that you can't abstract over them.
The final part is emphasis on immutability. When you stick to immutable objects representing valid states, the space for errors not caught by the type system is greatly reduced.
Let's get back to the headers, then. First, yes, you are allowed to add arbitrary headers (which is supported by Spray through RawHeader, something it took me 30 seconds to find out, even though I have never used Spray and have little familiarity with it), but section 14 of RFC 2616 has a nice list of standard headers and the rules they are expected to abide by, so let's have them.
And if you have a header, and it is a X-Forwarded-For, isn't it reasonable to expect the value to be a valid remote address? It is supposed to be a valid remote address, after all. So, if you ask for this header, should you simply get a string that may or may not be actually valid, or should the type system give you an Option that may contain Some valid header, or None, therefore ensuring that you don't just assume you are getting the right thing? And if you get something and retrieve the value, is it preferable to just get a string, that might lead to some ad hoc parsing of the address, or some actual type where you can easily retrieve information in a safe manner?
The Scala community will usually think that yes, that's a good idea, and design the APIs accordingly.
There's some evidence from what the author wrote he's aware of the benefits of type systems. The question he raises is whether the developers who wrote Spray modeled the problem domain well by choosing this particular set of types (his opinion is clearly no).
> the author makes a strange comment that H-M 'enabled' Monads, and the comment is written in a way that implies that Scala does not have Monads.
Given that the author immediately follows his "enabled" statement with the idea that monads can be used in a type-free language, I think it's most likely he means that H-M has been the ground where the use of monads has been largely developed/defined, not that monads can't be used in either Scala or even something with a considerably less expressive type system.
I think because it allows you to do OOP and FP, Scala becomes difficult since it is so easy to mix the styles. Similar to C and C++, this is very powerful, but also very dangerous. The main learning curve is programming in a way so you don't shoot yourself in the foot while using its flexibility.
Coming to Scala from experience including C, Java and Haskell, I intially found Scala quite difficult. It is true that there are some things in Scala that are not obvious to newcomers, and that are difficult to discover for yourself - such as the use of Implicits, and the strange precedence and binding rules for operator syntax.
That said, it doesn't take long to learn, and once you do, it all makes sense. There are other great languages out there (I'd say Haskell is one), but compared to for example Java, or one of the dynamically typed languages, Scala is superb.
Types, whilst not having the full H-M inference, are brilliant. That the author complains about having types rather than a simple map for keys shows a misunderstanding of what they are there for - the idea is to allow the compiler to prove at run-time what is valid code and what isn't. He comments that tests run too slowly in Scala (they don't - for our production systems building in SBT, a typical test run is significantly less than 10 seconds) but a lot of the time I don't even need to go that far - my IDE already highlights errors in the code as I type, where I have passed in incorrect or insufficient data.
Also, the author makes a strange comment that H-M 'enabled' Monads, and the comment is written in a way that implies that Scala does not have Monads. This is incorrect. Scala has monads, and the Scalaz library has huge support for Monadic programming. We use Monads and Applicative Functors (a close relative) daily to build high level abstractions, and we couldn't live without them. In Scala we say flatMap rather than bind (or >>=), but we mean the same thing. Although thanks to the same flexible method naming that the author complains about, you can in fact say >>= if you wish.
If you've only got a couple of days to use a language, and you're using it for a tiny project, then Scala is not for you. If want to learn a language that can make you vastly more productive whilst at the same time making your code safer and more robust, Scala is a very effective candidate. It's not the only candidate, but you should at least consider it.