Engee documentation
Notebook

Julia: Language features

This article is a concise guide to the basics of the Julia language, based on the principle of "minimum theory — maximum practice." All the material is organized around the code: each section is illustrated with directly working examples, and the text explanations are kept to the necessary minimum. This approach allows you to quickly immerse yourself in the syntax, see typical constructions and immediately start experimenting without being distracted by long descriptions. Julia is famous for her expressiveness and speed, and it's best to get to know her through live code — this is exactly the opportunity offered by the proposed selection. Here you will find examples of working with variables, data types, collections, functions, multiple dispatching, and other key language features.

Variables and assignment

Assigning an integer

In [ ]:
x = 100              
Out[0]:
100

Using a variable in an expression

In [ ]:
x * 5              
Out[0]:
500

Reassigning a variable

In [ ]:
x = 10 + 10    
Out[0]:
20

Julia is a dynamically typed language, a variable can change its type.

In [ ]:
x = "Hello World!"   
Out[0]:
"Hello World!"

Assignment returns the value of the right-hand side

In [ ]:
b=4
a = (b = 2 + 2) * 5
Out[0]:
20

Assignment chains are also possible, and in the example below, all three variables are assigned 10

In [ ]:
x = y = z = 10
Out[0]:
10

Unicode is supported in variable names

In [ ]:
x1 = 100             
 = "Point"         
δ = 0.001            
Out[0]:
0.001

Case dependence, myvar and myVar are two different variables.

In [ ]:
myvar = 1
Out[0]:
1
In [ ]:
MyVar = 2
Out[0]:
2

Forbidden names for variables:

  • You can't start with a number: 1x = 100
  • Language functions cannot be used as variables: baremodule, begin, break, catch, const, continue, do, else, elseif, end, export, false, finally, for, function, global, if, import, let, local, macro, module, quote, return, struct, true, try, using, while

Behavior with mutable types (arrays)
Important: assignment does NOT create a copy for mutable objects!

In [ ]:
a = [1, 2, 3] 
Out[0]:
3-element Vector{Int64}:
 1
 2
 3

b refers to the SAME array as a

In [ ]:
b = a 
Out[0]:
3-element Vector{Int64}:
 1
 2
 3

We mutate the array through a and output b, b also sees the change!

In [ ]:
a[1] = 42
b
Out[0]:
3-element Vector{Int64}:
 42
  2
  3

Reconnecting an array

In [ ]:
a = [1, 2, 3]
b = a
a = 3.14159
b
Out[0]:
3-element Vector{Int64}:
 1
 2
 3
In [ ]:
a = [1, 2, 3]
b .= a
a = [1, 2, 30] 
b
Out[0]:
3-element Vector{Int64}:
 1
 2
 3

Data types and annotations

Automatic type detection, Float64 is the default type for floating point numbers

In [ ]:
x = -2.0
typeof(x)
Out[0]:
Float64

Int64 is the default type for integers.

In [ ]:
x = 2
typeof(x)
Out[0]:
Int64
In [ ]:
x = -2
typeof(x)
Out[0]:
Int64

Domain error without complex numbers

In [ ]:
# sqrt(x) #ERROR

Explicit indication of the complex type. Adding 0im for the complex type

In [ ]:
x = -2.0 + 0im        
typeof(x) 
Out[0]:
ComplexF64 (alias for Complex{Float64})
In [ ]:
sqrt(x)              
Out[0]:
0.0 + 1.4142135623730951im

An annotation operator of the type :: checking whether the statement "is an instance" of a given type or not.

In [ ]:
(2 + 2)::Int 
Out[0]:
4
In [ ]:
# (2 + 2)::AbstractFloat #ERROR
In [ ]:
(2.0 + 2.0)::AbstractFloat
Out[0]:
4.0

Type stability check

In [ ]:
function fast_sum(arr::Vector{Int})
    s = 0
    for x in arr
        s += x
    end
    return s
end
@code_warntype fast_sum([1,2,3])   # should show Any::Any (or specific types)
# @code_native fast_sum([1,2,3]) # assembly code
MethodInstance for fast_sum(::Vector{Int64})
  from fast_sum(arr::Vector{Int64}) @ Main In[57]:1
Arguments
  #self#::Core.Const(Main.fast_sum)
  arr::Vector{Int64}
Locals
  @_3::Union{Nothing, Tuple{Int64, Int64}}
  s::Int64
  x::Int64
Body::Int64
1 ─       (s = 0)
 %2  = arr::Vector{Int64}
       (@_3 = Base.iterate(%2))
 %4  = @_3::Union{Nothing, Tuple{Int64, Int64}}
 %5  = (%4 === nothing)::Bool
 %6  = Base.not_int(%5)::Bool
└──       goto #4 if not %6
2 ┄ %8  = @_3::Tuple{Int64, Int64}
       (x = Core.getfield(%8, 1))
 %10 = Core.getfield(%8, 2)::Int64
 %11 = Main.:+::Core.Const(+)
 %12 = s::Int64
 %13 = x::Int64
       (s = (%11)(%12, %13))
       (@_3 = Base.iterate(%2, %10))
 %16 = @_3::Union{Nothing, Tuple{Int64, Int64}}
 %17 = (%16 === nothing)::Bool
 %18 = Base.not_int(%17)::Bool
└──       goto #4 if not %18
3 ─       goto #2
4 ┄ %21 = s::Int64
└──       return %21

Declaring a variable type

In [ ]:
x = Complex(-2)   
typeof(x)                  
Out[0]:
Complex{Int64}
In [ ]:
sqrt(x)
Out[0]:
0.0 + 1.4142135623730951im

Hierarchy of types:

  • Int64 <: Integer <: Real <: Number <: Any
  • Float64 <: AbstractFloat <: Real <: Number <: Any

Parametric types

Two-dimensional Int64 array

In [ ]:
Array{Int64, 2}
Out[0]:
Matrix{Int64} (alias for Array{Int64, 2})

Float64 vector (one-dimensional)

In [ ]:
Array{Float64, 1}
Out[0]:
Vector{Float64} (alias for Array{Float64, 1})

Integers

Aliases of system types:

Int - Int64 integer

UInt - UInt64 unsigned integer

In [ ]:
10 
Out[0]:
10

A leading zero does not make a number octal.

In [ ]:
0123456789
Out[0]:
123456789

Automatic bit depth expansion for large numbers is supported.

In [ ]:
typeof(10000000000000000000)
Out[0]:
Int128
In [ ]:
typeof(1000000000000000000000000000000000000000)
Out[0]:
BigInt

Unsigned integers (hexadecimal), the size is determined automatically by the number of digits.

In [ ]:
x = 0x1              # UInt8 (1 byte)
x = 0x123            # UInt16 (2 bytes)
x = 0x1234567        # UInt32 (4 bytes)
x = 0x123456789abcdef # UInt64 (8 bytes)
x = 0x11112222333344445555666677778888  # UInt128 (16 bytes)
Out[0]:
0x11112222333344445555666677778888
In [ ]:
typeof(0xfffffffffffffffffffffffffffffffff)
Out[0]:
BigInt

Julia does NOT check overflow by default - cyclical behavior.

In [ ]:
x = typemax(Int64)
Out[0]:
9223372036854775807
In [ ]:
x + 1 # overflow!
Out[0]:
-9223372036854775808
In [ ]:
x + 1 == typemin(Int64) 
Out[0]:
true
In [ ]:
x = typemax(UInt64) 
x + 1  
Out[0]:
0x0000000000000000
In [ ]:
x + 1 == typemin(UInt64) 
Out[0]:
true

BigInt Overflow solution

In [ ]:
10^19
Out[0]:
-8446744073709551616
In [ ]:
BigInt(10)^19
Out[0]:
10000000000000000000

Floating-point numbers.

In [ ]:
1.0                  # Standard entry
1.                   # You can omit the zero after the dot.
0.5                  # A regular fraction
.5                   # You can omit the zero before the dot.
-1.23                # Negative
Out[0]:
-1.23

E-notation

In [ ]:
1e10                 # 1.0e10 = 1.0 × 10^10
2.5e-4               # 0.00025
Out[0]:
0.00025

Float32 can be specified using the suffix f

In [ ]:
x = 0.5f0
typeof(x)          
Out[0]:
Float32
In [ ]:
2.5f-4
Out[0]:
0.00025f0

Float16 is implemented through an explicit type assignment

In [ ]:
Float16(4.)
Out[0]:
Float16(4.0)

Bit representation.

In [ ]:
0.0 == -0.0
Out[0]:
true
In [ ]:
bitstring(0.0)
Out[0]:
"0000000000000000000000000000000000000000000000000000000000000000"
In [ ]:
bitstring(-0.0)  
Out[0]:
"1000000000000000000000000000000000000000000000000000000000000000"

Arbitrary precision of BigFloat

In [ ]:
BigFloat(2.0)^100 / 4
Out[0]:
3.16912650057057350374175801344e+29

Special values

  • -Inf (negative infinity)
  • Inf (positive infinity)
In [ ]:
typemin(Float64)
Out[0]:
-Inf
In [ ]:
typemax(Float64) 
Out[0]:
Inf

Arithmetic with infinities

In [ ]:
1 / 0                # Inf
-5 / 0               # -Inf
0 / 0                # NaN
1 / Inf              # 0.0
1 / -Inf             # -0.0
Inf - Inf            # NaN
0 * Inf              # NaN
Out[0]:
NaN

NaN is not equal to himself

In [ ]:
NaN == NaN           # false!
NaN != NaN           # true
NaN < NaN            # false
NaN > NaN            # false
Out[0]:
false

For a correct comparison, it is used isequal

In [ ]:
isequal(NaN, NaN)            # true - NaN are considered equal
Out[0]:
true
In [ ]:
isequal([1 NaN], [1 NaN])    # true - comparing arrays
Out[0]:
true
In [ ]:
isequal(-0.0, 0.0)           # false - distinguishes between signed zeros!
Out[0]:
false

Machine epsilon

In [ ]:
eps(Float64)
Out[0]:
2.220446049250313e-16
In [ ]:
eps(1000.) 
Out[0]:
1.1368683772161603e-13
In [ ]:
eps(0.0) # 5.0e-324 - minimum positive
Out[0]:
5.0e-324

Strings and symbols

Lines

In [ ]:
s = "Hello!"
Out[0]:
"Hello!"

Interpolation

In [ ]:
"Interpolation: $s" 
Out[0]:
"Интерполяция: Hello!"
In [ ]:
"Expression: $(2 + 2)" 
Out[0]:
"Выражение: 4"

string (does not handle escaping)

In [ ]:
"String without \n interpolation"
Out[0]:
"Строка без \n интерполяции"

Multi-line lines

In [ ]:
multiline = """
    Line
    with hyphenations
    """
Out[0]:
"Строка\nс переносами\n"

Concatenation and repetition

In [ ]:
"Hello" * " " * "World" 
Out[0]:
"Hello World"
In [ ]:
"Hi"^3 
Out[0]:
"HiHiHi"

Characters (Char)

In [ ]:
c = 'a' 
typeof(c)                   
Out[0]:
Char
Warning: detected a stack overflow; program state may be corrupted, so further execution might be unreliable.
In [ ]:
c+1
Out[0]:
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)

Symbols (Symbol)

In [ ]:
sym = :my_symbol
typeof(sym)
Out[0]:
Symbol

They are often used as dictionary keys.

In [ ]:
Dict(:key => "value")
Out[0]:
Dict{Symbol, String} with 1 entry:
  :key => "value"

Structures and abstract types

They are used to create custom types and organize hierarchies.

In [ ]:
# Immutable structure
struct Point
    x::Float64
    y::Float64
end
In [ ]:
# Mutable structure
mutable struct MPoint
    x::Float64
    y::Float64
end
In [ ]:
# The abstract type
abstract type Shape end
struct Circle <: Shape
    radius::Float64
end
struct Rectangle <: Shape
    width::Float64
    height::Float64
end
In [ ]:
# Constructors
Point(3.0, 4.0)            # automatic
Out[0]:
Point(3.0, 4.0)

Collections

Tuples are an immutable structure, faster than arrays.

In [ ]:
t = (1, 2, 3)
t[1]
Out[0]:
1
In [ ]:
# t[1] = 5 #ERROR

Unpacking tuples

In [ ]:
a, b, c = t
Out[0]:
(1, 2, 3)

Dictionaries (Dict)

In [ ]:
d = Dict("a" => 1, "b" => 2)
Out[0]:
Dict{String, Int64} with 2 entries:
  "b" => 2
  "a" => 1
In [ ]:
d["a"]
Out[0]:
1
In [ ]:
d["c"] = 3   
Out[0]:
3
In [ ]:
haskey(d, "a")
Out[0]:
true
In [ ]:
keys(d), values(d)
Out[0]:
(["c", "b", "a"], [3, 2, 1])

Sets (Set) - removes duplicates

In [ ]:
s = Set([1, 2, 2, 3]) 
Out[0]:
Set{Int64} with 3 elements:
  2
  3
  1
In [ ]:
1  s 
Out[0]:
true
In [ ]:
push!(s, 4)
Out[0]:
Set{Int64} with 4 elements:
  4
  2
  3
  1

MISSING and NOTHING

nothing is an analog of null/None (the value is missing)

In [ ]:
function f()
    return nothing
end
f() === nothing
Out[0]:
true

missing — missing data (distributed in calculations)

In [ ]:
1 + missing
Out[0]:
missing
In [ ]:
# mean([1, missing, 3]) #ERROR

Check

In [ ]:
ismissing(missing)      
Out[0]:
true
In [ ]:
isnothing(nothing)     
Out[0]:
true

Basic operators

Arithmetic operators

In [ ]:
1 + 10 - 5           # addition and subtraction
5 * 20 / 10          # multiplication and division
20 \ 10              # reverse division (10/20)
3^3                  # exponentiation
5.5 % -2             # the remainder of the division
Out[0]:
1.5

Implicit multiplication (numerical factor), Julia allows you to write 2x instead of 2*x

In [ ]:
x = 3
2x                   # implicit multiplication
2(x + 1)             # It also works with brackets.
2x^2                 # priority:  above implicit multiplication
2^2x                 
Out[0]:
64

Logical operators

In [ ]:
!true                # false - negation
!false               # true
true && true         # true - logical And (abbreviated)
true && false        # false
false && false       # false
true || true         # true - logical OR (abbreviated)
true || false        # true
false || false       # false
Out[0]:
false

Bitwise operators

In [ ]:
~100                 # -101 - bitwise NOTATION (inversion)
121 & 232            # 104 - bitwise and
121 | 232            # 249 - bitwise OR
121  232            # 145 - bit XOR (Unicode character!)
xor(121, 232)        # 145 - the same through the function
~UInt32(121)         # 0xffffff86 - type-preserving inversion
~UInt8(121)          # 0x86 is also a UInt8 result.
Out[0]:
0x86

Update Operators (in-place)

In [ ]:
x = 25
x += 25              # x = x + 25
x *= 2               # x = x * 2
x /= 4               # x = x / 4
x ^= 2               # x = x^2
Out[0]:
625.0

Update operators can change the data type.

In [ ]:
x = 0x01             
typeof(x)                     
Out[0]:
UInt8
In [ ]:
x *= 2               
typeof(x)   
Out[0]:
Int64

Vectorization

Creating a matrix

In [ ]:
x = [1 2 3 4 5; 6 7 8 9 10]
Out[0]:
2×5 Matrix{Int64}:
 1  2  3  4   5
 6  7  8  9  10

Operator . applies the operation element-by-element, as well as this operator creates a new matrix.

In [ ]:
x.^2
Out[0]:
2×5 Matrix{Int64}:
  1   4   9  16   25
 36  49  64  81  100
In [ ]:
x .+ 1               # Each element is + 1
x .- 1               # Each element is 1
x .* 2               # Each element * 2
x ./ 2               # Each element / 2
Out[0]:
2×5 Matrix{Float64}:
 0.5  1.0  1.5  2.0  2.5
 3.0  3.5  4.0  4.5  5.0

Point update operators

In [ ]:
x = [1 2 3 4 5; 6 7 8 9 10]
Out[0]:
2×5 Matrix{Int64}:
 1  2  3  4   5
 6  7  8  9  10

Mutates an EXISTING array x by overwriting it.

In [ ]:
x .+= 1
Out[0]:
2×5 Matrix{Int64}:
 2  3  4   5   6
 7  8  9  10  11

Creating a NEW array, x does not change

In [ ]:
y = x .+ 1
Out[0]:
2×5 Matrix{Int64}:
 3  4   5   6   7
 8  9  10  11  12

Comparison operators

In [ ]:
2 == 2.0             # true - different types, but equal values
3 == 5               # false
3 != 5               # true
3 < 5                # true
5 > 3                # true
3 <= 3               # true
5 >= 5               # true
Out[0]:
true

Features for Float:

  • A positive zero is equal to, but not greater than, a negative one
  • Inf is equal to itself and most of all (except NaN)
  • -Inf is equal to itself and least of all (except NaN)
  • NaN is not comparable to anything

Julia also allows you to write mathematical comparison chains.

In [ ]:
10 < 15 <= 20 < 30 == 30 > 20 >= 10 == 10 < 30 != 5
Out[0]:
true

Equivalent to:

In [ ]:
(10 < 15) && (15 <= 20) && (20 < 30) && (30 == 30) && (30 > 20) && (20 >= 10) && (10 == 10) && (10 < 30) && (30 != 5)
Out[0]:
true

Point comparisons

In [ ]:
x = [1 2 3 4 5; 6 7 8 9 10]
x .<= 3
Out[0]:
2×5 BitMatrix:
 1  1  1  0  0
 0  0  0  0  0
In [ ]:
1 .< x .< 7
Out[0]:
2×5 BitMatrix:
 0  1  1  1  1
 1  0  0  0  0

Indexation

In [ ]:
A = [1 2 3; 4 5 6]          # 2×3 Matrix{Int64}
A[1, 2]                     # 2 (first row, second column)
A[1, :]                     # the first line (1×3)
A[:, 2]                     # second column (2×1)
A[1:2, 1]                   # the first column is like a vector
A[1:2, 1:2]                 # the 2×2 submatrix
Out[0]:
2×2 Matrix{Int64}:
 1  2
 4  5

Indexing from the end

In [ ]:
A[1, end]                   # the last element of the first line
A[end, 1]                   # the last element of the first column
Out[0]:
4

Logical indexing

In [ ]:
A[A .> 2]                   # [4, 5, 6, 3] ( aligns to a vector)
Out[0]:
4-element Vector{Int64}:
 4
 5
 3
 6

Operator priority

Hierarchy (from highest to lowest):

  1. Numerical coefficients: 2x (higher than all binary coefficients except ^)
  2. Exponentiation: ^
  3. Unary numbers: +x, -x, √x, ...
  4. Multiplication/division: *, /, \, ÷, %
  5. Addition/subtraction: +, -
  6. The Shift: <<, >>, >>>
  7. Bitwise And: &
  8. Bitwise XOR: ⊻
  9. Bitwise OR: |
  10. Comparisons: ==, !=, <, <=, >, >=
  11. Type statement: <:
  12. Logical And: &&
  13. Logical OR: ||
  14. The pipe operator: |>
  15. Assignment: =, +=, -=, and so on.

First x^2=9, then 2*9

In [ ]:
x = 3
2x^2
Out[0]:
18

First 2x=6, then 2^6!

In [ ]:
2^2x                 
Out[0]:
64

Control structures

Conditional operator

In [ ]:
x = 10
msg = if x > 5
    "More than five"
else
    "Few"
end
Out[0]:
"Больше пяти"

The ternary operator

In [ ]:
x > 5 ? "Yes" : "No"
Out[0]:
"Да"

Short-circuit evaluation (replacing if)

In [ ]:
x > 0 && println("Positive")   # Executed if true
x < 0 || println("Not negative") # Executed if the first one is false
Положительное
Не отрицательное

Cycles:

  • With a precondition
  • With a postcondition
In [ ]:
for i in 1:3
    println(i)
end
1
2
3
In [ ]:
while x > 0
    x -= 1
end

Iterating through collections

In [ ]:
for (i, val) in enumerate(["a", "b", "c"])
    println("$i: $val")
end
1: a
2: b
3: c

Generators and comprehensions

Array Comprehension (creating an array)

In [ ]:
squares = [x^2 for x in 1:5]
Out[0]:
5-element Vector{Int64}:
  1
  4
  9
 16
 25

With the condition

In [ ]:
evens = [x for x in 1:10 if x % 2 == 0]
Out[0]:
5-element Vector{Int64}:
  2
  4
  6
  8
 10

Generator (lazy computation, saves memory), does not create an array in memory, but iterates one element at a time.

In [ ]:
gen = (x^2 for x in 1:1000000)
sum(gen)
Out[0]:
333333833333500000

Functions and multiple dispatching

A short note (one expression)

In [ ]:
f(x) = x^2 + 1
Out[0]:
f (generic function with 2 methods)
In [ ]:
f(5)
Out[0]:
26
In [ ]:
f(1)
Out[0]:
2

Classic entry (code block)

In [ ]:
function g(x, y)
    return x + y
end
Out[0]:
g (generic function with 1 method)

Default arguments, key arguments

In [ ]:
function greet(name; greeting="Hello", punctuation="!")
    return "$greeting, $name$punctuation"
end
greet("Engee", greeting="Hi")
Out[0]:
"Hi, Engee!"

Anonymous functions

In [ ]:
h = x -> x^2
h(4) 
Out[0]:
16

Often used in map, filter:

In [ ]:
map(x -> x^2, [1, 2, 3])
Out[0]:
3-element Vector{Int64}:
 1
 4
 9

Multiple Dispatch - the same function behaves differently depending on the data types.

In [ ]:
say_hello(name::String) = "Hello, man $name"
say_hello(name::Symbol) = "Hello, robot :$name"

say_hello("Anna")
say_hello(:R2D2) 
Out[0]:
"Привет, робот :R2D2"

Launching programs

image.png

Will execute the file

In [ ]:
include("example.jl")
Hello, World!

REPL modes

The main mode is julia

In [ ]:
2+2
Out[0]:
4

Reference mode (?)

In [ ]:
?sqrt
search: sqrt isqrt sort sort! Cshort struct cbrt stat sprint

Out[0]:

?sqrt

Packet Mode (])

In [ ]:
]add DataFrames
   Resolving package versions...
     Project No packages added to or removed from `~/.project/Project.toml`
    Manifest No packages added to or removed from `~/.project/Manifest.toml`
In [ ]:
]status
Status `~/.project/Project.toml`
  [150eb455] CoordinateTransformations v0.6.4
  [a93c6f00] DataFrames v1.8.1
  [cbc4b850] ImageBinarization v0.3.1
  [4381153b] ImageDraw v0.2.6
  [92ff4b2b] ImageFeatures v0.5.3
  [6a3955dd] ImageFiltering v0.7.12
 [787d08f9] ImageMorphology v0.4.6
  [916415d5] Images v0.26.2
  [033835bb] JLD2 v0.6.3
  [c46f51b8] ProfileView v1.10.3
  [6038ab10] Rotations v1.7.1
 [90137ffa] StaticArrays v1.9.16
  [5e47fb64] TestImages v1.9.0
Info Packages marked with  have new versions available but compatibility constraints restrict them from upgrading. To see why use `status --outdated`

Shell mode (;)

In [ ]:
;ls
Language_Features.ngscript
example.jl

Macros

Macros allow you to generate code and extend syntax; in Julia, they are often used for debugging, time measurement, and optimization.

In [ ]:
@show 2 + 2          # outputs the expression and the result
2 + 2 = 4
Out[0]:
4
In [ ]:
@time sleep(0.1)     # measures the execution time
  0.102356 seconds (10.70 k allocations: 1.160 MiB)
In [ ]:
@assert 1 == 1       # checking the condition
In [ ]:
macro hello(expr)
    quote
        println("Hi! It's going to happen now:")
        println("  ", $(string(expr)))
        $(esc(expr))
    end
end
@hello 2 + 3 * 5
Привет! Сейчас выполнится:
  2 + 3 * 5
Out[0]:
17

Modules and namespaces

In [ ]:
module MyModule
    export hello, PI
    const PI = 3.14
    hello() = println("Hello from module")
    # not exported
    internal() = println("internal")
end
Out[0]:
Main.MyModule
In [ ]:
using .MyModule   # or import MyModule
hello()           # available
# internal() # error, not exported
Hello from module

Error handling

In [ ]:
try
    sqrt(-1)
catch e
    println("Caught an error: $e")
finally
    println("This always runs")
end
Caught an error: DomainError(-1.0, "sqrt was called with a negative real argument but will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).")
This always runs
In [ ]:
# Error generation
if x < 0
    error("x must be non-negative")
end
In [ ]:
# Custom Exceptions
struct MyError <: Exception
    msg::String
end
# throw(MyError("something went wrong")) #ERROR

Documentation

In [ ]:
"""
    square(x)

Returns the square of the number `x`.

# Arguments
- `x': a number (any numeric type)

# Example
```julia
julia> square(5)
25

"""
square(x) = x^2
Out[0]:
square

Conclusion

You went through a concentrated presentation of the basics of Julia, where the focus was not on lengthy explanations, but on visual code snippets. This style allows you not only to read about the language's capabilities, but to immediately see them in action, memorize the syntax and understand the logic of the work. Now you have a compact cheat sheet that you can return to when writing your own programs.