Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala types and compilation

I was using shapeless tags and wrote code similar to this -

import shapeless.tag
import shapeless.tag.@@

object Typeplay {
  trait StringTrait
  type MyString = String @@ StringTrait

  case class StringClass(mps: MyString)
  val stringClass = StringClass(tag[StringTrait]("test"))
}

And this code would not compile. Scala compiler complains about the last line of code saying -

[error]  found   : String("test")
[error]  required: shapeless.tag.Tagged[in.bharathwrites.Typeplay.StringTrait] with String
[error]   val stringClass = StringClass(tag[StringTrait]("test"))

I could not understand what was I doing wrong. So I made a small change to my code -

import shapeless.tag
import shapeless.tag.@@

object Typeplay {
  trait StringTrait
  type MyString = String @@ StringTrait

  case class StringClass(mps: MyString)

  val stringTag = tag[StringTrait]("test")
  val stringClass = StringClass(stringTag)
}

Which is basically just using an explicit variable for the tagging. And this code compiles!!

How can this be? Why does the first program not compile and the second one does?

like image 588
Bharadwaj Avatar asked Nov 08 '22 15:11

Bharadwaj


1 Answers

It seems that type alias confuses type inference in this case. If you provide explicit types to the tag method, everything works fine:

StringClass(tag[StringTrait][String]("test"))

or

StringClass(tag[StringTrait]("test"):String @@ StringTrait)

or if you declare param StringClass directly:

case class StringClass(mps: String @@ StringTrait)

StringClass(tag[StringTrait]("test"))

Apparently the limitation of scala compiler.


UPD. Frankly, I can't tell what exact limitation of type inference you hit here. My search for relevant open bugs was fruitless.

Regarding the first example. Everything becomes clear if you look at the implementation of the tag:

object tag {
  def apply[U] = new Tagger[U]

  trait Tagged[U]
  type @@[+T, U] = T with Tagged[U]

  class Tagger[U] {
    def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
  }
}

So, when you do this:

tag[StringTrait][String]("test")

You basically do this:

tag.apply[StringTrait].apply[String]("test")
like image 120
Aivean Avatar answered Nov 14 '22 21:11

Aivean