I think this illustrates the author's point that languages structure our thinking. The value of a King as 13 and the Queen as 12 is determined by the rules of the card game, not the number of elements displayed on its face as is the case for the non-face cards - e.g. the face cards all have a value of 10 in blackjack.
Some languages better allow for the messy details of the world and allow the programmer to treat the partial and occasional isomorphism between names of and the values assigned to cards in a particular context uncomplected.
None of which is to say that strong static typing does not offer a particular set of advantages, only to suggest that it can become forced at a certain level of abstraction where real world objects are represented without a specific context for interpretation.
Imagine a program which begins by asking, "Which game do you want to play?" and includes a card guessing game, blackjack, Uno!, go fish, and crazy eights. We want the values of the cards to lie in their use within each game, not where we shuffle and deal and discard from hands.
I maintain that you gain nothing (except the possibility of errors) by representing the cards as int-or-string here. Think about how you'd actually use the cards in implementing those games. With my enum-like scala representation you could do anything you could do with the clojure version, and you'd get the advantage of e.g. compiler warnings if you defined incomplete match/case statements.
And this is the really important point, this pushing the abstraction down to a lower level causes it to leak into the implementation of card games in ways that make the card games themselves harder to reason about.
Decks of cards have Kings, not 13's, and using 13 to represent the King is of type leaky abstraction. It's a muddy road leading into the swamp.
When I implement blackjack I get to write little balls of mud:
If card = 13 then 10
And in my card guessing game If card = 13 and guess = King then "Yes, the card is a King!"
All that for a warning when I don't have a card 7, which is going to make Pinochle have to work around the abstraction - probably by bypassing the entire implementation when it chokes on two Jacks of Diamonds etc. in a deck.There's no value to a warning that's irrelevant and perhaps even negative value if it encourages the idea of adding a wildcard last case just so I don't have it interrupting my thoughts each and every time I build my program since doing so opens the door to very run time errors it was supposed to prevent or conversely creates the habit of ignoring the compiler warnings in the very worst situation - when I think I know what I am doing.
If enums were good enough and I wanted to ignore compiler warnings, I could have used C.
What? No it doesn't. Scala case objects don't have numerical values.
I have serious doubts about this since practically everything in the Scala standard library is horribly broken (collections, views, everything in scala.io, scala.xml and scala.actors etc.). The number of bugs found by Paul Phillips alone is absolutely ludicrous.
As it stands now, both Haskell and Clojure have vastly superior libraries, build systems that actually work, and implementations that people actually understand and can modify.
Paul has definitely found a lot of "bugs", he has certainly contributed a huge amount to the cleanliness of the code base, and has been a big pusher for removing certain levels of unsoundness in the type system, but if you were looking for bug-finders + fixers, Simon Ochsenreither is probably a better bet.
Foldable, Traversable, Monoid etc. are all far better abstractions than what Scala collections provide, and they don't lead to unmanageable inheritance hierarchies and ridiculous APIs. How many bugs have been caused by that? A few hundred maybe? Does Set equality work in the current release or is that broken again? Is it possible to do thread safe efficient merges in immutable collections yet?
The only thing Scala collections offers that Haskell doesn't is the CanBuildFrom travesty. At least in Clojure you can chain transformations together without generating tons of intermediate values. In Scala you're forced to choose between being ridiculously inefficient or using iterators.
(It seems like you've got interesting things to say, but you're being a bit strident. It bums me out that Scala discussions on HN take such a heated tone.)
In the rare cases where you actually need to convert between collection types, it's usually trivial and more efficient to do it manually. Essentially they've added tons of complexity for negligible benefit. One of my main gripes with the Scala collections library is that it's overly complex and that this complexity has been the source of hundreds of bugs.
If there was any real benefit to the way it's currently done they wouldn't be hiding the true type signature for things like `List.map` in the official Scaladocs.
Additionally, it seems that moving from lists to a different collection type still involves rewriting your whole code due to the insane idea of using different functions by default (fmap/map, mempty/[], mappend/++).
I just don't have to deal with any of these design mistakes in Scala. Having sane defaults and stuff that "just works" consistently are a huge benefit.
I can't even imagine what you are talking about, so I can't say if they "fixed it" or not.
>Additionally, it seems that moving from lists to a different collection type still involves rewriting your whole code due to the insane idea of using different functions by default
"I did something dumb and now I don't like it". So, don't do it? Why were you using map in the first place?
>I just don't have to deal with any of these design mistakes in Scala
I don't have to deal with them in haskell either. But I do have to deal with the hundreds of other mistakes scala made if I use it.
Maybe I'm feeding a troll here, but I've been building production software for over 4 years using SBT. It works.
> Akka actors (which are awesome, BTW).
PartialFunction[Any, Unit]. Ridiculous.
That's bad?
As for the PartialFunction[Any, Unit] comment: well, yeah. That's the way actors work. They can be sent any message but may or may not respond. The company I work for has a very large Akka-based backend and that has honestly never been an issue for us. Moreover, it's necessary to facilitate hop-swapping (changing an actor's behavior dynamically during runtime). That is most certainly not a feature I would be willing to sacrifice. "context.become" is an incredibly powerful tool within Akka, especially in how it makes modeling a finite-state machine quite trivial in practice.
We use the FSM helper [1] heavily in our backend at Conspire. For data-pipeline use cases, it's invaluable. Keeps our code concise, readable and testable. Even basic become/unbecome operations are big for us, I've written up one of their use cases on our blog [2].
[1] http://doc.akka.io/docs/akka/2.2.3/scala/fsm.html
[2] http://blog.goconspire.com/post/64901258135/akka-at-conspire...
Suits would surely be case objects rather than classes, or I'd be tempted to just use a Java enum (Scala could really do with an equivalent). With card ranks, either you want to be able to compare them - in which case integers are the correct representation - or they're just 13 "things", in which case again an enum-like representation is good; I can't imagine why you'd ever want to represent a card rank as int-or-string.
Case classes are java-serializable by default. Any number of other serializers (json, database...) exist that work seamlessly with case classes. I do think it would be nice to have an abstraction for something weaker than a class, something that was guaranteed to be inert data, but still typed.
And yeah, I might implement a deck as something that contains a sequence. But I could then derive typeclasses for sequence operations quite cheaply using lenses. (I do wish there was a nicer way of doing this kind of delegation though).
Sure, Scala steers you towards making a type straightjacket for yourself; you definitely can operate on stringly typed or maply typed data, as it sounds like Clojure encourages you to do all the time. And maybe it's not the best language for exploratory manipulation of semi-structured data. But when the time comes to write a production-ready system, the strong types that Scala gives you are a much faster way to achieve the level of reliability you need than the level of testing you need in a less typed language.
(And even if you don't need the safety, I find types are a great aid to figuring out WTF you were doing if you come back to the code in six months' time)