0

In Scala, during type erasure, the generic variable is replaced by 'Object' type wherever the generic variable appears in type position.

E.G: val x T; --> is replaced by val x Object;

Due to this, the details of exact type which is passed, will become unavailable during runtime.

To overcome this (to get the exact type during runtime), it is mentioned that ClassTag will help us.

Can you please help me how ClassTag gets the type information during runtime ?

When ClassTag is mentioned , that is also written with a generic type in context bound.

E.G: def method[T:ClassTag] {...}

So I think, the 'T' mentioned here too, will be erased. But ClassTag somehow keeps the type info. I am bit puzzled how this works.. (similarly TypeTag and WeakTag as well)

user3103957
  • 636
  • 4
  • 16
  • 3
    Do you know that context bound is actually syntactic sugar for `(implicit evidence ClassTag[T])`? Do you know how a Scala type class works? – jwvh Aug 19 '21 at 04:31
  • 1
    Start by learning about implicits, and then this question will likely answer itself. – Silvio Mayolo Aug 19 '21 at 04:40
  • @jwvh, yes I am aware of implicits and context bound is the syntactic sugar of the implicit. But not sure how the erasure process spares the T in the context bound. – user3103957 Aug 19 '21 at 05:11
  • @user3103957 because implicits are resolved by the compiler at compile time when the compiler still has all the types & classes information about all values, that is how it can generate a `ClassTag` instance for the type in question. At runtime, when those types are lost the `ClassTag` value injected by the compiler will allow you to tell what was the expected class of that value. – Luis Miguel Mejía Suárez Aug 19 '21 at 12:38
  • @LuisMiguelMejíaSuárez This would be better as an answer, not a comment, I think. – Alexey Romanov Aug 19 '21 at 22:55
  • @Luis, thanks for your time and much clearer reply! Even during the compile time, T is not known by the compiler. Isn't it ? – user3103957 Aug 22 '21 at 08:39
  • And also could you please let me know whether my understanding of T being replaced by Object type (during compile time) is not correct ? – user3103957 Aug 22 '21 at 08:50
  • @user3103957 if it isn't known by the compiler then when and who knows what `T` is and how would type checking work? If the compiler doesn't know something then you as a user will never know it _(unless you use unsafe runtime reflection but that is limited and a different story)_. - Also no, the `T` is not replaced by `Object` at compile-time, or at least not during type checking the erasure is a runtime behavior that is evidenced during the bytecode generation which is the latest stage of the compiler. – Luis Miguel Mejía Suárez Aug 22 '21 at 14:46
  • Thanks @Luis for the elaborated reply. It seems that type erasure is more complicated than how I understand. This link has more information - https://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens – user3103957 Aug 22 '21 at 18:00
  • Actually when I started to looking for articles on ClassTag, many pointed out tot this link - https://medium.com/@sinisalouc/overcoming-type-erasure-in-scala-8f2422070d20 This states that T is replaced by Object during type erasure. – user3103957 Aug 22 '21 at 18:03

1 Answers1

3

This is not correct:

E.G: val x T; --> is replaced by val x Object;

The type of x is not lost; you can look at the value of x at runtime and determine what type it is. Objects retain their runtime type.

Type erasure affects values of a parameterised type Y[T]. The runtime holds a single type for an object so it cannot hold T as well as Y and "erases" T from the type. If I have an instance of Y[T] I can tell at runtime that it is type Y but cannot tell which T it was parameterised with. Thus I can distinguish List[T] from Vector[T] but cannot distinguish List[T] from List[U]. But an element of that List retains its type and can be matched against T or U. And a member val x: T can be matched directly to determine the type of the object.

A ClassTag is value that represents a type, so if you store the ClassTag of T in your object then you can match that to work out the type of T without having to look at any of the values of type T inside the object. You are explicitly storing the type information for T that was previously erased.

[ Useful discussion in the comments about this really being about classes rather than types ]

Tim
  • 26,753
  • 2
  • 16
  • 29
  • 1
    There is no such thing as runtime type, there are no types at runtime; there are only classes _(and just if we focus just on the **JVM**, no idea how **V8** or the custom runtime of **ScalaNative** handle those things)_. - Also, `ClassTag` is a value that represents a class, not a type, that is why it will only know about `List` but not `List[Foo]` – Luis Miguel Mejía Suárez Aug 19 '21 at 12:36
  • This answer is in line with common usage of "type" and "run time type information"(RTTI). `match` in Scala is said to match on *type* (which would not possible if there were no types at runtime), and even the Wikipedia article on the JVM says "The class loader [] finds and imports the binary data for a *type*" (emphasis mine). – Tim Aug 19 '21 at 13:28
  • 1
    Uhm after spending some time googling I am actually more confused, some people claim **Java** does not have RTTI _(and actually said that is a **C++** thing)_ while others say it does, but I couldn't find any official source for neither. The [**erasure** docs](https://docs.oracle.com/javase/tutorial/java/generics/erasure.html) have a wording that gives the impression that at runtime there are only classes and interface. On the other hand the [**jvm** docs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html) mention that there are different types, where references are one of those.. – Luis Miguel Mejía Suárez Aug 19 '21 at 14:41
  • 1
    But, it was not clear for me if then all reference values share the same single type and are differentiated using its class, of each class creates its own type. Moreover, the [**classloading** docs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html) initially said that it can only load classes and interfaces but then it starts to use the term type for other things like methods. Nevertheless the [**instruction set** docs](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.checkcast) mention that `checkcast` / `isinstanceof` checks the type of an object... – Luis Miguel Mejía Suárez Aug 19 '21 at 14:44
  • 1
    But then the rules for the checks mention again about classes and interfaces. Similarly to the [**pattern matching** docs](https://www.scala-lang.org/files/archive/spec/2.12/08-pattern-matching.html#type-patterns) which talks about type tests, but the rules are explicit about runtime classes and erasure. Finally, the [`ClassTag` docs](https://www.scala-lang.org/api/current/scala/reflect/ClassTag.html) are clear that they provide information about the runtime class not about compile-time types. - In conclusion, all I can say is that I was wrong, the term runtime types do exist... – Luis Miguel Mejía Suárez Aug 19 '21 at 14:47
  • 1
    However, I am still not sure if its usage in the answer is correct, IMHO it would be clearer to talk about the runtime class. - In any case, this seems to be a case where we _(here referring to the whole programming community)_ were never strict enough with the terms and their distinctions which resulted in a common interchange of its usages. - Anyways, it was fun to read all that, hope the summary and links are also useful / interesting for you and other readers :) – Luis Miguel Mejía Suárez Aug 19 '21 at 14:50
  • 3
    I do take your point and I agree with the underlying technical reality of the confusion between class vs type. In the end it was a judgement call to say "type" rather than "class" but could easily have gone the other way. – Tim Aug 19 '21 at 15:15