In Julia type names start with uppercase by convention. If use two or more words name we use CamelCase. This is very important. This convention is like in Java, except that in Java only classes start with capital letters. Native types do not.
This program paradigm is used in traditional languages: Fortran, Ada, C, C++, Pascal, Java, Level. The static typing require all variables to be declared before use. Declaration consist of a variable or argument name and type. If the type of the variable is not native type it has to be defined before the variable can use it.
This programming paradigm was created as reaction to rigid typing used in imperative languages. It was considered a “waste of time” to declare and maintain all the variables before use. In dynamic typing we allow the use of a variable before declaration. The type is created at run-time and can be changed in the same scope.
Dispatch technique is the capability of a language to allow creation of polymorphic functions or methods. This is a function that can act on different argument types. In Julia we can create multiple versions of the same function for each argument type or combination of types. These sub-functions are called methods.
A function can have parameters with no type. In this case a dispatch is not possible and the arguments will have type “Any”. The function has only one method. To make dispatch possible we must use a type annotation for one or more arguments using two column symbol “::” that is named “is an instance of type …”.
In multiple dispatch we use all parameters to identify a method. In Object Oriented programming single dispatch is used. Only one parameter is used to identify a method. The methods are attached to the first argument that is the type. In Java this parameter is invisible (default) and is the current object “this”. In python this parameter is called “self”. In Julia we do not have a similar default parameter.
Before we can use multiple dispatch we have to understand the types. Once we define types we can create multiple methods for these types. Therefore in Julia types are the corner stone of Julia language. Is the foundation Julia philosophy.
The :: operator can be used to attach type annotations to expressions and variables in programs. There are two primary reasons to do this:
- As an assertion to help confirm that your program works the way you expect,
- To provide extra type information to the compiler, which can then improve performance
This function will always return Float64 even if x and y are integers. A function convert() is used to convert the result.
# example of a function that have a result type
function sum(x, y)::Float64
return x + y
In Julia types are organized like a tree. This tree is an abstract structure based on inheritance. One type can be derived from another type. The root type is called “Any”. There is a specific operator “sub-type of” <: used to specify the parent of a type. If the parent is not specified the parent is Any.
There are two categories of types:
- Abstract Type
- Concrete Type
Abstract Type is a node in the tree and can’t be instantiated.
# Examples of abstract types:
abstract type Number end
abstract type Real <: Number end
abstract type AbstractFloat <: Real end
abstract type Integer <: Real end
abstract type Signed <: Integer end
abstract type Unsigned <: Integer end
Julia define primitive types as concrete types based on a number of bits. These types are predefined. The syntax is simple and can be used to define your own primitive types for a specified number of bits.
primitive type type_name [<: super_type] number_of_bits end
In the previous syntax <: super_type can be missing from the declaration That means Any is the super-type.
# Examples of primitive types:
primitive type Float16 <: AbstractFloat 16 end
primitive type Float32 <: AbstractFloat 32 end
primitive type Float64 <: AbstractFloat 64 end
primitive type Bool <: Integer 8 end
primitive type Char 32 end
primitive type Int8 <: Signed 8 end
primitive type UInt8 <: Unsigned 8 end
primitive type Int16 <: Signed 16 end
primitive type UInt16 <: Unsigned 16 end
primitive type Int32 <: Signed 32 end
primitive type UInt32 <: Unsigned 32 end
primitive type Int64 <: Signed 64 end
primitive type UInt64 <: Unsigned 64 end
In other languages we have records or structures. Julia uses keyword “struct” to create composite types. By default a “struct type” is immutable. To create a mutable struct we use keyword “mutable”. So it is easy to remember. Immutable structs are more efficient but can’t be changed after initialization. Mutable struct can have it’s member changed.
# Example of composite type
mutable struct Person
# We create an instance of Person
person = Person("John","Doe",25)
To create a struct instance we need to use a constructor. The constructor name is the struct name. This is automatically created and is available for use with parameters. We do not use New keyword like in Java and Python. Simple use the name of the struct as constructor.
This is similar to “generics” in Java. We can define a composite type that have members of a variable type. We do not know the type until is used. This allow us to create meta structures. The use of parametric types is very advanced topic and complex. Be prepared to learn more about it.
# create a parametric type
# create a sub-type of parametric type
julia>point = Point(1.0,2.1)
This will create an object point with coordinates of type: Float64
See also: Julia Manual:Types