9
votes

Scala Traits et types de structure: Un trait peut-il prolonger un type structurel puis appeler Super?

J'aimerais avoir un trait qui peut a) être mélangé dans n'importe quelle classe avec une méthode particulière, et b) peut appeler Super. Quelque chose comme ceci: xxx pré>

existe-t-il un moyen de faire cela? P>

Notez que je ne contrôle pas A et B; Ils viennent d'une autre bibliothèque que je ne peux pas modifier. p>

[Modifier - ajouté après avoir vu des réponses] p>

est là un moyen d'appeler la méthode d'origine dans quelque chose comme ça? p>

  trait ImplementsStuff {
    this: HasStuffMethod =>
    abstract override def stuff = "foo" + "how do I call the original method here?"
  }


5 commentaires

Ici Hassffmethod n'est pas une classe de type. C'est un alias de type à un type structurel.


Droit - un modèle de typlass est autre chose. Et il n'est pas pertinent de savoir si hasstuffmethod est un type structurel ou nominal (c'est-à-dire un trait régulier).


J'ai ajouté une modification proposée à votre question. J'espère que cela clarifie ce que vous essayez de faire. Si j'ai mal interprété, vous pouvez l'effacer. Si c'est correct, vous pouvez l'utiliser pour reformuler votre question. Dans ce cas, veuillez également modifier la référence à "Typemass" dans le titre de la question.


@Paolofalabella, je pense que je vois où vous allez, mais je pense que la modification proposée ne le rend pas vraiment plus clair. Il est toujours faux de répéter le code, il y a donc une grosse morceine de l'édition proposée qui doit disparaître et je ne pense pas que ce qui reste est vraiment différent de l'original. Certainement, la référence à la typlass dans mon original n'est pas fausse et je vais le réparer. (A suscité votre commentaire)


Je pense avoir ce que vous demandiez, mais cela m'a semblé que Daniel C.Sobral et paradigmatique ne l'ont pas fait. Comme ils sont tous deux beaucoup plus experts à Scala que moi, je pensais que peut-être reharaser votre question pourrait vous obtenir une meilleure réponse que la mienne. Cependant, vous avez probablement raison que mon édition proposée n'était pas vraiment une amélioration.


3 Réponses :


4
votes

Vous avez besoin d'un abstraite remplacement dans un tel cas.


2 commentaires

Comment définissez-vous le trait? (Ajout d'une note indiquant que la ligne "Traiter ImplementsStuffstuffs étend HastuffmeThod" ne compile pas.)


@Jamesmoore Just Résumé Supprimer Def ... . Mais je viens de remarquer que vous l'avez d'émettre un type - - est juste un alias, et votre alias est un type structurel: cela ne fonctionnera pas. Faites prolonger un Classe abstraite à la place ou un trait .



5
votes

Je peux penser à deux options:

option 1, à l'aide d'une annotation de type auto-type et d'appel Stuff code> à partir d'une nouvelle méthode (que j'appelle imaginativement appelée CallStuff code>) de le remplacer. p> xxx pré>

option 2 (puisque vous dites que vous ne contrôlez pas A et B) est le cher ancien modèle de décorateur. P>

  trait HasStuff { def stuff: String }

  class DecorateStuff(decorated: HasStuffMethod) extends HasStuff {
    def stuff = "trait + " + decorated.stuff
  }
  val decA = new DecorateStuff(new A)
  assert(decA.stuff == "trait + a stuff")

  val decB = new DecorateStuff(new B)
  assert(decB.stuff == "trait + b stuff")


3 commentaires

Les deux intéressants, mais ni ne résout le problème. Le premier échoue car il n'ya aucun moyen de dire à tous les appelants qu'ils doivent appeler une nouvelle méthode (et donc les affirmations échouent définitivement). La seconde renvoie un type différent, il s'agit donc d'une technique utile, mais cela ne vous aide pas vraiment ici - que faites-vous que vous faites lorsque vous devez passer la nouvelle chose à un autre code qui attend un A, pas un décoratestuff?


@Jamesmoore Vous avez raison, les deux méthodes supposent que vous / votre équipe contrôlent le code de l'appelant. Si ce n'est pas le cas et que vos attentes sont de modifier le comportement de leur méthode de substance, mais ont toujours A et B, cela ressemble à une programmation orientée forme. Vous pouvez regarder AspectJ. Cet article de Jonas Boner peut vous aider


C'est juste que le système existant semble soooo près de ce que je voudrais. Dans votre premier exemple, si vous pouviez modifier CallStuff au bout des trucs ordinaires, puis avoir un moyen de référencer la méthode étant remplacée, vous l'auriez. (Ajouté que à ma question)



1
votes

Il n'y a aucun moyen d'étendre un type raffiné dans Scala (je ne suis pas sûr que cela pourrait être retiré en toute sécurité, mais il serait intéressant d'explorer).

J'ai une solution plus verbeuse, mais vous rapproche de votre objectif. P>

$ a.stuff
res0: java.lang.String = trait + a stuff

$ b.stuff
res1: java.lang.String = trait + b stuff


0 commentaires