---
engine: julia
---

```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```

# Fundamentals of Syntax

## Names of Variables, Functions, Types, etc.

- Names may contain letters, digits, underscores `_`, and exclamation marks `!`.
- The first character must be a letter or an underscore.
- Case is significant: `Nmax` and `NMAX` are different variables.
- The character set used is [Unicode](https://home.unicode.org/). This provides access to over 150 scripts and numerous symbols.
- There is a short [list of reserved keywords](https://docs.julialang.org/en/v1/base/base/#Keywords): `if, then, function, true, false,...`

:::{.callout-tip}  
## Example

permissible: `i, x, Ω, x2, DieUnbekannteZahl, neuer_Wert, 🎷, Zähler, лічильник, einself!!!!,...`

impermissible: `Uwe's_Funktion, 3achsen, A#B, $this_is_not_Perl, true,...` 
:::

----

:::{.callout-note }
## Note 

In addition to the *reserved keywords* of the core language, numerous additional functions and objects are predefined, such as the mathematical functions `sqrt(), log(), sin()`.
These definitions are found in the module `Base`, which Julia loads automatically at startup. 
Names from `Base` can be redefined as long as they have not yet been used:

```{julia}
#| error: true  
log = 3
1 + log
```
Now of course the logarithm is broken:
```{julia}
#| error: true
x = log(10)
```
(see also <https://stackoverflow.com/questions/65902105/how-to-reset-any-function-in-julia-to-its-original-state>)
:::

## Statements

- In normal circumstances, each line contains one statement.
- If a statement is recognizable as incomplete at the end of a line through 
    - open parentheses
    - operators,
    
  then the next line is regarded as a continuation.
- Multiple statements per line can be separated by semicolons.
- In interactive mode (REPL or notebook), a semicolon after the last statement suppresses the output of the result of that statement.

:::{.callout-tip}

## Example 

In interactive mode, the value of the last statement is also displayed without explicit `print()`:
```{julia}
println("Hallo 🌍!")
x = sum([i^2 for  i=1:10])
```
The semicolon suppresses this:
```{julia}
println("Hallo 🌍!")
x = sum([i^2 for  i=1:10]);
```
:::

---------


:::{.callout-warning }

For multi-line statements, the line to be continued must end with an open operation or parenthesis: 

```{julia}
x = sin(π/2) +
   3 * cos(0)
```

Therefore, the following goes wrong, but unfortunately **without an error message**!
```{julia}
#| error: true
#| warning: true
x = sin(π/2)
  + 3 * cos(0)
println(x)
```  
Here, the `+` in the second line is interpreted as a prefix operator (sign). Thus, lines 1 and 2 are each complete, correct expressions on their own (even though line 2 is of course completely useless) and are processed as such. 

Moral: If you want to split longer expressions across multiple lines, you should always open a parenthesis. Then it doesn't matter where the line break occurs:
```{julia}
x = ( sin(π/2) 
   + 3 * cos(0) )
println(x)
```     
:::


## Comments

Julia knows two types of comments in program text:

```{julia}
# Single-line comments begin with a hash symbol.

x = 2    # everything from '#' to the end of the line is a comment and is ignored. x = 3
```

```{julia}
#= 
   Single and multi-line comments can be enclosed between #= ...  =#.
   Nested comments are possible. 
   #= 
      i.e., unlike in C/C++/Java, the comment does not end with the first 
      comment-end character, but the #=...=# pairs act like parentheses.    
   =# 
   The automatic 'syntax highlighter' does not yet know this, as the alternating 
   gray shading of this comment shows.     
=#


x #= das ist ein seltener Variablenname! =#  = 3 
```


## Data Types Part I 

- Julia is a [strongly typed](https://de.wikipedia.org/wiki/Starke_Typisierung) language.   All objects have a type. Functions/operations expect arguments of the correct type.
- Julia is a [dynamically typed](https://de.wikipedia.org/wiki/Dynamische_Typisierung) language. Variables have no type. They are names that can be bound to objects via assignment `x = ...`.
- When speaking of the "type of a variable", one means the type of the object currently assigned to the variable.
- Functions/operators can implement different *methods* for different argument types.
- Depending on the concrete argument types, it is decided at function usage which method is used ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).


Simple basic types are, for example:

```
Int64, Float64, String, Char, Bool
```


```{julia}
x = 2
x, typeof(x), sizeof(x) 
```

```{julia}
x = 0.2
x, typeof(x), sizeof(x) 
```

```{julia}
x = "Hallo!"
x, typeof(x), sizeof(x) 
```


```{julia}
x = 'Ω'
x, typeof(x), sizeof(x) 
```

```{julia}
x = 3 > π
x, typeof(x), sizeof(x) 
```

- `sizeof()` returns the size of an object or type in bytes (1 byte = 8 bits)
- 64-bit integers and 64-bit floating-point numbers correspond to the instruction set of modern processors and are therefore the standard numeric types.
- Characters/*chars* `'A'` and strings/*strings* `"A"` of length 1 are different objects.   

## Control Flow

### `if` Blocks

- An `if` block *can* contain **any number** of `elseif` branches and at the end at most **one** `else` branch.
- The block has a value, the value of the last executed statement.

```{julia}
x = 33
y = 44
z = 34

if x < y && z != x                     # elseif- and else-branches are optional
    println("yes")
    x += 10
elseif x < z                           # any number of elseif branches
    println(" x is smaller than z")
elseif x == z+1                           
    println(" x is successor of z")
else                                   # at most one else block 
    println("Alles falsch")
end                                    # value of the entire block is the value of the 
                                       # last evaluated statement
```

Short blocks can be written in one line:
```{julia}
if x > 10 println("x is larger than 10") end 
```

The value of an `if` block can of course be assigned:
```{julia}
y = 33
z = if y > 10 
       println("y is larger than 10") 
       y += 1 
     end
z    
```

### Conditional Operator (ternary operator) `test ? exp1 : exp2`

```{julia}
x = 20
y = 15
z = x < y ? x+1 : y+1
```
is equivalent to

```{julia}
z = if x < y
        x+1
    else
        y+1
    end
```

## Comparisons, Tests, Logical Operations

### Arithmetic Comparisons

- `==`
- `!=`, `≠`
- `>`
- `>=`, `≥`
- `<`
- `<=`, `≤`

As usual, the equality test `==` is to be distinguished from the assignment operator `=`. Almost anything can be compared:

```{julia}
"Aachen" < "Leipzig", 10 ≤ 10.01, [3,4,5] < [3,6,2]
```

Well, almost anything:

```{julia}
3 < "vier"
```

The error message shows a few fundamental principles of Julia:

- Operators are also just functions: `x < y`  becomes the function call `isless(x, y)`.
- Functions (and thus operators) can implement different *methods* for different argument types. 
- Depending on the concrete argument types, it is decided at function call which method is used ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).

One can display all methods for a function. This provides insight into Julia's complex type system:

```{julia}
methods(<)
```

Finally: comparisons can be chained.

```{julia}
10 < x ≤ 100  # this is equivalent to
              #   10 < x && x ≤ 100

```


### Tests 
Some functions of type `f(c::Char) -> Bool`

```{julia}
isnumeric('a'), isnumeric('7'), isletter('a')
```


and of type `f(s1::String, s2::String) -> Bool`

```{julia}
contains("Lampenschirm", "pensch"), startswith("Lampenschirm", "Lamb"), endswith("Lampenschirm", "rm")
```

- The function `in(item, collection) -> Bool` tests whether `item` is in `collection`. 
- It also has the alias ` ∈(item, collection)` and 
- both `in` and `∈` can also be written as infix operators.

```{julia}
x = 3
x in [1, 2, 3, 4, 5]
``` 
```{julia}
x ∈ [1, 2, 33, 4, 5]
```

###  Logical Operations: `&&`, `||`, `!`


```{julia}
3 < 4 && !(2 > 8) && !contains("aaa", "b")
```

#### Conditional Evaluation (_short circuit evaluation_)

- in `a && b` `b` is only evaluated if `a == true`
- in `a || b` `b` is only evaluated if `a == false`

(i) Thus, `if test statement end` can also be written as `test && statement`.

(ii) Thus, `if !test statement end` can be written as `test || statement`.

As an example^[from the [Julia documentation](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation)] here is an implementation of the factorial function:

```{julia}
function fact(n::Int)
    n >= 0 || error("n must be non-negative")
    n == 0 && return 1
    n * fact(n-1)
end

fact(5)
```



Of course, all these tests can also be assigned to variables of type `Bool` and
these variables can be used as tests in `if` and `while` blocks:

```{julia}
x = 3 < 4
y = 5 ∈ [1, 2, 5, 7]
z = x && y
if z                        # equivalent to:  if 3 < 4  &&  5 in [1,2,5,7]
    println("Stimmt alles!")
end
```

- In Julia, all tests in a logical expression must be of type `Bool`.
- There is no implicit conversion such as *"0 is false and 1 (or anything != 0) is true"*
- If `x` is a numeric type, then the C idiom `if(x)` must be written as `if x != 0`.
- There is an exception to support the _short circuit evaluation_:
      - in the constructs `a && b && c...` or `a || b || c...` the last subexpression does not need to be of type `Bool` if these constructs are not used as tests in `if` or `while`:


```{julia}
z = 3 < 4 && 10 < 5 &&  sqrt(3^3)
z, typeof(z)
```

```{julia}
z = 3 < 4 && 10 < 50 &&  sqrt(3^3)
z, typeof(z)
```

## Loops *(loops)*

###  The `while` ("while") loop


Syntax:
```
while *condition*
   *loop body*
end
```
A series of statements (the loop body) is repeatedly executed as long as a condition is satisfied.


```{julia}
i = 1          # typically the test of the 
               # while loop needs preparation ...
while i < 10   
   println(i)
   i += 2      # ... and an update
end
```

The body of a `while` and `for` loop can contain the statements `break` and `continue`. `break` stops the loop, `continue` skips the rest of the loop body and immediately starts the next loop iteration.
```{julia}
i = 0

while i<10
   i += 1

   if i == 3
      continue     # start next iteration immediately,
   end             # skip rest of loop body

   println("i = $i")

   if i ≥ 5
      break        # break loop
   end
end

println("Fertig!")
```

With `break` one can also exit infinite loops:

```{julia}
i = 1

while true
    println(2^i)
    i += 1
    if i > 8 break end
end
```

###  `for` Loops

Syntax:

```
for *var* in *iterable container*
   *loop body*
end
```

The loop body is executed for all items from a container. 

Instead of `in`, $\in$ can always be used. In the header of a `for` loop, `=` can also be used.

```{julia}
for i ∈ ["Mutter", "Vater", "Tochter"]
    println(i)
end
```


Often a numerical loop counter is needed. For this purpose, there is the *range* construct. The simplest forms are 
`Start:End` and `Start:Step:End`. 

```{julia}
endwert = 5

for i ∈ 1:endwert
    println(i^2)
end
```

```{julia}
for i = 1:5.5  print(" $i") end
```


```{julia}
for i = 1:2:14 print("  $i") end
```

```{julia}
for k = 14 : -2.5 : 1 print("   $k") end
```




#### Nested Loops _(nested loops)_

A `break` ends the innermost loop.

```{julia}
for i = 1:3
    for j = 1:3
        println( (i,j) )
        if j == 2
            break
        end
    end
end
```

*Nested loops* can also be combined in a single `for` statement. Then a `break` ends the entire loop.

```{julia}
for i = 1:3, j=1:3     # essentially the same as above, but:
    println( (i,j) )
    if j == 2
        break          # break ends the entire loop here
    end
end
```


:::{.callout-important .titlenormalxx}
## **Important:** The semantics are completely different from C-style `for` loops!

**In each loop iteration, the loop variable is re-initialized with the next element from the container.**


```{julia}
for i = 1:5
    print(i," ... ")
    i += 2
    println(i)
end
```

-------

The C semantics of `for(i=1; i<5; i++)` corresponds to the `while` loop:
```
i = 1
while i<5
   *loop body*   # here one can also mess with i effectively
   i += 1
end
```
:::

## Unicode 

Julia uses Unicode as its character set. This allows identifiers from non-Latin scripts (e.g., Cyrillic, Korean, Sanskrit, runes,
emojis,...) to be used for variables, functions, etc. The question of how one can enter such characters in their editor and whether the used screen font can display them is not Julia's problem.

- Some Unicode characters, e.g., `≤, ≠, ≥, π, ∈, √`, can be used instead of `<=, !=, >=, pi, in, sqrt`. 

- Over 3000 Unicode characters can be entered in Julia in a LaTeX-like manner using tab completion. 
  - `\alpha<TAB>` becomes `α`, 
  - `\euler<TAB>` becomes `ℯ`  (Euler's number `exp(1)`, [special script e, `U+0212F`](https://www.htmlsymbol.com/unicode-code/212f.html))
  - `\le<TAB>` becomes `≤`,
  - `\in<TAB>` becomes `∈`,
  - `\:rainbow:<TAB>` becomes `🌈`       
  [Here is the list.](https://docs.julialang.org/en/v1/manual/unicode-input/)

## Idiosyncrasies and Pitfalls of Syntax

- After a numeric constant, the multiplication operator `*` can be omitted when a variable, function, or opening parenthesis follows.
  ```
   z = 3.4x + 2(x+y) + xy
  ```

is therefore valid Julia. Note, however, that the term `xy` is interpreted as a single variable named xy __and not__ as the product of x and y!

- This rule has a few pitfalls:

This works as expected:
```{julia}
e = 7
3e 
```

Here, the input is interpreted as a floating-point number -- and `3E+2` or `3f+2` (Float32) as well. 

```{julia}
3e+2 
```

A space creates clarity:

```{julia}
3e + 2 
```

This works:

```{julia}
x = 4
3x + 3 
```

...and this does not. `0x`, `0o`, `0b` are interpreted as the beginning of a hexadecimal, octal, or binary constant.

```{julia}
3y + 0x  
```


- There are a few other cases where the very permissive syntax leads to surprises.


```{julia}
Wichtig  = 21
Wichtig! = 42       # identifiers can also contain !
(Wichtig, Wichtig!)
```



```{julia}
Wichtig!=88
```


Julia interprets this as the comparison `Wichtig != 88`.

Spaces help:

```{julia}
Wichtig! = 88
Wichtig!
```

- Operators of the form `.*`, `.+`,... have a special meaning in Julia (*broadcasting*, i.e., vectorized operations).  

```{julia}
1.+2.
```

Again, spaces create clarity!

```{julia}
1. + 2.
```

