Hi Stefan, Toivo. Thanks for joining the discussion.
Toivo you are on point. Having though more on the matter, I think the right to describe the sitution is a s follows. Suppose we have two immutable types whose data layout is exactly the same, their behavior is exactly the same, and the only difference between them is their invariant which is enforced through two different constructors. In this case, I think it would be wrong to hide this information both from the compiler, and from other programmers. Even though I'm no expert in compilation, seems to me that providing this additional information about the type equivalence to the compiler can only benefit the optimization that happen under the hood. Second, from the programmer perspective, I would say that emphasizing that two types are only different in their constructors increases code readiability. For someone whose reading the code, having one less type to remember makes things easier. It makes the type hierarchy more parsimonious.
From an information theoretic perspective, defining two different types in case denies any reciever of the code (compiliers or other programmers) the fact that they are equivanlent. I cannot see any way how this could be beneficial.
In practice, I think the right way to go about this is to define a single type, and have few overloaded constructors. In Julia, this can be achieved by adding another parameter of value type. The only problem with this solution is that this makes the constructor a little more cumbersome to use. To overcome this, I can see two solutions. The first, which I like less, is to have a constructor alias. In this case, Julia would know to associate other constructors with the type, thus, allowing the use of <:, or any other method that operates on datatypes with the other constructors. The second solution, which I prefer, is adding or changing type aliases to type references. The problem with type aliases is that they merely provide shorthand notation, which I assuming, is removed by the Julia parser. If on the other hand, one could define a type reference which would indicate that the new type has exactly the same data layout as another type, but allowing the dispatch system to distiguish between the two types in terms of method calls, then this situation would have a great solution. The code in case would look like,
immutable SomeType
value::Int
end
typeref SomePositiveType SomeType
function SomePositiveType(value::Int)
if value < 0
error("value must be positive")
end
SomeType(value)
end
typeref SomeNegativeType SomeType
function SomeNegativeType(value::Int)
if value > 0
error("value must be negative")
end
SomeType(value)
end
If type references were an option, following the last discussion, then my answer to Tim and Stefan would be yes. Int, UInt, and Float64 should all be type references to a more basic type, maybe Number64.
Uri