6
  • I have 3 Scala classes (A,B,C).
  • I have one implicit conversion from A -> B and one from B -> C.

At some point in my code, I want to call a C method on A. Is this possible? One fix I came up is to have a conversion from A -> C but that seems somewhat redundant.

Note:

  • When I call B methods on A it works.
  • When I call C methods on B it works.
  • When I call C methods on A it says that it didn't find the method in the body of A

Thanks ...

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • 6
    Hint: this looks more like _transitivity_ than _associativity_. And you're not the first person to want this for Scala's implicits. Also `A -> C` is probably a typo for `B -> C` in your second line? – Travis Brown Mar 04 '12 at 18:42
  • 3
    also have a look at: [how-can-i-chain-implicits-in-scala](http://stackoverflow.com/questions/5332801/how-can-i-chain-implicits-in-scala) – Peter Schmitz Mar 04 '12 at 22:39

2 Answers2

9

It seems you made a typo when you wrote the question. Did you mean to say you have implicit conversions from A -> B and B -> C, and that you find an A -> C conversion redundant?

Scala has a rule that it will only apply one implicit conversion when necessary (but never two), so you can't just expect Scala to magically compose A -> B and B -> C to make the conversion you need. You'll need to provide your own A -> C conversion. It's not redundant.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • 4
    One reason why this is the case is that there might be multiple possibilities for the middle type. If there exist implicit conversions `A -> B1`, `B1 -> C` and `A -> B2`, `B2 -> C`, the compiler would be unable to guess which one you wanted. – hammar Mar 04 '12 at 19:38
  • with `implicit def transitive[A, B, C](implicit a2b: A => B, b2c: B => C): A => C = (a: A) => b2c(a2b(a))` it's theoretically possible to do transitive resolution. But in that case every `implicitly[A => B]` diverges, as there is implicit `$conforms[A]: A => A` - resolution algorithm ends up looping. – phadej Jan 21 '15 at 13:59
6

It does seem somewhat redundant, but the A -> C conversion is exactly what you should supply. The reason is that if implicits are rare, transitive chains are also rare, and are probably what you want. But if implicits are common, chances are you'll be able to turn anything into anything (or, if you add a handy-looking implicit, suddenly all sorts of behaviors will change because you've opened up different pathways for implicit conversion).

You can have Scala chain the implicit conversions for you, however, if you specify that it is to be done. The key is to use generics with <% which means "can be converted to". Here's an example:

class Foo(i: Int) { def foo = i }
class Bar(s: String) { def bar = s }
class Okay(b: Boolean) { def okay = b }
implicit def to_bar_through_foo[T <% Foo](t: T) = new Bar((t: Foo).foo.toString)
implicit def to_okay_through_bar[U <% Bar](u: U) = new Okay((u: Bar).bar.length < 4)

scala> (new Foo(5)).okay
res0: Boolean = true
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • Yeah, I tried the <% thing and it worked. But it also generated a weird implicit from Array[String] => Unit compiler error. So I'm back to bridging the gap manually. Tanks for your help. – Matei Alexandru Bogdan Mar 06 '12 at 08:20