---
engine: julia
---

```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
myactive_module() = Main.Notebook
Base.active_module() = myactive_module()
```

# Working with Julia: REPL, Packages, Introspection

```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
import QuartoNotebookWorker
Base.stdout = QuartoNotebookWorker.with_context(stdout)
myactive_module() = Main.Notebook
Base.active_module() = myactive_module()
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520
# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077
```

## Documentation

The official Julia documentation [https://docs.julialang.org/](https://docs.julialang.org/) contains numerous overviews, including:

 - [https://docs.julialang.org/en/v1/base/punctuation/](https://docs.julialang.org/en/v1/base/punctuation/) List of symbols
 - [https://docs.julialang.org/en/v1/manual/unicode-input/](https://docs.julialang.org/en/v1/manual/unicode-input/) List of special Unicode symbols and their input methods via tab completion in Julia
 - [https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions) List of mathematical functions 



## Julia REPL (Read - Eval - Print - Loop)

After starting Julia in a terminal, you can enter both Julia code and various commands:

:::{.narrow}
| Command                      | Effect                     |
| :----------------------------|  :------------------------ |
| `exit()` or `Ctrl-d`         | exit Julia                 |
| `Ctrl-c`                     | interrupt                  |
| `Ctrl-l`                     | clear screen               |
| End command with `;`         | suppress output            |
| `include("filename.jl")`     | read and execute file with Julia code |

  

The REPL has several modes: 

| Mode   | Prompt |  Start mode  | Exit mode  |
| :-     | :-      | :-             | :-               |
| default| `julia>` |  | `Ctrl-d` (exits Julia) |
| Package manager | `pkg>` | `]`    | `backspace` |
| Help    | `help?>` | `?`| `backspace `|
|Shell | `shell>`  | `;` | `backspace`|

:::


## Jupyter Notebooks (IJulia)


In a Jupyter notebook, the modes are usable as single-line commands in their own input cells:

(i) a package manager command:


```{julia}
#| eval: false
] status   
```

(ii) a help query:


```{julia}
#| eval: false
?sin
```

(iii) a shell command:


```{julia}
#| eval: false
;ls 
```

## The Package Manager

An important part of the _Julia ecosystem_ is the numerous packages that extend Julia.

- Some packages are part of every Julia installation and only need to be activated with a `using Packagename` statement. 
  - They form the so-called _standard library_, which includes 
  - `LinearAlgebra`, `Statistics`, `SparseArrays`, `Printf`, `Pkg`, and others.
- Over 9000 packages are officially registered, see   [https://julialang.org/packages/](https://julialang.org/packages/). 
  - These can be downloaded and installed with just a few keystrokes.
  - The _package manager_ `Pkg` is used for this purpose.
  - It can be used in two ways: 
    - as normal Julia statements that can also be in a `.jl` program file:
    ```
    using Pkg
    Pkg.add("PackageXY")
    ```
    - in the special pkg-mode of the Julia REPL:
    ```
    ] add PackageXY
    ```
  - Afterward, the package can be used with `using PackageXY`.
- You can also install packages from other sources and self-written packages.

      
### Some Package Manager Functions

| Function                | `pkg` - Mode            | Explanation                                               |
|:------------------------|:--------------------------| :-------------------------------------------------------|
| `Pkg.add("MyPack")`     | `pkg> add MyPack`     | add `MyPack.jl` to current environment                    |
| `Pkg.rm("MyPack")`      | `pkg> remove MyPack`  | remove `MyPack.jl` from current environment               |
| `Pkg.update()`          | `pkg> update`         | update packages in current environment                    |
| `Pkg.activate("mydir")` | `pkg> activate mydir` | activate directory as current environment                 |
| `Pkg.status()`    | `pkg> status`    | list packages                                  |
| `Pkg.instantiate()` | `pg> instantiate` | install all packages according to `Project.toml` |


### Installed Packages and Environments 

- Julia and the package manager maintain 
    1. a list of packages explicitly installed with the command `Pkg.add()` or `]add` with exact version specifications in a file `Project.toml` and 
    2. a list of all packages installed as implicit dependencies in the file `Manifest.toml`. 
- The directory in which these files are located is the `environment` and is displayed with `Pkg.status()` or `]status`. 
- In the normal case, this looks like this: 

```
(@v1.10) pkg> status
      Status `~/.julia/environments/v1.10/Project.toml`
  [6e4b80f9] BenchmarkTools v1.5.0
  [5fb14364] OhMyREPL v0.5.24
  [91a5bcdd] Plots v1.40.4
  [295af30f] Revise v3.5.14
```

- You can use separate `environments` for different projects. You can either start Julia with 
```shell
julia --project=path/to/myproject
```
or activate the environment in Julia with `Pkg.activate("path/to/myproject")`. Then `Project.toml, Manifest.toml` are created and managed there. (The installation of package files still takes place somewhere under `$HOME/.julia`) 


### For Installing Packages on Our Jupyter Server `misun103`:

- There is a central repository in which all packages mentioned in this course are already installed. 
- There you have no write permissions.
- However, you can install additional packages in your `HOME`. As a first command, you need to activate the current directory: 


```{julia}
#| eval: false
] activate .
```

(Note the dot!)




After that, you can install packages with `add` in the pkg-mode:

```{julia}
#| eval: false
] add PackageXY
```


Warning! This can take a long time! Many packages have complex dependencies and trigger the installation of further packages. Many packages are precompiled during installation. You can see the installation progress in the REPL, but unfortunately not in the Jupyter notebook.




## The Julia JIT _(just in time)_ Compiler: Introspection

Julia is built on the tools of the _LLVM Compiler Infrastructure Project_.

:::{.narrow}
Stages of Compilation 

|  stage & result   |  introspection command  |
| :---          |          :--- |
|Parse $\Longrightarrow$   Abstract Syntax Tree (AST) | `Meta.parse()` |
| Lowering:     transform AST $\Longrightarrow$  Static Single Assignment (SSA) form | `@code_lowered`|
|  Type Inference  |   `@code_warntype`, `@code_typed` |
| Generate LLVM intermediate representation | `@code_llvm`|
|  Generate native machine code | `@code_native` |

:::



```{julia}
function f(x,y)
    z = x^2 + log(y)
    return 2z
end
```


```{julia}
p = Meta.parse( "function f(x,y); z=x^2+log(y); return 2x; end  ")
```


```{julia}
using TreeView

walk_tree(p)
```


```{julia}
@code_lowered f(2,4)
```


```{julia}
@code_warntype f(2,4)
```


```{julia}
@code_typed f(2,4)
```


```{julia}
@code_llvm f(2,4)
```


```{julia}
@code_native f(2,4)
```
