Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Look into type tagging and value classes #644

Closed
dwijnand opened this issue Oct 12, 2016 · 9 comments
Closed

Look into type tagging and value classes #644

dwijnand opened this issue Oct 12, 2016 · 9 comments
Labels

Comments

@dwijnand
Copy link
Collaborator

See the conversation in the typelevel/scala Gitter room on October 11, 2016 8:58 PM.

@AlecZorab
Copy link
Contributor

Welcome to Scala 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_91).
Type in expressions for evaluation. Or try :help.

scala> import shapeless._
import shapeless._

scala> import tag._
import tag._

scala> case class A(i:Int) extends AnyVal
defined class A

scala> trait Bar
defined trait Bar

scala> val a = A(1)
a: A = A(1)

scala> tag[Bar](a)
res0: shapeless.tag.@@[A,Bar] = A(1)

scala> Array(res0)
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
  ... 42 elided

scala> Array(tag[Bar](A(1)))
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
  ... 42 elided

scala> trait Baz extends Any
defined trait Baz

scala> Array(tag[Baz](A(1)))
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
  ... 42 elided

scala> val z = tag[Baz](A(1))
z: shapeless.tag.@@[A,Baz] = A(1)

scala> Array(z)
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
  ... 42 elided

We'd probably expect the Baz case to work.

@dwijnand
Copy link
Collaborator Author

It works for Vector:

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> :pa
// Entering paste mode (ctrl-D to finish)

type @@[T, Tag] = T with Tag

trait Tagger[Tag] { def apply[A](a: A): A @@ Tag = a.asInstanceOf[A @@ Tag] }

def tag[Tag]: Tagger[Tag] = new Tagger[Tag] {}

case class Foo(x: Int) extends AnyVal

trait Bar extends Any


// Exiting paste mode, now interpreting.

defined type alias $at$at
defined trait Tagger
tag: [Tag]=> Tagger[Tag]
defined class Foo
defined trait Bar

scala> Vector(tag[Bar](Foo(1)), tag[Bar](Foo(2)))
res0: scala.collection.immutable.Vector[@@[Foo,Bar]] = Vector(1, 2)

@AlecZorab
Copy link
Contributor

AlecZorab commented Oct 12, 2016

https://github.com/milessabin/shapeless/blob/ab081796c183530efdd8b29dab8fee1fee7c61f9/core/src/main/scala/shapeless/typeoperators.scala

Tagged uses a slightly different merchanism. This appears to work:

Welcome to Scala 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_91).
Type in expressions for evaluation. Or try :help.

scala> object tag {
     |   def apply[U] = new Tagger[U]
     | 
     |   trait Tagged[U] extends Any
     |   type @@[+T, U] = T with Tagged[U]
     | 
     |   class Tagger[U] {
     |     def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U]
     |   }
     | }
defined object tag

scala> case class A(i:Int) extends AnyVal
defined class A

scala> val a = A(1)
a: A = A(1)

scala> trait Bar
defined trait Bar

scala> trait Baz extends Any
defined trait Baz

scala> Array(tag[Baz](a))
res0: Array[tag.@@[A,Baz]] = Array(1)

scala> Array(tag[Bar](a))
res1: Array[tag.@@[A,Bar]] = Array(1)

Though I've no idea how to check if those are Arrays of Int or Object underneath

edit:

scala> :t res1
Array[tag.@@[A,Bar]]

scala> res1.getClass
res2: Class[_ <: Array[tag.@@[A,Bar]]] = class [I

So even when the trait we're tagging with doesn't extend Any, it stays as an int

@dwijnand
Copy link
Collaborator Author

Yes, looks like Tagged needs to be a universal trait to not explode at runtime when the type T is a value class.

@AlecZorab
Copy link
Contributor

Any idea what the story is with universal traits and binary compatibility? I'm not sure whether we can change that in 2.3.X or not

@dwijnand
Copy link
Collaborator Author

dwijnand commented Oct 12, 2016

I agree with your suspicion - I would assume it's not a compatible change and would want to see proof that it actually is :D

@milessabin
Copy link
Owner

The tag is supposed to be erased, so I think there's a fair chance we can get away with this change ... could someone give it a try and attempt to confirm via MiMa?

@milessabin
Copy link
Owner

FTR, the issue I was remembering was #44. It looks as though I didn't consider the possibility of having Tagged extend Any, and thought that the only way to proceed would be to revert #20.

@lJoublanc
Copy link

Would this extend to shapeless.labelled.field? I'm seeing similar issues when trying to create records. Posted on gitter https://gitter.im/milessabin/shapeless?at=5ae890ccb37eab7d045bef1e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants