8
votes

Comment créer un objet compagnon explicite pour une classe de cas qui se comporte de manière identique au compilateur remplacé fourni à un objet compilion implicite?

J'ai une classe de cas définie comme telle:

object StreetSecondary extends ((String, Option[String]) => StreetSecondary) {
  //empty for now
}


4 commentaires

Voici un article associé expliquant pourquoi le compilateur a généré un objet compilion implicite qui s'étend sur le fonctionnement: Stackoverflow.com/questions/3049368/...


Selon Stackoverflow.com/ Questions / 34533539 / ... , l'objet "Implicity Companion" n'est pas perdu, mais a l'objet de compagnon explicitement défini de sorte que "ajouté" ou "combiné". (Je ne sais pas ce qui est correct: /)


@Mark Malheureusement, il est partiellement perdu. Essayez-vous avec vous Classe de la case FOO (A: TOUT: B: TOUT) {}; objet foo {}; Foo.tuplé conduit à une erreur de compilateur. Sortez l'objet et ça marche.


Il y a un Buggy Bug pour SCALA pour résoudre ce problème. Il est âgé de 6 ans, peut-être un jour, il sera corrigé et l'objet de compagnon explicite ne provoque pas la perte de l'objet de compagnon implicite.


3 Réponses :


1
votes

Pourquoi penseriez-vous que vous les perdez?

scala> StreetSecondary.unapply _
res10: StreetSecondary => Option[(String, Option[String])] = <function1>


6 commentaires

La méthode tuplée fonctionne-t-elle? Je reçois un rouge squigly sous tupled lorsque vous essayez de l'utiliser. Pour plus de contexte, voir Streetsecondary3 dans cette question, qui est où j'avais le problème avec la méthode tuplée: Stackoverflow.com/questions/25386493/...


Il n'y a en fait aucun tuplé . Vrai. N'était pas au courant de cela. Je n'ai pas encore utilisé cela.


@ chaotic3quilibrium tuplé est une fonction de fonction2 ou (a, b) => C . Essayez (strighetsecondary.apply _). Tuples . Je ne sais pas pourquoi le compilateur n'est plus en mesure de déduire cela.


Je pense que cela ne fonctionnera pas dès que nous ajoutons un nouveau constructeur dans l'objet compagnon. Le compilateur ne saura probablement pas quel Appliquer appelez la méthode et c'est pourquoi il ne peut pas déduire tuplé


@goral C'est exactement pourquoi je veux des éclaircissements sur explicitement ce que le compilateur Scala "génère" lorsqu'il crée l'objet de compagnon implicite. Par exemple, je suis sûr que je suis sûr que le compilateur ajoute "s'étend ((chaîne, option [string]) => Streetsecondary)" juste après le nom de l'objet compaction implicite. C'est là que se trouve la méthode tuplée. J'ai besoin de savoir quelle est la définition complète pour l'objet compagnon implicite afin que je puisse être sûr de lui fournir lorsque j'ai explicitement générer un objet de compagnie explicite. J'ai du mal à trouver la réponse et jusqu'à présent, pas de joie.


@drStevens qui a fonctionné (bien que je ne comprenne pas comment). Cependant, je n'essaie pas vraiment de résoudre le problème de la méthode tupled manquant en soi. J'essaie de comprendre beaucoup plus avec précision et complètement ce que le compilateur Scala génère lorsqu'il génère automatiquement l'objet de compagnon implicite. À ce stade, je ne trouve pas de spécification, formelle ou informelle, de manière explicite explicitement de cela.



3
votes

scala 2.11.0

On dirait que Scalac est prédéfinant la fonction tuples code> lorsque vous ne fournissez pas de fonctions supplémentaires dans la compagnie P>

public class AA implements scala.Product,scala.Serializable {
  public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(AA);
  public static AA apply(int, int);
  public static scala.Function1<scala.Tuple2<java.lang.Object, java.lang.Object>, AA> tupled();
  public static scala.Function1<java.lang.Object, scala.Function1<java.lang.Object, AA>> curried();
  public int a();
  public int b();
  public AA copy(int, int);
  public int copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public AA(int, int);
}

public final class AA$ extends scala.runtime.AbstractFunction2<java.lang.Object, java.lang.Object, AA> implements scala.Serializable {
  public static final AA$ MODULE$;
  public static {};
  public final java.lang.String toString();
  public AA apply(int, int);
  public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(AA);
  public java.lang.Object apply(java.lang.Object, java.lang.Object);
}

public class BB implements scala.Product,scala.Serializable {
  public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(BB);
  public static BB apply(int, int);
  public int a();
  public int b();
  public BB copy(int, int);
  public int copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public BB(int, int);
}

public final class BB$ implements scala.Serializable {
  public static final BB$ MODULE$;
  public static {};
  public BB apply(int, int);
  public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(BB);
}

public class CC implements scala.Product,scala.Serializable {
  public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(CC);
  public static CC apply(int, int);
  public int a();
  public int b();
  public CC copy(int, int);
  public int copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public CC(int, int);
}

public final class CC$ implements scala.Serializable {
  public static final CC$ MODULE$;
  public static {};
  public CC apply(int, int);
  public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(CC);
}


4 commentaires

Impressionnant! TYSVM! Comme il s'agit de Code Java, cela va me prendre un peu de temps pour analyser / évaluer / difforme cela pour déterminer ce à quoi on ressemble à Scala. Comment avez-vous généré cela ?!


Placez le code SCALA dans un fichier et compilez-le avec SCALAC, par exemple. scalac test.scala . Ensuite, vous pouvez utiliser Javap pour examiner les fichiers de classe générés, par ex. Javap AA $ .


Je viens de poster une réponse détaillant ce qui doit être fait dans le code SCALA pour dupliquer les fonctionnalités fournies par l'objet compaction implicite à une classe de cas. Si vous avez du temps et de l'inclination, veuillez l'examiner pour voir si j'ai manqué quelque chose d'évident. Merci.


Dans des versions plus récentes de Scala, vous pouvez également obtenir (uniquement Verbose, y compris les instructions de bytecode) la vidage Javap d'une classe dans la RÉPL avec : Javap Someclass



4
votes

Lors de la définition d'un objet compagnon explicite pour une classe de cas (à la suite de SCALA 2.11), remplacer complètement la fonctionnalité de compilateur fourni dans l'objet compilion implicite perdu, le modèle de base de l'objet de compagnon explicite a deux exigences:

Exigences :
1. Doit étendre une définition de fonction qui consiste en un tuple (correspondant exactement au type et à l'ordre des paramètres du constructeur de la classe de cas) renvoyant le type de la classe de boîtier
2. Doit remplacer la fonction de tostring pour fournir le nom de la classe d'objet (identique à celui de la classe de cas associée) p>

Voici le code d'exemple original pour l'objet de compagnon explicite "vide": p>

object StreetSecondary extends ((String, Option[String]) => StreetSecondary) {
    //replace the toString implementation coming from the inherited class (FunctionN)
    override def toString =
      getClass.getName.split("""\$""").reverse.dropWhile(x => {val char = x.take(1).head; !((char == '_') || char.isLetter)}).head
}


3 commentaires

Je ne suis pas sûr que toute la plaque de chaudière vaut la peine de revenir ce qui est perdu. Les fonctions importantes, non apply , appliquer , égale , hashcode , tostring ne sont pas perdu. Basé sur la réponse de Odersky à la question que vous avez trouvée ( Stackoverflow.com/questions/3049368/... ), il n'existe que pour des raisons héritées. La fonction TUPLE PSUDEO-SPÉCIALISÉE est agréable d'avoir, mais à nouveau, c'est une fonction appartenant à la fonction2 de toute façon. J'ai définitivement appris quelque chose de cet exercice cependant. Dans les 3 ans, j'ai écrit Scala, je n'ai jamais rencontré cela.


@DSTEvens je suis d'accord. Je ne suis pas sûr que cela vaut la peine de la chaudière, non plus. Ce dont j'avais besoin, c'était la confiance que lorsque j'ai décidé de déplacer une classe de cas en fonction de l'objet compilion implicite d'un compilateur Scala à un objet de compagnie explicite, le code existant en fonction de la fonctionnalité implicite a continué de fonctionner. J'utilisais la méthode tuplée en interaction avec la transformation de fichiers texte. Donc, il était surprenant de le faire "disparaître" lorsque je suis allé au refacteur du code produisant un objet de compagnon explicite.


J'ai continué et étendu cette voie avec un post sur Codereview, qui permet un modèle de validation et d'instanciation sans lancer des exceptions de runtimeExceptions (renvoie une liste d'entre eux dans un moyen de faciliter un moyen de manutention plus de la création de classes de cas): Codereview.stackexchange.com/a/60756/4758