Engee documentation
Notebook

Data types

The Julia language type system is dynamic, but at the same time it contains some advantages of static type systems, allowing you to specify that certain values belong to certain types.

There is no division into 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 the Engee and MATLAB data types.

Type (Engee/MATLAB) Number of bits Smallest value Largest value
Int8 / int8 8 -2^7 2^7 - 1
UInt8 / uint8 8 0 2^8 - 1
Int16 / int16 16 -2^ 2^{15} - 1
UInt16 / uint16 16 0 2^{16} - 1
Int32 / int32 32 -2^ 2^{31} - 1
UInt32 / uint32 32 0 2^{32} - 1
Int64 / int64 64 -2^ 2^{63} - 1
UInt64 / uint64 64 0 2^{64} - 1
Int128 / no 128 -2^ 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
Float32 / single 32 Single precision Single precision
Float64 / double 64 Double precision Double precision
(Nifj or Qifj) / fi(i,x,n,m) (min 8, max 64) / (min 1, max 1024) Fixed-point number Fixed-point number

Type Declarations

Operator :: It can be used to attach type annotations to expressions and variables in programs. There are two main reasons to do this.

  1. As an installation to help confirm that your program is working as you expect.
  2. To provide the compiler with additional information about the type, and in some cases this can improve performance.

When added to the expression calculating the value, :: the operator is read as "is an instance".

In [ ]:
(1+2)::Int
Out[0]:
3

When added to a variable on the left side of the assignment :: declares that a variable always has a specified type, similar to a type declaration in a statically typed language such as C.

In [ ]:
function foo()
    x::Int8 = 100
end
Out[0]:
foo (generic function with 1 method)
In [ ]:
x = foo()
Out[0]:
100
In [ ]:
typeof(x)
Out[0]:
Int64

This feature is useful to prevent performance problems that may occur if one of the assignments to a variable unexpectedly changes its type.

This "declaration" behavior only occurs in certain contexts and applies to the entire current scope, even before the declaration.

In [ ]:
local x::Int8  # in a local declaration

Type declarations can also be applied to global variables.

In [ ]:
a = 10
Out[0]:
10
In [ ]:
typeof(a)
Out[0]:
Int64
In [ ]:
function foo(y)
        global a = 15   # throws an error when foo is called
        return a + y
end
Out[0]:
foo (generic function with 2 methods)
In [ ]:
foo(10)
Out[0]:
25

Declarations can also be attached to function definitions.:

In [ ]:
function sinc(x)::Float64
    if x == 0
        return 1
    end
    return sin(pi*x)/(pi*x)
end

sinc(1.1)
Out[0]:
-0.08942105846213334

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.

In [ ]:
abstract type Pointy{T} end
In [ ]:
Pointy{Int64} <: Pointy
Out[0]:
true
In [ ]:
Pointy{1} <: Pointy
Out[0]:
true
In [ ]:
Pointy{Float64} <: Pointy{Real}
Out[0]:
false

Types of tuples

Tuples are an abstraction of function arguments without the function itself. The most important aspects of function arguments are their order and types. Therefore, the tuple type is similar to a parameterized immutable type, where each parameter is a type of a single field. For example, the type of a tuple of two elements is similar to the following immutable type:

In [ ]:
struct Tuple2{A,B}
    a::A
    b::B
end

However, there are three key differences:

  1. Tuple types can have any number of parameters.
  2. Tuple types are covariant in their parameters: Tuple{Int} It is a subtype of Tuple{Any}. Therefore Tuple{Any} It is considered an abstract type, and tuple types are specific only if their parameters are specific.
  3. Tuples do not have field names; fields are accessed only by index.

Tuple values are written in parentheses and commas. When building a tuple, the corresponding tuple type is generated on demand.:

In [ ]:
typeof((1,"foo",2.5))
Tuple{Int64, String, Float64}
Out[0]:
Tuple{Int64, String, Float64}
In [ ]:
Tuple{Int,AbstractString} <: Tuple{Real,Any}
Out[0]:
true
In [ ]:
Tuple{Int,AbstractString} <: Tuple{Real,Real}
Out[0]:
false

Types of Vararg tuples

The last parameter of the tuple type can be a special value. Vararg, denoting any number of finite elements:

In [ ]:
mytupletype = Tuple{AbstractString,Vararg{Int}}
Tuple{AbstractString, Vararg{Int64}}
Out[0]:
Tuple{AbstractString, Vararg{Int64}}
In [ ]:
isa(("1",1,2), mytupletype)
Out[0]:
true
In [ ]:
isa(("1",1,2,3.0), mytupletype)
Out[0]:
false

Named tuples

Named tuples are instances of the type NamedTuple, which has two parameters: a tuple of characters specifying the names of fields, and a tuple type specifying the types of fields. For convenience NamedTuple the types are derived using @NamedTuple the macro.

In [ ]:
typeof((a=1,b="hello")) # prints in macro form
@NamedTuple{a::Int64, b::String}
Out[0]:
@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:

In [ ]:
# 64-bit system:
primitive type P{T} 64 end
In [ ]:
P{Int64} <: P
Out[0]:
true
In [ ]:
P{Float64} <: P
Out[0]:
true

Conclusion

This demo shows the main types of data, as well as the possibilities of their declaration and application.
For more information, see the articles about integers and floating numbers запятой , as well as in the article about data types, on the basis of which this demonstration was implemented.