In Julia and programming languages in general, identity means the “same” instance that cannot be distinguished by any program; this is different than the colloquial sense of similarity. For example, we can distinguish “identical” twins by giving them differently colored hats. For a coding example, twin arrays [1] and [1] can be distinguished by mutating them to different values. In fact, separate instantiations of a mutable type always result in different instances by definition.
Back to your case, the T are not identical (===) despite having the same internal values because TypeVar is a mutable type, and equality (==) falls back to === by default:
Note that all the fields of TypeVar are const so we can’t reassign them; despite the effective inability to mutate them to different values, they are still distinguishable by memory address, and that is what === currently checks.
Ok, thank you for the clarification. I had mistakenly assumed that TypeVars were immutable. The const mutable implementation seems a very explicit way of defining them, which leads me to the followup question of: why do typevars need to be separated even at the instance level even when indicating the same parameter and bounds?
It’s easier to flip the question, when do you need the same TypeVar instance? When the same type parameter is shared by several places, like T in the line struct MyArr{T,N} and the line arr:Array{T,N} of the definition:
TypeVar identity is how Julia ensures both places get the same T value you specify per concrete type. Flipping back to your question, we thus need different instances for different type parameters that happen to share a name and bounds but can be specified with different values. That might have been doable with an immutable type if there was an additional field for identity, but everything has an address, might as well use it.