Question

La question est de savoir pourquoi le code suivant ne fonctionne pas avec l'inférence de type (ci-dessous est une session REPL à démontrer), et peut-il être corrigé?Plus précisément, en quoi est-ce différent de l'utilisation de CanBuildF à partir de laquelle le compilateur utilise pour déduire le type de retour?

Compte tenu de ce code:

object S {
    import java.net._

    trait UrlLike[T] {
      def url(s: String): T
    }

    object UrlLike {
      implicit object str extends UrlLike[String]{def url(s: String) = s}
      implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
      implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
    }

    trait UrlSupport {
        val _url: String

        def url[T : UrlLike]: T = implicitly[UrlLike[T]].url(_url)
    }
}

J'ai cette session dans le REPL (2.8.1):

scala> :load c:\temp\UrlTest.scala
Loading c:\temp\UrlTest.scala...
defined module S

scala> import java.net._
import java.net._

scala> import S._
import S._

scala> new UrlSupport{val _url = "http://example.com"}
res0: java.lang.Object with S.UrlSupport = $anon$1@155bd22

scala> res0.url : String
<console>:14: error: ambiguous implicit values:
 both object uri in object UrlLike of type object S.UrlLike.uri
 and object url in object UrlLike of type object S.UrlLike.url
 match expected type S.UrlLike[T]
       res0.url : String
            ^

scala> res0.url : URL
<console>:14: error: ambiguous implicit values:
 both object uri in object UrlLike of type object S.UrlLike.uri
 and object url in object UrlLike of type object S.UrlLike.url
 match expected type S.UrlLike[T]
       res0.url : URL
            ^

scala> res0.url[String]
res3: String = http://example.com

scala> res0.url[URL]
res4: java.net.URL = http://example.com 
Était-ce utile?

La solution

> trait UrlLike[T] {

trait UrlLike[+T] {

Autres conseils

Je peux voir pourquoi vous vous attendez à ce que cela fonctionne, mais, évidemment, l'inférence de type n'utilise pas le type de retour pour inférer T.Je m'y attendrais aussi.

Quant à l'ambiguïté, CanBuildFrom évite d'être ambigu en ne définissant simplement pas tout dans le même "niveau".Par exemple, cela résout le problème d'ambiguïté:

trait LowPriorityImplicits {
  implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
  implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}

object UrlLike extends LowPriorityImplicits {
  implicit object str extends UrlLike[String]{def url(s: String) = s}
}

Cependant, cela ne fera pas que l'inférence de type fonctionne comme vous le souhaitez:

scala> res0.url : URL
<console>:16: error: type mismatch;
 found   : String
 required: java.net.URL
       res0.url : URL
            ^

Ce qui indique qu'il fait évidemment une inférence T sans prendre en compte le type de retour.

En ce qui concerne toute ambiguïté implicite, la règle est (depuis Scala2.8) :

Lors de la comparaison de deux alternatives applicables différentes d'une méthode surchargée ou d'une implicite, chaque méthode:

  • obtient un point pour avoir des arguments plus spéci fi ques ,
  • et un autre point pour être défini dans une sous-classe appropriée .

Une alternative "l'emporte" sur une autre si elle obtient un plus grand nombre de points dans ces deux comparaisons.
Cela signifie en particulier que si les alternatives ont des types d'arguments identiques, celui qui est défini dans une sous-classe l'emporte.

Je ne pense pas que les implicites autour de URL ou URI obtiennent un ensemble de points différent suivant ces critères.

Cela n'est peut-être pas évident d'après le rapport d'erreur que vous voyez, mais les trois implicits définis dans l'objet UrlLike contribuent à l'ambiguïté (par exemple, essayez de commenter la définition de uri et vous verrez l'ambiguïtésignalé comme étant entre str et url).

La raison de l'ambiguïté est que le paramètre de type T de UrlSupport.url n'est limité que par l'exigence qu'une instance UrlLike implicite soit disponible pour lui.La chaîne, l'URL et l'URI satisfont également à cette exigence grâce aux instances UrlLike fournies par vos trois objets implicites.Le compilateur ne choisira pas arbitrairement l'un de ceux-ci pour vous, il signale donc une ambiguïté.

À moins, bien sûr, que vous ne résolviez l'ambiguïté en spécifiant explicitement l'argument de type, comme vous l'avez fait dans les deux dernières de vos interactions REPL.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top