pic
Personal
Website

2b. Variables, Types, and Operators

PhD in Economics

Introduction

This section introduces the concepts of variables and their types. We'll also present operators, focusing on their syntax. To ensure a smooth learning experience, I've minimized the reliance on objects we haven't covered yet. The only one introduced is the syntax vectors, which are expressed by enclosing elements in brackets (e.g., [1,2,3]).

Variables

Variables act as labels for objects, essentially playing the role of identifiers. They're created through the so-called assignment operator, denoted by =. Likewise, variables are associated with objects, which are storage locations that hold values. Each value, in turn, has a type associated with it, defining the nature of the object.

For example, x = "Hello" assigns the label x to a memory location. In turn, this memory allocation holds an object with the value Hello, where the value Hello has type String. [note] Saying that "a variable has a specific type" is a simplification. Technically, it's the variable's value that has a specific type, not the variable itself.

Variables


Defining Variables

Variable names in Julia can be defined using Unicode characters, thus offering a wide range of possibilities. This enables you to use Greek letters, Chinese characters, symbols, and even emoticons. [note] You can insert a Unicode character by copying and pasting it from a list, such as the one found on this website. Alternatively, you can use Tab completion with the commands listed in the Julia documenation. Underscores _ are also permitted, which can be helpful for separating words in variable names (e.g., intermediate_result). [note] However, not all the symbols are allowed. For instance, names that incorporate symbols commonly used in mathematical notation, such as x^ or %x, aren't permitted. Additionally, while numbers are allowed, they can't be the first character (e.g., 2x is invalid). Importantly, names are case-sensitive, so that bar and Bar are treated as two distinct variables.

Code

a = 2
A = 2               # variable `A` is different from `a`

new_value = 2       # underscores allowed

β = 2               # Greek letters allowed

中國 = 2            # Chinese characters allowed   

x̄  = 2              # decorations allowed
x₁ = 2               

🐒 = 2             # emoticons allowed

Warning!
Unlike other programming languages, Julia doesn't let you delete variables. Once a variable is created, it remains in memory until the program terminates. If a variable is taking up too much memory, you can free up space by reassigning it to a smaller object.
Notation for Variable Names
Julia's developers adopt the convention of using snake-case notation for variable names. This relies on lowercase letters and numbers, with words separated by underscores. (e.g., snake_case_var1). Note that this is only a convention, not a language's requirement.

Updating Variables

It's possible to assign a new value to a variable using the variable itself. This approach is referred to as updating a variable.

Code

x  = 2

x  = x + 3    # 'x' now equals 5

Julia offers a concise syntax for updates based on common operations, which involves prefixing = with the operator applied.

Code

x  = 2

x  = x + 3
x += 3        # equivalent

x  = x * 3
x *= 3        # equivalent

x  = x - 3
x -= 3        # equivalent

Types

To effectively work with Julia, it's essential to understand some fundamental principles related to types. At this point, we'll only cover the bare minimum for the upcoming chapters, revisiting it during Part II of this website.

Objects can be broadly classified into single-element objects and multiple-element objects, respectively referred to as scalars and collections. The following lists outline the main types you can find in each category.

Types play a crucial role in characterizing an object's value. In some cases, they can be further specified by type parameters, which provide additional information about the value. The syntax for specifying type parameters is <name of type>{<type parameters>}, where type parameters are optional and can be omitted when not needed.

In terms of scalars, common numeric types include Int64 for integers, Float64 for decimal numbers, and Bool for binary values (true and false values). [note] The suffix 64 in these type names represents the number's precision. It determines the maximum number of significant digits or decimals that can be accurately represented. Likewise, the type Char represents individual characters, and serve as the building block for the String type. String is the standard for representing text, and is formally considered as a collection of characters.

For their part, collections usually require type parameters for their description. For instance, the type Vector{Int64} indicates that the vector exclusively contains elements of type Int64, such as the object [2, 4, 6]. In this case, Int64 serves as the type parameter, which can vary depending on the type of elements the collection is intended to store.

Type Annotations
You can explicitly declare a variable's type. This requires using type annotations through the :: operator. For example, x::String ensures that x can only store string values, resulting in an error if you attempt to reassign x with a value of different type.
Notation for Types
Julia's developers adopt the convention of using CamelCase notation for denoting types, where every first letter is capitalized (e.g., MyType). Note that this is only a convention, not a language's requirement.

Type Hierarchy: Concrete Types and Abstract Types

Types in Julia are organized in a hierarchical structure. This enables the definition of supersets and subsets of types, which in programming are respectively referred to as supertypes and subtypes. Likewise, this hierarchy gives rise to the notions of abstract and concrete types.

An abstract type is a set of types that serve as a parent to other types. The Any type in Julia is a prime example, which comprises all possible subtypes—by definition, every type in Julia is a subtype of Any. In contrast, a concrete type represents an irreducible unit, therefore lacking subtypes. It covers in particular primitive types, which are the fundamental types used by computers to perform calculations. Examples of primitive types are Int64 and Float64.

Abstract types provide great flexibility for writing code. For example, Julia includes the abstract type Number, which encompasses all possible numeric types (e.g., Float64, Int64, Float32). This allows you to declare a variable with the generic type Number, without the need to specify whether it's an integer, float, or its numerical precision.

Below, we demonstrate the concept of abstract and concrete types through the type Number. Although Number encompasses a broader range of subtypes than the ones depicted in the table, the representation below has been simplified for clarity. [note] The subtype Signed from Integers represents integers that can be either negative or positive. Julia also offers the type Unsigned, which encompasses subtypes UInt64, UInt32, etc., and only accepts positive integers.

Example of Supertype "Number"

Note: Dashed red borders indicate abstract types, while solid blue borders indicate concrete types.

It's worth noting that the names in the table match the exact names of each type.

Operators

In programming, operators are symbols that represent operations performed on objects. They can be thought of as syntactic sugar for functions, as we'll see in the next chapters. In fact, almost all operators in Julia can be employed as functions.

For instance, the symbol + in x + y is an operator that performs the addition of x and y. Likewise, the symbols x and y are referred to as its operands, which represent the operator's inputs to perform its calculation. Operators follow specific syntax rules based on the number of operands they require. Understanding this syntax will prove useful for several topics covered later on the website. Next, we define and illustrate the syntax through several examples. At this point, just focus on how operators are written, even if their specific functions are not yet clear.

  • Unary operators: They take one operand, with the operator written to the left of it. [note] Operators to the left of the operand are known as prefix operators. Conversely, operators written to the right of the operand are known as postfix operators. Julia has a few of them (e.g., ' to transpose a vector or matrix x, which is written as x'). We won't use postfix operators on this website. Formally, their syntax is <operator>x, such as √x or -x.

  • Binary operators: They take two operands, and the operator is written between them. [note] Operators with this syntax are called infix operators. Formally, their syntax is x <operator> y, such as x + y or x^y for \(x^y\).

  • Ternary operators: They take three operands. Formally, their syntax is x <operator1> y <operator2> z. Ternary operators are rare, which is why the specific operator x ? y : z is directly referred to as the ternary operator. We'll see that this operator performs a conditional evaluation, returning y if x is true and z returned otherwise.