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

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