2012-07-14 1 views
1

Vous pouvez le faire pour obtenir des conversions implicites à la chaîne:enchaînant les conversions implicites en toute sécurité

package language 

object chainedImplicits { 
    implicit def chainImplicits[A, B, C](a: A)(implicit conv1: A => B, conv2: B => C): C = conv2(conv1(a)) 
} 

mais ce n'est évidemment pas sûr.

Je ne vois rien de mal avec cette version, bien que:

package language 

package chainedImplicits { 

    final class Chained[A, B] private[chainedImplicits] (val f: A => B) 

    trait Low { this: `package`.type => 
    implicit def startChaining(implicit conv: A => B): Chained[A, B] = new Chained[A, B](conv) 
    implicit def chainImplicits[A, B, C](implicit conv1: Chained[A, B], conv2: B => C): Chained[B, C] = new Chained(conv1.f andThen conv2) 
    } 

} 

package object chainedImplicits extends Low { 
    implicit def endChain[A, B](a: A)(implicit conv: Chained[A, B]): B = conv.f(a) 
} 

est-il un piège ici?

+4

Pourquoi le premier bloc de code d'un code évidemment pas sûr? Scala pourrait-il créer une chaîne infinie d'implicits en instanciant '' A'' et '' C'' avec le même type concret? –

+0

@mhs Non, car Scala n'appelle une conversion implicite que si le code ne vérifie pas le type. Le danger avec le premier est que les chaînes d'implicits pourraient ne pas être uniques signature finale modulo. –

Répondre

0

D'abord, je ne peux pas obtenir votre premier exemple "évidemment pas sûr" rien à faire:

import language.implicitConversions 

object Test { 
    implicit def chain[A, B, C](a: A)(implicit ab: A => B, bc: B => C): C = bc(ab(a)) 

    case class X() 
    case class Y() 
    case class Z() 

    implicit def xy(x: X) = Y() 
    implicit def yz(y: Y) = Z() 

    val z: Z = X() 
} 

...

type mismatch; 
    found : Test.X 
    required: Test.Z 
    val z: Z = X() 
      ^

Ensuite, l'évidence "attraper" dans votre deuxième Par exemple, il ne compile pas. Avez-vous réellement essayé? Peu importe, après « la fixation », il ne fonctionne toujours pas ce que vous voulez:

import language.implicitConversions 

class Convert[A, B](val convert: A => B) extends AnyVal 
trait Convert0 { 
    implicit def convert[A, B](implicit ab: A => B): Convert[A, B] = new Convert(ab) 
    implicit def convert[A, B, C](implicit ab: Convert[A, B], bc: B => C): Convert[A, C] = new Convert(ab.convert andThen bc) 
} 
object Convert extends Convert0 { 
    implicit def convert[A, B](a: A)(implicit convert: Convert[A, B]): B = convert.convert(a) 
} 

object Test { 
    case class X() 
    case class Y() 
    case class Z() 

    implicit def xy(x: X) = Y() 
    implicit def yz(y: Y) = Z() 

    val z: Z = X() 
} 

Cela donne la même erreur d'incompatibilité de type. A ma connaissance, si vous voulez des conversions implicites à la chaîne, vous devez être explicite à ce sujet:

import language.implicitConversions 

object test { 
    case class X() 
    case class Y() 
    case class Z() 

    // anything convertible to X is convertible to Y 
    implicit def xy[A <% X](x: A) = Y() 

    // anything convertible to Y is convertible to Z 
    implicit def yz[B <% Y](y: B) = Z() 

    val z: Z = X() 
} 
Questions connexes