10
votes

Classe de cas et linéarisation des traits

Supposons que je souhaite écrire une classe de cas stepper code> comme suit: xxx pré>

Il est livré avec un joli Tostring code> implémentation: xxx pré>

mais ce n'est pas vraiment une fonction: p> xxx pré>

une solution de contournement consiste à implémenter la fonction code> Trait ... p>

scala> Stepper(42).toString
res2: java.lang.String = <function1>


0 commentaires

3 Réponses :


2
votes

EDIT: Qu'en est-il de la réalisation de tostring? XXX


2 commentaires

Oui je le sais. Mais je ne veux vraiment pas ajouter Nations Unia (Imagine-le dans un DSL).


L'idée était de trouver quelque chose qui peut être réutilisé, c'est pourquoi je ne suis pas allé dans la réécriture de la réécriture.



1
votes

Vous pouvez utiliser une conversion implicite pour avoir stepper code> traitée comme une fonction uniquement si nécessaire:

case class Stepper(step: Int) { def apply(x: Int) = x + step }

implicit def s2f(s: Stepper) = new Function[Int, Int] {
  def apply(x: Int) = s.apply(x)
}


5 commentaires

Oui, mais la construction de ce implicite est plus douloureuse que la réécriture de tostring;)


@Nicolas: vraiment? C'est 40 caractères. Cela semble beaucoup moins "douloureux" que d'utiliser un bit non documenté de l'API d'exécution.


Ce n'est pas une question de nombre de caractères, c'est une question d'ajouter un code «non sèche» dans une classe. La solution SCALARUNTime n'est pas parfaite, n'est clairement pas prête à la production mais passe dans une direction sèche. BTW, je l'ai initialement comparuré à la réécriture de Tostring (voir la réponse de Tal Pressman)


@Nicolas: Je ne pense pas que vous allez pouvoir écrire une bibliothèque très satisfaisante de DSL-ISP sans impliquer et, dans ce cas, l'approche implicite est effectivement plus propre que l'héritage: vous n'avez besoin que d'une fonction Pour faire de votre syntaxe jolie, alors pourquoi le forcer dans votre hiérarchie de classe?


Non, mon point n'était pas l'utilisation implicite. La question avec votre solution est TAHT, je dois créer une nouvelle fonction implicite à chaque fois que je souhaite que ma classe soit considérée comme une fonction. De plus, addind La fonction traitz est non seulement syntaxique, il est seulement sémantique: les instances de ma classe sont des fonctions. Enfin, la question n'était pas "Puis-je le faire avec une autre chose, implicite ou autre chose" mais "puis-je récupérer la définition de Tostring introduite par la classe de cas".



8
votes

La question n'est pas vraiment à voir avec la linéarisation. Dans cas-Classes Tostring code> est une méthode générée automatiquement par le compilateur si et uniquement si any.tostring code> n'est pas remplacé dans le type d'extrémité.

Cependant, la réponse est en partie à voir avec la linéarisation - nous devons remplacer fonction1.tostring code> avec la méthode qui aurait été générée par compilateur si non pour la version introduite par Fonction1 : p> xxx pré>

puis p> xxx pré>

produira p>

trait ProperName extends Product {
  override lazy val toString  = {
    val caseFields = {
       val arity = productArity
       def fields(from: Int): List[Any] =
         if (from == arity) List()
         else productElement(from) :: fields(from + 1)
       fields(0) 
    }
    caseFields.mkString(productPrefix + "(", ",", ")")
  }
}


9 commentaires

Oui, ce n'est pas vraiment linéarisation, mais je n'ai trouvé aucun autre nom approprié pour cela. Et c'était le genre d'astuce que je m'attendais, merci.


@Nicolas Je vous comprends très bien, je me trouve que souvent, il est difficile de décrire un problème exactement quand je ne suis pas sûr de ce qui se passe.


@Vlad: J'ai toujours évité d'utiliser quelque chose à partir de scala.runtime qui ne figure pas dans les documents de l'API Scala. Je conviens que c'est une solution de contournement intelligente, mais pensez-vous vraiment que cela en vaut la peine, étant donné qu'il y a des solutions tout aussi bonnes qui utilisent des fonctionnalités de langue plante de Scala?


Les autres solutions nécessitent de revoir la logique encore et encore dans chaque cas. Bien sûr, la solution VLAD n'est pas une "production prête", mais agréable. C'est pourquoi, une fois que quelqu'un fournit quelque chose d'élégant à l'aide de l'API standard, il est accepté. ;)


Et aussi: jusqu'à présent, c'était le seul que je n'avais pas déjà envisagé.


@Travis Toute personne qui s'inquiète de l'utilisation de Scala.Runtime pourrait déployer son propre générique Tostring Remplacer en regardant le scala.runtime.runtime source source Harrah.github.com/Browse/Semples/Library/ Scala / Runtime / ... Cela prendra un peu plus d'effort, mais pourrait boucler contre des changements potentiels à l'API à l'avenir. Une approche alternative serait de couvrir le remplacement proposé Tostring avec des tests unitaires et une fois (et une fois) il est cassé dans la version future - 1) Créer une classe de cas simple 2) Compiler 3) Javap 4) Look Quelle méthode générée ressemble


@Nicolas Je pense que Tostring a été inclus dans les classes de cas comme une fonctionnalité "agréable d'avoir" qui aide lors du prototypage / du débogage / de la déconnexion dans la RÉPEP. Normalement, vous ne voudriez pas compter sur un détail de mise en œuvre, comme le nom d'une classe dans le code pour influencer l'IO de votre application, donc dans le code de production, vous devez veulent d'inclure votre propre représentation à chaîne si vous besoin d'une telle chose.


Une solution acceptable peut être de modifier le trait ci-dessus à une classe abstraite et de passer le nom et l'argument explicitement, c'est-à-dire abstract classe func [t] (nom: chaîne, arg: t) s'étend (t => t) {Remplacer def tostring = nom + "(" + arg + ")"}


@LUIGIPLINGE dans la production ne signifie pas que la logique repose sur la méthode de tostrage. Votre Func nécessite également beaucoup de répétitions (et pour ce genre de chose, la classe Abstract est définitivement une mauvaise réponse). Et encore une fois, cela ne répond pas à ma question. Je sais comment créer une bibliothèque ou une bibliothèque à proximité, je me demandais simplement comment je peux obtenir la méthode de totring d'une classe de cas, même si j'ajoute d'autres traits.