Variables and Types¶
When you issue an assignment statement, such as
x = 2
you create a variable called x
. What does this actually mean?
Julia creates a place in memory where the value 2
is stored. It then creates a "binding" so that the symbol :x
from now on points to that location in memory. (This is actually not the way it works for scalar real numbers, but we will set this detail aside right now.)
The memory location now has a type
. In this case, it is Int64
:
typeof(x)
Int64
Julia is dynamically typed. This means that I can change the type of x
by simply reassigning a new value or by converting the value to a different type:
x=Float64(x)
2.0
Doing this kind of thing is generally a bad idea, but it is legal. It is a bad idea because it confuses the reader of the code and the compiler.
Important types include:
- Scalar numbers, such as
1
or1.0
. - Strings, such as "this is a string".
- Arrays of numbers, such as
[1 2; 3 4]
. Dict
: a container that maps names to values; similar to astruct
in Matlab.Struct
: a composite, user-defined type with fixed fields; similar to aclass
in Matlab.
Supertypes and Subtypes¶
One DataType
is Number
. This includes integers, floating point numbers, etc.
Types come in hierarchies. For example:
Base.show_supertypes(Int64)
Int64 <: Signed <: Integer <: Real <: Number <: Any
shows that Int64
is a subtype of Signed
etc.
Only the "lowest" types in the hierarchy are concrete types that can actually be assigned values. The higher up types are abstract. They only exist to make a type hierarchy.
Why do types come in a hierarchy? Mainly because some functions are defined on certain groups of types, but not on others. For example, sin("abc")
does not make sense, but sin(x)
makes sense for various types of Number
.
Scalar Numbers¶
The main Number
types that we care about are integers and floats. Integers come in various flavors depending on how many digits they can store and whether or not they are signed. The default is Int64
which stores 64 bits and is signed. UInt8
requires only 8 bits, but it cannot store large values.
Julia knows standard operators on numbers and is smart enough to convert types as needed:
julia> x= 1 + 2.0
3.0
julia> typeof(x)
Float64
Overflow warning: If you assign a value that is too large for a type to store, you get overflow issues:
y=UInt8(12345678)
InexactError: trunc(UInt8, 12345678)
Stacktrace:
[1] throw_inexacterror(::Symbol, ::Type{UInt8}, ::Int64) at ./boot.jl:558
[2] checked_trunc_uint at ./boot.jl:588 [inlined]
[3] toUInt8 at ./boot.jl:650 [inlined]
[4] UInt8(::Int64) at ./boot.jl:710
[5] top-level scope at In[5]:1
[6] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091
This throws an error because Julia cannot convert a large number to a UInt8
.
The several lines below the error message are a stacktrace. It shows where in your code the error occurred. This is important for debugging.
We will talk about arrays separately.
Strings¶
In contrast to Matlab, Strings
are not Vector{Char}
. They are their own type.
A String
is created by providing characters inside quotes:
a = "This is a string"
But strings can be indexed like character vectors:
julia> a[4]
's': ASCII/Unicode U+0073 (category Ll: Letter, lowercase)