The example cited here is insulting to everyone's intelligence:
The possibility of representing face cards with a name would likely never occur to you, because it would be too complicated to go through the effort of defining the type of a rank to be a "integer or a class comprised of four case classes -- jack,queen,king,ace".
I'm sure every competent Scala developer will see that the equivalent in Clojure can be done with val King = 13; val Queen = 12; ..., which also means you get ordering for free as you're not mixing ints and keywords.
I do agree with the author's point that Clojure almost forces you to adopt a simpler design, but I feel that long-term maintainability requires a delicate balance of simplicity and structure that can be achieved with Scala, but takes more self-control with Clojure.
Using val King = 13; val Queen = 12; in Scala is not equivalent with using Clojure keywords, as their printed variant will be 13 and 12, not :king and :queen. Reading debugging output or logs would force you to manually convert those values.
Ordering for free is valuable, I guess, but it sort of depends on the situation. Sometimes face cards are worth 10, other times they are worth 11, 12, 13. If you use val King = 10;, then it suddenly is impossible to distinguish between face cards and tens.
Right, if you wanted to have an ordering around, you would use an enum. The enum's values would print as Ace, 2, 3, 4, ..., Jack, Queen, King, and then when you wanted to implement a particular game the game could define the mapping from rank -> set of possible values. You wouldn't want to map each rank to a single value, since in commonly played games aces are worth both 1 and 11 or both 1 and 14.
If you didn't want the ordering (or the compiler warning when your blackjack implementation omits queens), you could use Scala's symbols, which are more or less the same as Clojure's keywords:
No, your first sentence is wrong. The following definition stores the ranks as unboxed integers, but prints them differently:
case class Rank private (val rank : Int) extends AnyVal {
override def toString() = {
rank match {
case 1 => "A"
case 11 => "J"
case 12 => "Q"
case 13 => "K"
case _ => rank.toString()
}
}
}
object Rank {
val Ace = Rank(1)
val Two = Rank(2)
// ...
val King = Rank(13)
}
I do agree with the author's point that Clojure almost forces you to adopt a simpler design, but I feel that long-term maintainability requires a delicate balance of simplicity and structure that can be achieved with Scala, but takes more self-control with Clojure.