Yann Moisan

Scala, Web, Linux…

Scala Puzzles

Quelques petites bizarreries ou astuces, issues de mon expérience. Je vous encourage à réfléchir un peu avant de tester dans le REPL. Et j'en profite pour vous donner une petite astuce que je viens de découvrir : :paste permet de coller plusieurs lignes dans le REPL.

Division par zéro

Commençons par une venant de Java :
0/0
0d/0

Qu'affichent ces deux lignes ?

La première ligne lève une java.lang.ArithmeticException alors que la deuxième affiche NaN. Cela peut paraitre étrange mais c'est conforme au standard IEEE 754 pour la représentation des nombres à virgule flottante. NaN est le résultat d'une opération invalide.

Pattern matching

Considérons la méthode suivante :

def f(a: Any) = a match {
  case ints: List[Int]    => println("int")
  case strs: List[String] => println("string")
}

Qu'affiche le code suivant ?

f(List(42))
f(List("scala.io"))

Les deux lignes affichent int. Le pattern matching est fait à l'exécution, l'information de type n'est donc plus disponible en raison du type erasure de la JVM.

Pattern matching

case class A(x: Int, y: Int)
def f: A => Int = { a => a.x + a.y }
def g: A => Int = { case A(x, y) => x + y }

Qu'affiche le code suivant ?

f(A(21, 21))
g(A(21, 21))

Même si la syntaxe de la deuxième méthode est surprenante, les deux méthodes sont équivalentes. Scala permet d'utiliser le pattern matching, et donc la déstructuration pour les paramètres d'entrée d'une fonction anonyme.

Un pattern courant

object Action { def apply(f: String => Int) = { s: String => println("s = " + f(s)) } }
val f = Action { _.length }
val g = Action { _.toInt }

Qu'affiche le code suivant ?

f("42")
g("42")

Cette astuce combine l'appel implicite de la méthode apply du companion object, qui est une HOF car elle retourne une méthode. Cela permet d'implémenter élégamment le design pattern Template method.

Collection

Que renvoie le code suivant ?

Array(42) == new Array(42)

Et oui, cela renvoie false. A gauche, cela appelle la méthode apply du companion object de Array, qui créé un Array[Int] avec un seul élément. A droite, ça appelle le constructeur de Array qui créé un tableau de taille 42.

Collection

Que font ces deux lignes ?

val l : List[Any] = List[Int]()
val a : Array[Any] = Array[Int]()

La première ligne ne pose pas de problème. En revanche, la deuxième ligne ne compile pas car le type Array est invariant.

PS: Les plus attentifs auront surement remarqué une publicité subliminale.