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

implicit disaster: typetag reifies type param instead of type argument #5884

Closed
scabug opened this issue Jun 5, 2012 · 17 comments
Closed

implicit disaster: typetag reifies type param instead of type argument #5884

scabug opened this issue Jun 5, 2012 · 17 comments
Assignees
Milestone

Comments

@scabug
Copy link

@scabug scabug commented Jun 5, 2012

I spent a good half a day trying to work out a VerifyError, which I eventually tracked back to this:

scala> def f[QVC: ClassTag] = typeTag[QVC]
f: [QVC](implicit evidence$1: ClassTag[QVC])TypeTag[QVC]

scala> f[List[Int]]
res0: TypeTag[List[Int]] = TypeTag[QVC]

I sure hope it's intended to act like this:

scala> def f[QVC: TypeTag] = classTag[QVC]
<console>:7: error: No ClassTag available for QVC
       def f[QVC: TypeTag] = classTag[QVC]
                                     ^
@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@paulp said:
I see from reading "ErasureTag vs ClassTag and TypeTag vs ConcreteTypeTag" that this is expected. I hope this behavior will be reconsidered.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@xeno-by said (edited on Jun 5, 2012 5:13:18 PM UTC):
Yep, this is by design, since you might want to reify a complex type that has a teeny-tiny reference to an unresolved type parameter. In that case this behaviour is useful.

But overall this typetag business is annoying. Especially since right now TypeTags are easy-to-type and referred by everyone involved, so they almost whisper to a newcomer "write me, write me, I'm simple and popular, come on". Your problem would have been solved if you used ConcreteTypeTags, though, but that's a mouthful, and who wants to type more.

However we plan to address this problem by renaming TypeTag into AbsTypeable and ConcreteTypeTag into Typeable. Then TypeTag will become an odd one, which will nicely fit its surprising nature.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@paulp said:
"Your problem would have been solved if you used ConcreteTypeTags..."

Understand that I wasn't using anything. I changed a method from using typetags to classtags - or so I thought. (So I was trying NOT to use type tags.) The reason I use a typesafe language is so if I make a mistake like that, it will be caught by the compiler. It doesn't help to give it a different name.

We have two things with similar, overlapping purposes, and if you put one where you mean the other, not only does everything still compile, but the manifestation of the problem is a million miles away. Really, a VerifyError in the scala.reflect package object which silently freezes startup and which only happens under select circumstances is not how I want to find out about what should be a static typing error.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@paulp said:
"Yep, this is by design, since you might want to reify a complex type that has a teeny-tiny reference to an unresolved type parameter. In that case this behaviour is useful."

Do we not see that the audience for reifying unresolved type parameters is such a small fraction of the audience for reifying the actual explicit type argument that it is lost in the noise. To have a trap like this in place, in the default scope, on the basis that it's useful for that tiny audience... it is emblematic of the most common criticism of scala.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@xeno-by said:
Makes sense. If anyone wants to reify non-ground types, it is possible to write a macro for that. I'll bring up this issue on the next reflection meeting. Thanks for putting this in perspective, Paul!

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 5, 2012

@paulp said:
Always glad to put things in perspective. Thanks for taking it as intended.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 7, 2012

@xeno-by said:
Unfortunately, there's one more aspect to this problem. Macros themselves need type tags to represent incoming type arguments, so that macro implementations can be polymorphic. And macros do need to work with non-ground types. So it seems that we need both TypeTags and AbsTypeTags.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 7, 2012

@paulp said:
The question isn't whether they should exist, but what should happen by default when someone uses the obvious name. A default which silently offers such dangerously different behavior between "def f[T] = typeTag[T]" and "def f[T: TypeTag] = typeTag[T]" is the kind of thing which would literally cause me to find another language. And I'm a fan. I hate to think how someone who was already conflicted might react.

If you leave it like this, just don't say later nobody saw it coming.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 7, 2012

@paulp said:
To properly appreciate this example, put a couple thousand lines of code and/or inheritance from elsewhere between the implicit definition of tag and the method.

scala> class Foo[T](implicit tag: TypeTag[T]) { def bippy = typeTag[T] }
defined class Foo

scala> (new Foo[List[Int]]).bippy
res0: TypeTag[List[Int]] = ConcreteTypeTag[List[Int]]

scala> class Foo2[T](implicit tag: TypeTag[T]) { def bippy = { val tag = "bippy" ; typeTag[T] } }
defined class Foo2

scala> (new Foo2[List[Int]]).bippy
res1: TypeTag[List[Int]] = TypeTag[T]
@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 7, 2012

@xeno-by said (edited on Jun 7, 2012 4:31:11 PM UTC):
I'd argue that using an AbsTypeTag (this is how it will be named in M4) is not very obvious. To further discourage widespread use, implicit incantations for summoning type tags will only work with concrete type tags.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 7, 2012

@paulp said:
"implicit incantations for summoning type tags will only work with concrete type tags."

So does that mean my original example (and the one in the comment) will be compile time errors?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 7, 2012

@xeno-by said:
Yes, exactly.

Of course, if you replace all TypeTag[T] with AbsTypeTag[T] and typeTag[T] with implicitly[AbsTypeTag[T]], then you will observe the bug that you described.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 8, 2012

@paulp said:
I can live with that then. I'm not sure AbsTypeTag is the ideal name, especially since "ConcreteTypeTag" is spelled out, and Abstract and Concrete have the same number of letters.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 8, 2012

@xeno-by said:
ConcreteTypeTag was a real mouthful, and it didn't have a good contraction. Also it wasn't supposed to be used widely, whereas AbsTypeTag will be used in a lot of macros.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 8, 2012

@paulp said:
I should also point out that "AbsXXX" is used as a name in six other places in the reflection library. In 6/6 it means "an abstract class which is extended by something else." Here you are using "Abs" for the concrete class in regards to what it represents rather than in reference to what it is. It is a naming category error to mix them.

It isn't as if "Abs" is unambiguous, either. One can easily imagine an "absolute type tag" for instance, in contrast to a "relative" one which requires a prefix. An absent type tag, an absurd type tag... we have the means to alias long names. AbsTypeTag is still too long for me if I care about the length at all, so I'd have to alias it anyway. Why not let me alias from a name which doesn't require still more decoding.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jun 9, 2012

@xeno-by said:
Naming needs additional thinking, I agree.

However, as of scala/scala@5acac4d the root cause of the problem is fixed, so I close this bug.

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

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.