struct A{T}
end
const Dog = A{String}
const Cat = A{Int}
I have
julia> Dog
Dog (alias for A{String})
julia> Cat
Cat (alias for A{Int64})
But with this
struct A{T}
end
const Dog = A{String}
const Cat = A{Int}
const Giraffe = A{<:Number}
I have
julia> Dog
Dog (alias for A{String})
julia> Cat
A{Int64}
julia> Giraffe
Giraffe (alias for A{<:Number})
Why is Cat no longer an alias in the latter case? In my application, which is a bit more verbose, I want to have both Cat and Giraffe show as aliases. I use Giraffe for parameter annotations that occur many times in method definitions.
I don’t know why, but does it make any difference in practice? It seems that you can still use both as aliases for parameter annotations, don’t you?
You loose the pretty printing, apparently, is that it?
julia> x = A{Int}()
Cat()
julia> const Giraffe = A{<:Number}
Giraffe{var"#s1"} where var"#s1"<:Number (alias for A{var"#s1"} where var"#s1"<:Number)
julia> x = A{Int}()
A{Int64}()
Probably something related to the ambiguity (A{Int}() is a Cat or a Giraffe?). Removing it solves the problem:
julia> struct A{T} end
julia> const Cat = A{Int}
Cat (alias for A{Int64})
julia> const Giraffe = A{<:Union{AbstractFloat,Complex}}
Giraffe{var"#s1"} where var"#s1"<:Union{AbstractFloat, Complex} (alias for A{var"#s1"} where var"#s1"<:Union{AbstractFloat, Complex})
julia> A{Int}()
Cat()
julia> A{Float64}()
Giraffe{Float64}()
Yes, nothing has changed about the type, just the way it’s displayed.
But it is indeed an Alias, right? It is just a matter of printing.
Yes, absolutely. It’s, as far as I can tell, just a matter of printing. But, the printing is apparently all that distinguishes a type alias from any other binding with a const declaration; So in this sense, Cat above is no longer a type alias. In any case, I have a rather large package and the Cat alias is user facing. Having the printing depend on another variable binding seems fragile. Or maybe there is a good reason for it and I just can’t have what I want.
I’m inclined to agree with @sdanisch that this is unintentional.
I think it is, but consider that there is that ambiguity (A{Int}() is both a Cat and a Giraffe). Probably one would like that the alias referring to least general subtype is printed, but that has to be a decision that someone has to take.
Here is more unexpected behavior: Wrap the code above in a module. Then choose one of
export Cat, Dog, Giraffe
or
export Cat, Dog
Now, whether Cat prints as an alias depends on whether Giraffe appears in the export list. Importantly, it does not depend on whether I import (or using) any of Cat, Dog, or Giraffe. I can import any or all of the three. Or import none of them and refer to each of them by its fully qualified name. The alias status of Giraffe (when printing) only overrides that of Cat if both of them appear in the lists of exported symbols in the module.