Julia’s type system is unique. Julia behaves as a dynamically-typed language (such as
Python for instance) most of the time. This means that a variable bound to an integer at
one point might later be bound to a string. For example, consider the following:
julia> x = 10
10
julia> x = "hello"
"hello"
However, one can, optionally, add type information to a variable. This causes the variable
to only accept values that match that specific type. This is done through a type annotation.
For instance, declaring x::ASCIIString implies that only strings can be bound to x; in
general, it looks like var::TypeName. These are used most often to qualify the arguments a
function can take. The extra type information is useful for documenting the code, and
often allows the JIT compiler to generate better optimized native code. It also allows the
development environments to give more support, and code tools such as a linter that can
check your code for possible wrong type use.
Here is an example: a function with the calc_position name defined as the function
calc_position(time::Float64), indicates that this function takes one argument named
time of the type Float64.
Julia uses the same syntax for type assertions that are used to check whether a variable or
an expression has a specific type. Writing (expr)::TypeName raises an error if expr is not
of the required type. For instance, consider the following:
julia> (2+3)::ASCIIString
ERROR: type: typeassert: expected ASCIIString, got Int64
Notice that the type comes after the variable name, unlike in most other languages. In
general, the type of a variable can change in Julia, but this is detrimental to performance.
For utmost performance, you need to write type-stable code. Code is type-stable if the
type of every variable does not vary over time. Carefully thinking in terms of the types of
variables is useful in avoiding performance bottlenecks. Adding type annotations to
variables updated in the inner loop of a critical region of code can lead to drastic
improvements in the performance by helping the JIT compiler remove some type
checking. To see an excellent example where this is important, read the article available at http://www.johnmyleswhite.com/notebook/2013/12/06/writing-type-stable-code-in-julia/.
A lot of types exist, in fact, a whole type hierarchy is built in in Julia. If you don’t specify
the type of a function argument, it has the type Any, which is effectively the root or parent
of all types. Every object is at least of the universal type Any. At the other end of the
spectrum, there is type None that has no values. No object can have this type, but it is a
subtype of every other type. While running the code, Julia will infer the type of the
parameters passed in a function, and with this information, it will generate optimal
machine code.
You can define your own custom types as well, for instance, a Person type. By
convention, the names of types begin with a capital letter, and if necessary, the word
separation is shown with CamelCase, such as BigFloat or AbstractArray.
If x is a variable, then typeof(x) gives its type, and isa(x, T) tests whether x is of type
T. For example, isa("ABC", String) returns true, and isa(1, Bool) returns false.
Everything in Julia has a type, including types themselves, which are of type DataType:
typeof(Int64) returns DataType. Conversion of a variable var to a type Type1 can be
done using the type name (lower-cased) as a function type1(var), for example,
int64(3.14) returns 3.
However, this raises an error if type conversion is impossible as follows:
julia> int64("hello")
ERROR: invalid base 10 digit 'h' in "hello"
』