Dotty: Special syntax for type quotes and type splices is redundant

Created on 3 Aug 2020  Â·  5Comments  Â·  Source: lampepfl/dotty

Currently, we can create a quoted.Type[X] with

val t1: Type[X] = '[X] // special syntax
val t2: Type[X] = Type[X] // Type.apply method
val t2: Type[X] = summon[Type[X]] // given by Type.apply

the first two are equivalent as '[X] is typed as Type[X] which is just a call to the function Type.apply. Most of the time this type is not generated by hand, it is just summoned for some contextual parameter. Hence the special syntax '[...] is redundant.


On the other side, using a quoted.Type[X] can be done with

def f[X](using QuoteContext)(using t: Type[X]) = '{
  val t1: $t = ??? // special syntax
  val t2: t.T = ??? // accessed directly
  val t3: X = ??? // healed using t.T
}

both are equivalent as '$t is typed as t.T which is just a member selection. Most of the type we use directly X which gets healed to t.T. Hence the special syntax $t is redundant.


Furthermore, we used quotes and splices for both expressions and types because in the beginnings we thought that they behaved similarly level-wise. But now that we realized that this is not true, this similarity in syntax only leads to confusion.

metaprogramming enhancement question

Most helpful comment

@smarter I used to think that too, but this type doesn't really embody anything specific that would warrant a more specific name. One could think a "good" name would be something like UnerlyingType, but that's just verbose and would simply add a lot of needless noise. It's the same reason we don't use ElementType instead of A for collections. In the end, I think theType.T is clear enough and more concise, which actually helps when reading code.

All 5 comments

Should we remove this syntax?

Can you manually insert a type evidence you don't have in implicit scope? As in { List.empty[${foo.bar.theType}] }. It feels like not having such a capability might be annoying — you'd have to do something like:

  given as foo.bar.T = foo.bar.theType
  '{ List.empty[foo.bar.theType.T] }

Obligatory "it works in Squid!":

scala> object foo {
     |   object bar {
     |     type T
     |     val theType = codeTypeOf[Int].asInstanceOf[CodeType[T]]
     |   }
     | }
defined object foo

scala> code"List.empty[${foo.bar.theType}]"
res0: squid.IR.ClosedCode[List[foo.bar.T]] = code"scala.collection.immutable.List.empty[scala.Int]"

Yes. The t.T does that. There we do not need to look for the implicit because we already have it from the t itself. The splice behaves the same way. Though in some cases inference decides to widen them and there we might need it implicitly.

If .T is meant to be a public API, it needs a more descriptive name I think, maybe .Splice or .Repr

@smarter I used to think that too, but this type doesn't really embody anything specific that would warrant a more specific name. One could think a "good" name would be something like UnerlyingType, but that's just verbose and would simply add a lot of needless noise. It's the same reason we don't use ElementType instead of A for collections. In the end, I think theType.T is clear enough and more concise, which actually helps when reading code.

Was this page helpful?
0 / 5 - 0 ratings