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