# Why isn't this type signature allowed?

Given that functions `f`, `g`, and `h` all work, why isn’t function `i` allowed?
Shouldn’t `i` work like an alias for `g` just like `h` does?

``````x = 1
y = 0.1
function f(x::Number, y::Number)
return "This is function f."
end
function g(x::T1 where T1<:Number, y::T2 where T2<:Number)
return "This is function g."
end
function h(x::Vector{<:Number}, y::Vector{<:Number}) # Call with h([x], [y])
return "This is function h."
end
function i(x<:Number, y<:Number)
return "This is function i."
end
``````
``````ERROR: syntax: "x <: Number" is not a valid function argument name
``````
1 Like

It’s unclear if you’re referring to the type of the argument, or if the type is the argument

1 Like

Is that different from `h`? I could have a vector of types.

A `Vector{<:Number}` is a vector of values, each of which is a `Number`. It’s not a vector of types

For me (even in reading) it is not clear for this whether you mean that `x` is a type that inherits from number or a variable of a type that inherits from number.

edit: To be more precise, you could pass `x=Float64` in there, which is one way to read your definition, but since it is not clear what you mean (informally reading it for me it does not get clear at least, but the compiler also complains)

I do see two solutions with different goals. You probably meant

``````function i(x::T, y::S) where {T<:Number, S<:Number}
return "This is function i."
end
``````

that is x and y are some kind of numbers (informally said).
This is basically your `g` just that the scope of the `T` and `S` is a little larger, because you could also do

``````function i(x::T, y::T) where {T<:Number}
return "This is function i."
end
``````

which would say they are some kind of number, but the same.

Yup, this is the crux – `x::T` works when `x` are values, `x<:T` works for types `x` (of course any `x` can be both a value and type, but the operator gives context then). Function arguments are always treated as values, so you can’t `<:` them.

4 Likes

In that case, you can use

``````function h(x::Vector{Type{<:Number}}, y::Vector{Type{<:Number}})
return "This is function h."
end
``````

Interestingly, this will fail:

``````julia> h([Int], [Float32])
ERROR: MethodError: no method matching h(::Vector{DataType}, ::Vector{DataType})
``````

because

``````julia> typeof([Int])
Vector{DataType}
``````

You have to enforce the eltype:

``````julia> h(Type{Int}[Int], Type{Float32}[Float32])
"This is function h."
``````

Similarly, `i` could be

``````function i(x::Type{<:Number}, y::Type{<:Number})
return "This is function i."
end
``````
2 Likes

I’m starting to get it.
`f` just doesn’t seem like it should work to me. `x` is not a `Number` it is an `Int` which is a subtype of `Number`. Thus I want to indicate that with `x<:Number` just like in `h`.

Also, DNF showed that you have to explicitly write `Type` whenever you want to operate on types themselves, so the type vs value argument seems clear regardless.

But `x` is a `Number`:

``````julia> 1 isa Number
true
``````

That is how subtype relationships work. For any value of type `T`, that value is also belongs to the supertypes of `T`:

``````julia> isa.(1, (Int, Signed, Integer, Real, Number, Any))
(true, true, true, true, true, true)
``````
1 Like

I see. So the Vector equivalent to `f` is `j`:

``````function j(x::Vector{Number}, y::Vector{Number})
return "This if function j."
end
``````
``````julia> j(Vector{Number}([x]), Vector{Number}([y]))
"This if function j."
``````

Almost, but not quite. Due to type in variance, `Vector{Int}` is not a subtype of `Vector{Number}`. The equivalent is

``````function j(x::Vector{<:Number}, y::Vector{<:Number})
return "This if function j."
end
``````

Yes, I do know that fact and have it as function `h`. Although I guess I don’t fully understand since `j` works as I expected but `k` doesn’t:

``````struct MyType{T<:Number}
x::T
end
function k(x::Vector{MyType{<:Number}})
return "This is function k."
end
``````
``````julia> k([MyType(x)])
ERROR: MethodError: no method matching k(::Vector{MyType{Int64}})
Closest candidates are:
k(::Vector{MyType})
``````

Try

``````function k(x::Vector{<:MyType{<:Number}})
``````
1 Like

You can also write

``````function k(x::Vector{MyType{T}}) where {T<:Number}
``````

I was a bit surprised, because I though that `Vector{MyType{<:Number}}` was the same as `Vector{MyType{T}} where {T<:Number}`. But it turns out to be a tiny bit different:

``````julia> Vector{MyType{<:Number}} === Vector{MyType{T}} where {T<:Number}
false

julia> Vector{MyType{<:Number}} === Vector{MyType{T} where {T<:Number}}
true
``````

The difference is the location of the closing `}`s.

1 Like

Yes, but why?
What is the full identical equivalence for this form?

I don’t see how that would make a functional difference. The `where` defines `T` the same either way, and the `where` location doesn’t matter in this case from the documentation:

A correct way to define a method that accepts all arguments of type `Point{T}` where `T` is a subtype of `Real` is:

``````function norm(p::Point{<:Real})
sqrt(p.x^2 + p.y^2)
end
``````

(Equivalently, one could define `function norm(p::Point{T} where T<:Real)` or `function norm(p::Point{T}) where T<:Real`; see UnionAll Types.)

Or, more semantically, whether the vector has to contain elements of the same `MyType` which all are constrained to the same `T<:Number`, or whether the vector can contain different `MyType`, possibly with different `T` (each of which is still constrained to be `<:Number`).

1 Like

The case you quote from the docs is not the same, because that only has one level of type parameters.

Ah, thanks. That makes sense.

The shorthand version from Gunnar doesn’t equal the longhand version from DNF though. What does it expand to?

``````julia> Vector{<:MyType{<:Number}} === Vector{MyType{T}} where {T<:Number}
false
``````

Also, how can these all be true?

``````julia> isconcretetype(Vector{MyType})
true

julia> isconcretetype(Vector{MyType{Int}})
true

julia> isconcretetype(Vector{MyType{<:Number}})
true
``````

(This one is false: ` isconcretetype(Vector{<:MyType{<:Number}})`.)

At least we have

``````julia> (Vector{MyType{T}} where {T<:Number}) <: Vector{<:MyType{<:Number}}
true
``````
1 Like