Data types¶
The Julia language type system is dynamic, but at the same time it contains some of the advantages of static type systems, allowing you to specify that certain values belong to certain types.
There is no separation between object and non-object values: all values in Julia are true objects having a type belonging to one fully connected type graph, all nodes of which are equally first-class as types.
Below is a summary table comparing Engee and MATLAB data types.
| Type (Engee/MATLAB) | Number of bits | Lowest value | Highest value | |--------------------------|----------------|----------------------|-----------------------| | Int8 / int8 | 8 | -2^7 | 2^7 - 1 | | UInt8 / uint8 | 8 | 0 | 2^8 - 1 | | Int16 / int16 | 16 | 16 | -2^{15} | 2^{15} - 1 | | UInt16 / uint16 | 16 | 16 | 0 | 2^{16} - 1 | | Int32 / int32 | 32 | -2^{31} | 2^{31} - 1 | | UInt32 / uint32 | 32 | | 0 | 2^{32} - 1 | | Int64 / int64 | 64 | -2^{63} | 2^{63} - 1 | | UInt64 / uint64 | 64 | 0 | 0 | 2^{64} - 1 | | Int128 / no | 128 | -2^{127} | 2^{127} | 2^{127} - 1 | | UInt128 / no | 128 | 0 | 2^{128} - 1 | | Bool / logical | 8/1 | false(0) | true(1) | | Float16 / no | 16 | Half precision | Half precision | Half precision | | Float32 / single | 32 | Single | Single precision | Single precision | Single precision | | Float64 / double | 64 | Double precision | Double precision | Double precision | (Nifj or Qifj). | (Nifj or Qifj) / fi(i,x,n,m) | (min 8, max 64) / (min 1, max 1024) | Fixed-point number | Fixed-point number | Fixed-point number | Fixed-point number |
Type declarations¶
The ::
operator can be used to attach type annotations to expressions and variables in programs. There are two main reasons to do this.
- As a setup to help confirm that your programme works as you expect.
- To provide the compiler with additional type information, and in some cases this can improve performance.
When added to an expression that evaluates a value, the ::
operator reads "is an instance of".
(1+2)::Int
When added to a variable in the left-hand side of an assignment, ::
declares that the variable always has the specified type, similar to a type declaration in a statically typed language such as C.
function foo()
x::Int8 = 100
end
x = foo()
typeof(x)
This feature is useful for preventing performance problems that can occur if one of the assignments to a variable unexpectedly changes its type.
This "declaration" behaviour only occurs in certain contexts and applies to the entire current scope, even before the declaration.
local x::Int8 # in a local declaration
Type declarations can also be applied to global variables.
a = 10
typeof(a)
function foo(y)
global a = 15 # throws an error when foo is called
return a + y
end
foo(10)
Declarations can also be attached to function definitions:
function sinc(x)::Float64
if x == 0
return 1
end
return sin(pi*x)/(pi*x)
end
sinc(1.1)
Abstract types¶
Abstract types cannot be created and serve only as nodes in the type graph, thus describing sets of related concrete types that are their descendants.
abstract type Pointy{T} end
Pointy{Int64} <: Pointy
Pointy{1} <: Pointy
Pointy{Float64} <: Pointy{Real}
Types of motorcades¶
Cortices are an abstraction of function arguments without the function itself. The most important aspects of function arguments are their order and types. Therefore, a tuple type is similar to a parameterised immutable type, where each parameter is the type of a single field. For example, a tuple type of two elements is similar to the following immutable type:
struct Tuple2{A,B}
a::A
b::B
end
However, there are three key differences:
- tuple types can have any number of parameters.
- Tuple types are covariant in their parameters:
Tuple{Int}
is a subtype ofTuple{Any}
. Therefore,Tuple{Any}
is considered an abstract type, and tuple types are concrete only if their parameters are concrete. - Tuples do not have field names; fields are accessed only by index.
Tuple values are written in parentheses and commas. When constructing a tuple, the corresponding tuple type is generated on demand:
typeof((1,"foo",2.5))
Tuple{Int64, String, Float64}
Tuple{Int,AbstractString} <: Tuple{Real,Any}
Tuple{Int,AbstractString} <: Tuple{Real,Real}
Vararg tuple types¶
The last parameter of a tuple type can be a special value Vararg
, denoting any number of finite elements:
mytupletype = Tuple{AbstractString,Vararg{Int}}
Tuple{AbstractString, Vararg{Int64}}
isa(("1",1,2), mytupletype)
isa(("1",1,2,3.0), mytupletype)
Named tuples¶
Named tuples are instances of type NamedTuple
, which has two parameters: a character tuple specifying field names and a tuple type specifying field types. For convenience, NamedTuple
types are rendered using the @NamedTuple
macro.
typeof((a=1,b="hello")) # prints in macro form
@NamedTuple{a::Int64, b::String}
Parametric primitive types¶
Primitive types can also be declared parametrically. For example, pointers are represented as primitive types, which will be declared in Julia as follows:
# 64-bit system:
primitive type P{T} 64 end
P{Int64} <: P
P{Float64} <: P
Conclusion¶
This demonstration shows the basic data types and how they can be declared and used. More information can be found in the articles about integers and floating point numbers, and in the article about data types, which is the basis for this demonstration.