Behaviour of nested alias type parameters

Hi all,

I am new to Julia and encountered a confusing result with nested where statements. However, I do not know if this is a bug or an intended (but ill-documented) behaviour. Here’s a snippet describing it:

julia> MyAlias{A,B} = Tuple{A,B} where {B,A}
Tuple{A,B} where A where B

julia> MyAlias{1,2}
Tuple{2,1}

I was expecting to get a Tuple{1,2}, as I thought that the only purpose of where was to annotate yet unknown parameters. Obviously, this is easily fixed by using parameters in the right order (where {A,B}), but still, it’s confusing.

This does not happen if I try to reproduce it with a function, so it might be a bug:

julia> myprint(::Tuple{A,B}) where {B,A} = print(A,B)
myprint (generic function with 1 method)

julia> myprint((1,1.0))
Int64Float64

I am using julia 1.0.0:

julia> versioninfo()
Julia Version 1.0.0
Commit 5d4eaca0c9 (2018-08-08 20:58 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin14.5.0)
  CPU: Intel(R) Core(TM) i5-4258U CPU @ 2.40GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, haswell)
Environment:
  JULIA_EDITOR = atom -a
  JULIA_NUM_THREADS = 2

The precedence of where is indeed confusing, though as I recall, other choices led to some pretty strange behavior in function declarations.

What you’re supposed to do in this case is

const MyAlias{A,B} = Tuple{A,B}

without the where. I agree this is confusing. It’s probably legacy from when there used to be a typealias keyword. Essentially the = operator is special for type aliases.

Note also that Tuple is special in that it is the only covariant type in the language.

I’m curious what opinion the core devs have on the lack of anything to indicate the fact that the type parameters are undefined variables lacking a where clause in these cases.

The A and B left and right of the = are not related (this is not a function-like thing):

julia> MyAlias{X,Y} = Tuple{A,B} where {B,A}                                                                                                                            
Tuple{A,B} where A where B                                                                                                                                              

julia> MyAlias{1,2}                                                                                                                                                     
Tuple{2,1}   

What you wrote above is equivalent to (note the switch):

julia> MyAlias{X,Y} = Tuple{A,B} where A where B                                                                                                                        
Tuple{A,B} where A where B                                                                                                                                              

julia> MyAlias{1}                                                                                                                                                       
Tuple{A,1} where A                                                                                                                                                      

And that is indeed reversed from the parameters in the type. Hmm, this wasn’t that clear, sorry.

2 Likes

Thanks a lot!

I did not realize that the where was not necessary in this case. It is indeed cleaner (and less error-prone) with this syntax.

There’s still some confusing stuff:

julia> Type1 = Tuple{A,B} where {A,B}
Tuple{A,B} where B where A

julia> Type2 = Tuple{A,B} where {B,A}
Tuple{A,B} where A where B

julia> Type1 == Type2
true

julia> Type1{1,2}
Tuple{1,2}

julia> Type2{1,2}
Tuple{2,1}

julia> Type1{1,2} == Type2{1,2}
false
1 Like

Yep, also this one:

julia> Type3{X,Y,Z} = Tuple{A,B} where {A,B}                                                                                                                            
Tuple{A,B} where B where A                                                                                                                                              

julia> Type3{2,3,4}                                                                                                                                                     
ERROR: too many parameters for type                                                                                                                                     
Stacktrace:
 [1] top-level scope at none:0

It looks like the parameters on the LHS are just ignored. Better would be to error if there are any parameters at all.

I filed issues Type alias defs can contain parameters but they are just ignored · Issue #29533 · JuliaLang/julia · GitHub and UnionAll comparison does not take order of parameters into account · Issue #29534 · JuliaLang/julia · GitHub. Thanks @balbasty!

1 Like