Types and arguments

I have a doubt. Sorry if is very obvious. First: is the type specification used as a cast? For example, if f receives a real number as argument, is

a=2
f(a::Real) 

doing a type conversion? And a second doubt is: can’t I specify an argument as a subtype of others?

g(z<:Integer, x<:AbstractFloat)

No. All objects in julia have a concrete type, there is no conversion happening.

If you don’t need the actual type of z in the function, this is just g(z::Integer, x::AbstractFloat) . You can call this with any object whose type is a subtype of integer (like Int8 , for example) in the first argument, and any object whose type is a subtype of AbstractFloat (like Float16, for example) in the second argument.

If you need direct access to the type of an object, you can also use g(z::I, x::F) where {I <: Integer, F <: AbstractFloat}. This allows you to use I and F (the types of each argument) directly in the function.

6 Likes

tbf, type annotations do cause conversions in different contexts, and it takes some reading to grok what they do where. It might be understandably confusing that the annotations in the definition function f(a::Real) ... end and the call f(a::Real) don’t do the same things at all, and it’s worth making that distinction in method signatures for newcomers. The wording “cast” makes me think there might be an expectation borne from experience in another language, but I can’t recall a language that annotates arguments at call sites often.

If you define a function double foo(double x) in C or C++, and call it with an integer argument ala foo(1), the language will automatically cast it to double.

Whereas if you define a method foo(x::Float64) = ... in Julia, it will only accept Float64 arguments, and trying to call foo(1) (or any other numeric type) will throw a MethodError (unless another foo method exists for that type).

Argument-type declarations in Julia are best thought of as “filters” — saying what arguments are allowed for that method — rather than as directions on how to compile the code. If you define foo(x::Real) = ..., then it will accept any subtype of Real as an argument (integers, floating-point, rationals, …), but the compiler will still generate specialized code for each concrete argument type that you call foo with.

See also Argument-type declarations in the Julia manual.

3 Likes

I read the post as the call being foo(a::Real), which is a type assertion (not conversion) prior to the call, but I think I misread that now.

It’s also probably worth pointing out that concrete (instantiable) types in Julia do not subtype each other, so they only subtype (and supertype a few special) abstract types. Conversions with a target abstract type cannot result in an instance of an abstract type, but some concrete subtype convert(Real, 1) == 1.