01 JULIA1 - 2A: Types, objects, variables and operators (13:5)
01 JULIA1 - 2B: Object mutability and effects on copying objects (13:34)
0102 Types and objects
Some stuff to set-up the environment..
julia> cd(@__DIR__)
julia> using Pkg
julia> Pkg.activate(".") # If using a Julia version different than 1.10 please uncomment and run the following line (reproductibility guarantee will hower be lost) # Pkg.resolve() # Pkg.instantiate() # run this if you didn't in Segment 01.01
Activating project at `~/work/SPMLJ/SPMLJ/buildedDoc/01_-_JULIA1_-_Basic_Julia_programming`
julia> using Random
julia> Random.seed!(123)
Random.TaskLocalRNG()
Types
julia> # 1 in not 1.0: a = 1
1
julia> b = 1.0
1.0
julia> typeof(a) # type is inferred !
Int64
julia> typeof(b) # Convert type (cast)
Float64
julia> a = 1
1
julia> b = convert(Float64,a)
1.0
julia> typeof(b)
Float64
Type hierarchy in Julia:
Any
AbstractString
(We'll see what all these "abstract" mean....)String
- ...
AbstractArray
Array
- ....
Number
Complex
Real
Rational
Integer
Unsigned
UInt64
- ...
Signed
Int32
Int64
BigInt
- ...
Bool
FixedPoints
- ...
AbstractIrrational
Irrational
AbstractFloat
Float32
Float64
BigFloat
- ...
- ...
Complete Number hierarchy: https://upload.wikimedia.org/wikipedia/commons/d/d9/Julia-number-type-hierarchy.svg
Everythong is an object, i.e. of some "type":
julia> c = typeof(a)
Int64
julia> typeof(c)
DataType
julia> d = sin
sin (generic function with 25 methods)
julia> typeof(d) <: Function
true
julia> typeof(+) <: Function
true
Operators are just functions:
julia> 1 + 2
3
julia> +(1,2) # this call the function "+"
3
julia> import Base.+ # +(a,b,c) = a*b*c # Defining my new crazy addition operation with 3 arguments
julia> 10+20+30 # This call it
60
julia> 10+20 # The addition with two parameters remains the same
30
julia> 10+20+30+40 # Also this one remains with the standard addition..
100
After you tested this singular interpretation of the summation function, please restart Julia or few things will continue to work: with great power comes great responsability, and if we change the meaning of such a inner feature of the language, repercussions will be deep.
Objects and variables
julia> k = 10 # "create" an object Int64 in memory and binds (assign) it to the `k` identifier (the variable name)
10
julia> typeof(k)
Int64
julia> sizeof(k) # bytes (1 byte is 8 bits)
8
julia> bitstring(k)
"0000000000000000000000000000000000000000000000000000000000001010"
julia> 0*2^0+1*2^1+0*2^2+1*2^3
10
julia> m = k # name binding: it binds (assign) the entity (object) referenced by a to the b identifier (the variable name)
10
julia> m == k # are the two objects equal ?
true
julia> m === k # are the two identifiers binding the same identical object in memory ?
true
Mutability property of Julia objects
Mutable objects are stored in memory "directly", while for mutable objects it is its memory address to be stored:
julia> k = 10
10
julia> v = [1,2]
2-element Vector{Int64}: 1 2
julia> p = 'z'
'z': ASCII/Unicode U+007A (category Ll: Letter, lowercase)
julia> g = "hello"
"hello"
julia> ismutable(k)
false
julia> ismutable(v)
true
julia> ismutable(p)
false
julia> ismutable(g)
true
Three different ways to "copy" objects...
julia> a = [[[1,2],3],4] # First element of a is said to be "mutable", second one is not:
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> ismutable(a[1])
true
julia> ismutable(a[2])
false
julia> b = a # binding to a new identifier
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> c = copy(a) # create a new copy of a and binds it to c
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> d = deepcopy(a) # copy all the references recursively and assign this new object to d
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> c == a # are the two objects equal ?
true
julia> c === a # are the two identifiers binding the same identical object in memory ?
false
julia> a[2] = 40 # rebinds a[2] to an other objects and at the same time mutates object a:
40
julia> b
2-element Vector{Any}: Any[[1, 2], 3] 40
julia> c
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> d
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> a[1][2] = 30 # rebinds a[1][2] and at the same time mutates both a and a[1]
30
julia> b
2-element Vector{Any}: Any[[1, 2], 30] 40
julia> c
2-element Vector{Any}: Any[[1, 2], 30] 4
julia> d
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> a[1][1][2] = 20
20
julia> b
2-element Vector{Any}: Any[[1, 20], 30] 40
julia> c
2-element Vector{Any}: Any[[1, 20], 30] 4
julia> d
2-element Vector{Any}: Any[[1, 2], 3] 4
julia> a = 5 # rebinds a:
5
julia> b
2-element Vector{Any}: Any[[1, 20], 30] 40
julia> c
2-element Vector{Any}: Any[[1, 20], 30] 4
julia> d
2-element Vector{Any}: Any[[1, 2], 3] 4
Consider these memory isues when we'll discuss calling a function by reference/value !
This page was generated using Literate.jl.