Do I need to specify concrete type of a variable such as Int64 or just Int, Float64 or just Float?

In Julia, do I need to really set very specific and concrete type of the variable?
Like,

i::Int64

or

i::Int

and

x::Float

or

x::Float64

Is there performance difference?
Or, like, is it just using Int and Float is enough, and no need to particular do Int64 and Float64?

Thanks!

On a 64-bit platform, Int is just another name for Int64. There is no Float. However, often the types can be inferred and don’t need to be annotated at all.

6 Likes

If I want to enforce say integers in a function call, is it better to restrict the types on which the function can be called, or to throw an particular error:
option 1:

function f1(n::Integer) = n + 1

option 2:

function f2(n)
    typeof(n) <: Integer || throw(error("error"))
    n + 1
end

@amrods It is better to use the type parameter in the signature.

4 Likes

Almost never, and almost certainly not in the cases you’re thinking of.

On 32 bit platforms, Int refers to Int32. On 64 bit platforms, Int refers to Int64. There is no equivalent shorthand for floating point numbers.


For variables, type assertions limit the type of that binding in the current scope to the asserted type.

For function arguments in function definitions, type assertions restrict the allowed incoming types for that argument.

For struct fields, type assertions signify that the field in question holds a value of the asserted type. The default constructors will try to convert incoming arguments to the types in question.

For more information, see the section on type declarations in the docs.

2 Likes

Have a look at Stefan’s answer here

1 is an Int64, so may want

function f1(n::Integer) = n + one(n) 

instead.

3 Likes

The answer strongly depends on the context the type annotation is used in.

Function signatures

Annotating argument type makes no performance difference, but adds dispatch methods. The general recommendation is to use concrete types in function signatures only for dispatch, and use a possibly loose type bounds otherwise to keep the functions generic. In translating code from Fortran, I’d recommend using Integer and Real type annotations for the beginning to easier keep track what is what.

Variable declaration within functions

Usually type declaration is redundant but you need to watch for type stability for performance. Sometimes, a nudge to the type inference algorithm may be useful, though. For performance, the types must be concrete or small unions.

Structure type members

Concrete types are absolutely crucial for performance.

Type parameters / generics

The advises on how to annotate function argument types and local variable types are contradictory. So, you may go without any type annotations for local variables (what’s usually done anyways) or, if you feel uneasy about it, you could use types as parameters in signatures and function body (if you continue using Julia, you’ll need to learn it in any case, so this is just one of many examples)

# Bad: input type is too tight
function cube(x::Float64)
    local square::Float64 = x * x
    return square * x
end

# Better but local variable type is too loose. 
# Does not help with type instabilities within the abstract type
function cube(x::Number)
    local square::Number = x * x
    return square * x
end

# Good: concrete type is parameterized.
# Function is now generic, and all local variable types are concrete.
# A drawback, of course, is that {T<:Number} is also too tight
# (it could include matrices, rotations, etc)
function cube(x::T) where {T<:Number}
    local square::T = x * x
    return square * x
end
6 Likes
function cube(x::Number) 
    local square::Number = x * x
    return square * x
end

What makes it too loose?

Note: 99% of the time, you don’t need to add a type parameter to local square::T. Julia will infer this just fine.

6 Likes

Turns out, abstract type annotations don’t stop the compiler from narrowing down the type, so it must be the same as untyped version performance-wise.
But it won’t catch type instabilities or inefficiencies within the abstract type annotation, if that was the intent.
I’ll edit my post accordingly, thanks for pointing that out.

2 Likes