43 votes

Éléments du style Scala ?

Le jour, j'écris du C#. Tout ce que je fais passe par les outils d'analyse de code et d'analyse statique de Microsoft, de sorte que mon C# a une structure et une disposition très régulières. Évidemment, j'écris du code avec un certain style. C'est en partie parce que je n'ai pas le choix (il ne compilera pas si j'oublie un espace avant cette virgule), mais c'est aussi agréable d'avoir un code d'apparence régulière, de savoir où chercher les choses, etc.

Le week-end, je m'initie à Scala. Je regarde l'API Scala et Ascenseur de la source du framework web, je ne vois évidemment pas de style standardisé. Une chose qui me saute aux yeux, par exemple, est l'absence d'un fichier séparé par classe. Le manque de cohérence avec les crochets et les accolades est un autre exemple.

Je comprends qu'il y a probablement plusieurs raisons à cela : premièrement, avec le code source ouvert (ou hobby), s'assurer qu'une méthode évidente n'est pas complètement documentée est moins prioritaire. Deuxièmement, des choses comme les classes de cas réduisent les déclarations de classe de 20 lignes à une seule ligne. Troisièmement, le C# est un langage beaucoup plus " plat " : à moins qu'il ne s'agisse d'un code complexe, le C# peut être utilisé comme un outil d'aide à la décision. LINQ le nombre de parenthèses, d'accolades et de crochets imbriqués n'est pas si élevé. En Scala, les choses ont tendance à être un peu plus imbriquées.

Les utilisateurs réguliers de Scala ont-ils un style spécifique auquel ils se tiennent ? Suis-je simplement stupide en mettant une classe de cas d'une ligne dans son propre fichier au nom d'une convention [étrangère] ? Des conseils ?

45voto

Daniel C. Sobral Points 159554

Avoir plusieurs classes et objets dans un seul fichier est considéré comme une bonne pratique en Scala, tant que les classes sont étroitement liées.

Bien que cela ne soit pas nécessaire, le type renvoyé par une méthode - une fonction nommée déclarée sur un trait, une classe ou un objet - doit être déclaré pour les méthodes non privées. Les espaces sont attendus après : mais pas avant.

//  methods declared on a class, trait or object
def length: Int = ...
def multiply(other: Foo): Foo = ...

def hypotenuse(a: Double, b: Double): Double = {
  //  function inside a method, so effectively private
  def square(x: Double) = x * x

  math.sqrt(square(a) + square(b))
}

Des espaces sont attendus entre les mots clés et les parenthèses, mais pas entre un nom de méthode et la parenthèse suivante, en notation point. Pour la notation des opérateurs, il ne semble pas y avoir de style accepté concernant les parenthèses - ou quand utiliser cette notation, d'ailleurs, mais des espaces sont attendus autour des méthodes non alphanumériques dans une telle notation.

//  keywords
if (foo) ...

//  dot notation
foo.doSomething(bar)

//  operator notation
foo doSomething bar
foo + bar

Exceptionnellement, lors de la concaténation de chaînes de caractères avec + le style recommandé est de ne pas utiliser d'espaces autour. Par exemple :

//  concatenate strings
println("Name: "+person.name+"\tAge: "+person.age)

Les déclarations qui peuvent être d'une ligne sont censées être d'une ligne, à moins que l'imbrication ne soit pas évidente.

//  one-liners
lazy val foo = calculateFoo
def square(x: Int) = x * x

Les méthodes qui n'attendent pas de paramètres et qui n'ont pas d'effets secondaires sont censées être utilisées sans parenthèses, à l'exception des méthodes Java, qui sont censées être utilisées avec des parenthèses. Les méthodes sans paramètres ayant des effets secondaires sont censées être utilisées avec des parenthèses.

//  without side-effects
val x = foo.length
val y = bar.coefficient

//  with side-effects
foo.reverse()

Les déclarations qui contiennent une seule expression ne doivent pas être placées entre accolades, à moins que d'autres considérations syntaxiques ne le rendent impossible. Le fait d'enfermer une expression entre parenthèses pour permettre des expressions sur plusieurs lignes est accepté, mais j'ai vu peu d'utilisation de cela.

//  single-line expression
def sum(list: List[Int]): Int = if (!list.isEmpty) list reduceLeft (_ + _) else 0

//  multi-line expression
val sum = (
  getItems
  reduceLeft (_ + _)
)

Dans les for-comprehensions, garder les générateurs et les conditions alignés verticalement semble être un style accepté. Comme pour les yield Je l'ai vu à la fois aligné avec for et en retrait.

//  for-comprehensions
val squares =
  for (x <- numbers)
    yield x * x

// Curly brackets-style identation
val cells = for {
  x <- columns
  y <- rows
  if x != y
} yield Cell(x, y)

// Parameter-style identation
val cells = for (x <- columns;
                 y <- rows;
                 if x != y)
            yield Cell(x, y)

Il est également accepté d'aligner verticalement les paramètres d'une déclaration de classe.

En ce qui concerne l'indentation, deux espaces est la convention acceptée.

Les accolades sont censées commencer sur la même ligne de la déclaration et se terminer dans l'alignement vertical de cette ligne.

//  another example
def factorial(n: Int): Int = {
  def fact(n: Int, acc: Int): Int = n match {
    case 0 => acc
    case x => fact(x - 1, x * acc)
  }

  fact(n, 1)
}

Pour les procédures -- fonctions dont le type de retour est Unit -- , le style attendu était censé laisser de côté le type de la méthode et le signe égal :

//  procedures
def complain {
  println("Oh, no!")
}

Certains pensent que ce style est source d'erreurs, cependant, car un signe égal oublié changera une fonction retournant autre chose que Unit dans une procédure.

Les identifiants sont écrits en majuscules (ex : identifiersHaveHumps ), comme en Java. Pour les noms de champs, de paramètres de méthodes, de variables locales et de fonctions, commencez par une lettre minuscule. Pour les classes, les traits et les types, commencez par une lettre majuscule.

Les noms constants s'écartent de la convention Java. En Scala, la pratique est d'utiliser la casse standard en commençant par une lettre majuscule. Par exemple Pi et non PI , XOffset et non X_OFFSET . Cette règle est généralement suivie par tout singleton. Le fait que les constantes et les singletons soient représentés de cette manière a une conséquence pratique, pour les correspondances de cas :

import scala.Math.Pi

val pi = Pi // this identifier will be shadowed by the identifier in the function below

def isPi(n: Double): Boolean = n match {
  case Pi => println("I got a true Pi."); true
  case pi => println("I got "+pi+" and bounded it to an identifier named pi."); false
}

Les noms des paquets sont écrits en commençant par une lettre minuscule. Cela est particulièrement utile pour distinguer dans une déclaration d'importation ce qui est un paquetage et ce qui ne l'est pas. Dans l'exemple précédent, Math n'est pas un paquet (c'est un singleton), car il commence par une lettre majuscule.

Utilisation du caractère de soulignement -- _ -- n'est pas recommandé, car ce caractère a de nombreuses significations spéciales en Scala. Ces règles pour les identificateurs se trouvent aux pages 141 et 142 de Programming in Scala, par Odersky, Spoon & Venners.

Pour l'instant, je ne me souviens pas d'autres situations, mais n'hésitez pas à demander des précisions sur des points spécifiques. Certaines de ces règles ont été explicitement énoncées, d'autres relèvent davantage d'un consensus de la communauté. J'ai essayé de laisser de côté mes propres préférences, mais j'ai peut-être échoué.

Plus important encore, peut-être, il n'y a tout simplement pas vraiment de convention unifiée. Cela peut s'expliquer par le fait que Scala attire des personnes venant d'horizons très différents, comme des spécialistes des langages fonctionnels, des programmeurs Java et des passionnés du Web 2.0.

12voto

Daniel Spiewak Points 30706

Il existe désormais un guide de style complet pour Scala qui a été proposé à la communauté . Ce n'est pas encore officiel, même de loin, mais c'est la seule codification (à ma connaissance) des conventions acceptées par la communauté.

7voto

kolen Points 712

Maintenant Guide de style Scala est disponible. Il n'est pas 100% officiel (situé sur " Documentation communautaire pour Scala ") mais semble être le guide de style le plus standard pour Scala.

2voto

Erick Fleming Points 743

Je n'aime pas vraiment le style typique que beaucoup de codeurs Scala utilisent, alors je me contente d'appliquer la même norme que celle que j'utiliserais en C#, Java ou surtout JavaScript.

Scala peut être très expressif, mais l'utilisation d'un format peu familier augmentera votre barrière à l'entrée. Surtout si l'on considère que les DSLs qui ne peut pas avoir de "norme".

Donc, je dis de faire tout ce qui peut rendre votre code plus lisible pour vous et votre équipe.

2voto

Daniel Spiewak Points 30706

Il s'agit d'une question très importante. En général, le style Scala semble s'acquérir en fréquentant les autres membres de la communauté Scala, en lisant le code source Scala, etc. Ce n'est pas très utile pour les nouveaux arrivants dans le langage, mais cela indique qu'une sorte de norme de facto est nécessaire. hace existent (tels que choisis par la sagesse des masses). Je travaille actuellement sur un guide de style pour Scala, qui documente les conventions et les meilleures pratiques choisies par la communauté. Cependant, a) il n'est pas encore terminé, et b) je ne suis pas encore sûr d'être autorisé à le publier (je l'écris pour le travail).

Pour répondre à votre deuxième question (en quelque sorte) : en général, chaque classe/trait/objet devrait avoir son propre fichier nommé selon les conventions de nommage Java. Cependant, dans les situations où vous avez beaucoup de classes qui partagent un concept commun, il est parfois plus facile (à court et à long terme) de les mettre toutes dans le même fichier. Dans ce cas, le nom du fichier doit commencer par une lettre minuscule (toujours en camelCase) et être descriptif de ce concept commun.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X