Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
chaining implicit conversions in Scala 2 and Scala 3

in Scala 2, they don't chain 😇, even if we try to give the compiler an assist

can we make them chain in Dotty? 😈

let's try it!

first let's set up sbt:

% cat project/plugins.sbt
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.3.3")
% cat build.sbt
scalaVersion := crossScalaVersions.value.head
crossScalaVersions := Seq("2.13.0", "0.16.0-RC3")

then let's write some Scala 2 code:

import language.implicitConversions

class A; class B; class C

object O {
  implicit def a2b(a: A): B = new B
  implicit def b2c(b: B): C = new C
  implicit def chain[T1,T2,T3](x: T1)(implicit c1: T1 => T2, c2: T2 => T3): T3 =
    c2(c1(x))
  // will it compile?
  (new A): C
}

and try it in both Scala 2 and Dotty:

sbt:chain-2-13> ;++0.16.0-RC3 ;compile
[info] Setting Scala version to 0.16.0-RC3 on 1 projects.
[info] Reapplying settings...
[info] Set current project to chain-2-13 (in build file:/Users/tisue/tmp/chain-2.13/)
[info] Updating ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/tisue/tmp/chain-2.13/target/scala-0.16/classes ...
[info] Done compiling.
[success] Total time: 0 s, completed Jun 19, 2019 4:26:43 PM
sbt:chain-2-13> ;++2.13.0 ;compile
[info] Setting Scala version to 2.13.0 on 1 projects.
[info] Reapplying settings...
[info] Set current project to chain-2-13 (in build file:/Users/tisue/tmp/chain-2.13/)
[info] Compiling 1 Scala source to /Users/tisue/tmp/chain-2.13/target/scala-2.13/classes ...
[error] /Users/tisue/tmp/chain-2.13/S.scala:11:4: type mismatch;
[error]  found   : A
[error]  required: C
[error]   (new A): C
[error]    ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 0 s, completed Jun 19, 2019 4:26:45 PM

Scala 2 does not allow us to chain conversions in this way 😇; Dotty does! 😈

That's using implicit def. What if we use delegate?

import language.implicitConversions

class A; class B; class C

object O {
  delegate for Conversion[A, B] = _ => new B
  delegate for Conversion[B, C] = _ => new C
  delegate [T1, T2, T3] for Conversion[T1, T3]
      given (c1: Conversion[T1, T2], c2: Conversion[T2, T3]) =
    x => c2(c1(x))
  the[Conversion[A, C]]  // compiles!
  // DOES NOT COMPILE:
  // (new A): C
}

I don't understand this 🤔; if delegate search finds an Conversion[A, C], then why wouldn't (new A): C compile?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.