Quelles sont les plus grandes différences entre Scala 2.8 et Scala 2.7?

J’ai écrit un programme assez volumineux dans Scala 2.7.5, et j’attends maintenant avec impatience la version 2.8. Mais je suis curieux de savoir comment ce grand saut dans l’évolution de Scala va m’affecter.

Quelles seront les plus grandes différences entre ces deux versions de Scala? Et peut-être le plus important:

  • Devrais-je réécrire quelque chose?
  • Est-ce que je veux réécrire quelque chose simplement pour profiter d’une nouvelle fonctionnalité intéressante?
  • Quelles sont exactement les nouvelles fonctionnalités de Scala 2.8 en général?

Vous pouvez trouver ici un aperçu de la nouvelle fonctionnalité de Scala2.8 (avril 2009), complétée par les articles récents (juin 2009).

  • Arguments nommés et par défaut
  • Annotations nestedes
  • Objets du package
  • @spécialisé
  • Collections améliorées (certaines réécritures pourraient être nécessaires ici)
  • REPL aura la complétion de commande (plus sur cela et d’autres astuces dans cet article )
  • Nouvelles abstractions de contrôle (suite ou interruption)
  • Améliorations (wrapper Swing, performances, …)

“Réécrire le code” n’est pas une obligation (sauf pour certaines collections améliorées), mais certaines fonctionnalités comme la continuation ( Wikipedia : une représentation abstraite de l’état de contrôle ou le “rest du calcul” ou “rest du code à exécuter) “) peut vous donner de nouvelles idées. Une bonne introduction est trouvée ici , écrite par Daniel (qui a également posté une réponse beaucoup plus détaillée et spécifique dans ce sujet).

Note: Scala sur Netbeans semble fonctionner avec un build de nuit 2.8 (vs. la page officielle pour 2.7.x )

Prendre le saut

Lorsque vous migrez, le compilateur peut vous fournir des filets de sécurité.

  1. Comstackz votre ancien code avec 2.7.7 avec -deprecation et suivez les recommandations de tous les avertissements de dépréciation.
  2. Mettez à jour votre code pour utiliser des packages non nesteds. Cela peut être fait mécaniquement en exécutant à plusieurs resockets ce remplacement de recherche par expression régulière.

     s/^(package com.example.project.*)\.(\w+)/$1\npackage $2/g 
  3. Comstackr avec le compilateur 2.8.0, en utilisant les options de ligne de commande paranoïaques -deprecation -Xmigration -Xcheckinit -Xssortingct-warnings -Xwarninit

  4. Si vous recevez des erreurs, l’erreur could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T] , vous devez append un paramètre implicite (ou, de manière équivalente, une liaison de contexte) sur un paramètre de type.

    Avant:

     scala> def listToArray[T](ls: List[T]): Array[T] = ls.toArray :5: error: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T] def listToArray[T](ls: List[T]): Array[T] = ls.toArray ^ 

    Après:

     scala> def listToArray[T: Manifest](ls: List[T]): Array[T] = ls.toArray listToArray: [T](ls: List[T])(implicit evidence$1: Manifest[T])Array[T] scala> def listToArray[T](ls: List[T])(implicit m: Manifest[T]): Array[T] = ls.toArray listToArray: [T](ls: List[T])(implicit m: Manifest[T])Array[T] 

    Toute méthode qui appelle listToArray et elle-même prend T comme paramètre de type doit également accepter le manifeste comme paramètre implicite. Consultez le SID des tableaux pour plus de détails.

  5. Avant trop longtemps, vous rencontrerez une erreur comme celle-ci:

     scala> collection.Map(1 -> 2): Map[Int, Int] :6: error: type mismatch; found : scala.collection.Map[Int,Int] required: Map[Int,Int] collection.Map(1 -> 2): Map[Int, Int] ^ 

    Vous devez comprendre que le type Map est un alias dans Predef pour collection.immutable.Map .

      object Predef { type Map[A, B] = collection.immutable.Map[A, B] val Map = collection.immutable.Map } 

    Il existe trois types nommés Map – une interface en lecture seule: collection.Map , une implémentation immuable: collection.immutable.Map , et une implémentation mutable: collection.mutable.Map . De plus, la bibliothèque définit le comportement dans un ensemble parallèle de traits MapLike , mais il s’agit vraiment d’un détail d’implémentation.

Récolter les bénéfices

  1. Remplacez une surcharge de méthode par des parameters nommés et par défaut.
  2. Utilisez la méthode de copy générée des classes de cas.

      scala> case class Foo(a: Int, b: Ssortingng) defined class Foo scala> Foo(1, "a").copy(b = "b") res1: Foo = Foo(1,b) 
  3. Généraliser vos signatures de méthode de List à Seq ou Iterable ou Traversable . Les classes de collecte étant dans une hiérarchie propre, pouvez-vous accepter un type plus général.
  4. Intégration avec les bibliothèques Java à l’aide des annotations. Vous pouvez désormais spécifier des annotations nestedes et contrôler si les annotations sont ciblées sur les champs ou les méthodes. Cela aide à utiliser Spring ou JPA avec le code Scala.

Il existe de nombreuses autres nouvelles fonctionnalités qui peuvent être ignorées en toute sécurité lorsque vous commencez à migrer, par exemple @specialized et Continuations.

La réponse de VonC est difficile à améliorer, alors je ne vais même pas essayer. Je couvrirai d’autres choses non mentionnées par lui.

Tout d’abord, certaines choses dépréciées iront. Si vous avez des avertissements de dépréciation dans votre code, il est probable qu’il ne sera plus compilé.

Ensuite, la bibliothèque de Scala se développe. Surtout, les petits motifs courants, tels que la capture des exceptions dans Either ou Option , ou la conversion d’un AnyRef en une option avec null mappé sur None . Ces choses peuvent généralement passer inaperçues, mais je commence à en avoir marre de poster quelque chose sur le blog et plus tard, demander à quelqu’un de me dire que c’est déjà sur Scala 2.8. Eh bien, en fait, je ne m’en lasse pas, mais plutôt, et heureusement, je m’y suis habitué. Et je ne parle pas ici des collections, qui font l’object d’une révision majeure.

Maintenant, ce serait bien si les gens affichaient des exemples concrets de ces améliorations de bibliothèque. J’accepterais avec plaisir toutes ces réponses.

REPL n’obtient pas seulement l’achèvement des commandes. Cela prend beaucoup de choses, y compris la possibilité d’examiner l’AST pour un object, ou la possibilité d’insérer des points de rupture dans le code qui tombe dans REPL.

En outre, le compilateur de Scala est en cours de modification pour pouvoir fournir une compilation partielle rapide aux IDE, ce qui signifie que nous pouvons nous attendre à ce qu’ils soient bien plus informés sur Scala – en interrogeant le compilateur Scala lui-même sur le code.

Un grand changement est susceptible de passer inaperçu par beaucoup, bien qu’il réduise les problèmes pour les auteurs de bibliothèques et les utilisateurs. En ce moment, si vous écrivez ce qui suit:

 package com.mystuff.java.wrappers import java.net._ 

Vous com.mystuff.java pas la bibliothèque net de Java, mais net bibliothèque net com.mystuff , com.mystuff.java que com , com.mystuff , com.mystuff.java et com.mystuff.java.wrappers toutes été com.mystuff.java.wrappers dans la scope et java se trouve à l’intérieur. com.mystuff . Avec Scala 2.8, seuls les wrappers sont ciblés. Étant donné que, parfois, vous souhaitez qu’une partie du rest soit dans Scope, une autre syntaxe de package est désormais autorisée:

 package com.mystuff.factories package ligthbulbs 

ce qui équivaut à:

 package com.mystuff.factories { package lightbulbs { ... } } 

Et il arrive que les factories et les lightbulbs entrent dans la scope.

Devrais-je réécrire quelque chose?

 def takesArray(arr: Array[AnyRef]) {…} def usesVarArgs(obs: AnyRef*) { takesArray(obs) } 

doit devenir

 def usesVarArgs(obs: AnyRef*) { takesArray(obs.toArray) } 

J’ai dû visiter le canal IRC pour celui-là, mais j’ai alors réalisé que j’aurais dû commencer ici.

Voici une liste de contrôle d’Eric Willigers, qui utilise Scala depuis 2.2. Certains de ces éléments sembleront datés pour les utilisateurs plus récents.

* Importation explicite à partir de paquets externes *

Supposons que nous ayons

 package a class B 

Changement

 package ac class D extends B 

à

 package ac import aB class D extends B 

ou

 package a package c class D extends B 

* Utiliser un nom de package complet lors de l’importation depuis un package externe *

Supposons que nous ayons

 package ab object O { val x = 1 } 

Changement

 package abc import bOx 

à

 package abc import abOx 

* Lorsque vous spécifiez explicitement des parameters de type dans les appels de méthode de conteneur, ajoutez de nouveaux parameters de type *

Changement

 list.map[Int](f) 

à

 list.map[Int, List[Int]](f) 

Changement

 map.transform[Value](g) 

à

 map.transform[Value, Map[Key, Value]](g) 

* Créer une carte sortingée en utilisant la commande au lieu de la conversion en commande *

  [scalac] found : (Ssortingng) => Ordered[Ssortingng] [scalac] required: Ordering[Ssortingng] [scalac] TreeMap[Ssortingng, Any](map.toList: _*)(ssortingngToCaseInsensitiveOrdered _) 

* Importez les conversions implicites qui remplacent scala.collection.jcl *

* La carte immuable .update devient .updated *

*** Migrer à partir des méthodes List récemment obsolètes –
* elements * remove * sort * List.flatten(someList) * List.fromSsortingng(someList, sep) * List.make

*** Utiliser les méthodes de liste * diff * iterator * filterNot * sortWith * someList.flatten * someList.split(sep) * List.fill

* classpath lors de l’utilisation de scala.tools.nsc.Settings *

http://thread.gmane.org/gmane.comp.lang.scala/18245/focus=18247 settings.classpath.value = System.getProperty (“java.class.path”)

* Éviter l’erreur: _ doit suivre la méthode; ne peut pas suivre (Any) => Boolean *

Remplacer

 list.filter(that.f _) 

avec

 list.filter(that f _) 

ou

 list.filter(that.f(_)) 

>>>

* Migration à partir des méthodes d’énumération obsolètes map * Utilisation des méthodes d’énumération values.iterator values.map

* Migrer à partir de Iterator.fromValues(a, b, c, d) obsolètes Iterator.fromValues(a, b, c, d) * Utiliser Iterator(a, b, c, d)

* Evitez les types obsolètes Collection * Utilisez plutôt Iterable

* Changer l’ordre d’initialisation *

Supposons que nous ayons

 trait T { val v val w = v + v } 

Remplacer

 class C extends T { val v = "v" } 

avec

 class C extends { val v = "v" } with T 

* Evitez les val inutiles for (val x <- ...) *

* Évitez les virgules *