Inconsistent use of type parameters?

struct A{T}
nothing
end

Can we use the name A without a parameter?
julia> A
A

Yes, how about with a type parameter?
julia> A{Int64}
A{Int64}
no problem. But:

function b{T}(x::T)
return x
end
b (generic function with 1 method)

Name ‘b’ without parameter?
julia> b
b (generic function with 1 method)
yes, but
julia> b{Int64}
ERROR: TypeError: Type{…} expression: expected UnionAll, got #b
Stacktrace:
[1] macro expansion at ./REPL.jl:97 [inlined]
[2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73

Naming the function with a type parameter gives a (strange!) error
Seems inconsistent to this naive user, and the message seems mysterious.

I agree that this can be confusing. Fortunately, Julia v0.6 introduces a new syntax for b:

function b(x::T) where T
  return x
end

which no longer (incorrectly) implies that you could write b{Int}.

1 Like

To expand on this a little, in Julia there are two types of constructors

  • Inner: these accept type parameters (i.e. the arguments in the {}) and are declared inside the type declaration. i.e. they are called like XType{T}(args...)
  • Outer: these do not take any type parameters and are declared outside of the type declaration. i.e. they are called like XType(args...).

This seems quite confusing at first, but is actually quite useful as it is helpful to be able to declare either type of constructor. However, like @rdeits pointed out, there is now an additional syntax available for sorting this out.

The only “inconsistency” is that we don’t allow explicitly specifing the type parameters for a method. And that’s also related to that type cannot be overload but functions can.

2 Likes