# Arbeit mit Julia: REPL, Pakete, Introspection


@sec-tab

## Dokumentation

Die offizielle Julia-Dokumentation [https://docs.julialang.org/](https://docs.julialang.org/) enthält zahlreiche Übersichten, darunter:

 - [https://docs.julialang.org/en/v1/base/punctuation/](https://docs.julialang.org/en/v1/base/punctuation/) Verzeichnis der Symbole
 - [https://docs.julialang.org/en/v1/manual/unicode-input/](https://docs.julialang.org/en/v1/manual/unicode-input/) Verzeichnis spezieller Unicode-Symbole und deren Eingabe in Julia via Tab-Vervollständigung
 - [https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions](https://docs.julialang.org/en/v1/manual/mathematical-operations/#Rounding-functions) Liste mathematischer Funktionen 




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

Nach dem Start von Julia in einem Terminal kann man neben Julia-Code auch verschiedene Kommandos eingeben 

:::{.narrow}
| Kommando                     | Wirkung                    |
| :----------------------------|  :------------------------ |
| `exit()` oder `Ctrl-d`       | exit Julia                 |
| `Ctrl-c`                     | interrupt                  |
| `Ctrl-l`                     | clear screen               |
| Kommando mit `;` beenden     | Ausgabe unterdrückt        |
| `include("filename.jl")`     | Datei mit Julia-Code einlesen und ausführen |



Der REPL hat verschiedene Modi: 

| Modus  | Prompt |  Modus starten  | Modus verlassen  |
| :-     | :-      | :-             | :-               |
| default| `julia>` |  | `Ctrl-d`|
| Package manager | `pkg>` | `]`    | `backspace` |
| Help    | `help?>` | `?`| `backspace `|
|Shell | `shell>`  | `;` | `backspace`|

:::


## Jupyter-Notebooks (IJulia)


In einem Jupyter-Notebook sind die Modi sind als Einzeiler in einer eigenen Input-Zelle nutzbar: 

(i) ein Kommando des Paket-Managers:


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

(ii) eine Help-Abfrage:


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

(iii) Ein Shell-Kommando:


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

## Der Paketmanager

Wichtiger Teil des _Julia Ecosystems_ sind die zahlreichen Pakete, die Julia erweitern.

- Einige Pakete sind Teil jeder Julia-Installation und müssen nur mit einer `using Paketname`-Anweisung aktiviert werden. 
  - Sie bilden die sogenannte _Standard Library_ und dazu gehören 
  - `LinearAlgebra`, `Statistics`, `SparseArrays`, `Printf`, `Pkg` und andere.
- Über 9000 Pakete sind offiziell registriert, siehe   [https://julialang.org/packages/](https://julialang.org/packages/). 
  - Diese können mit wenigen Tastendrücken heruntergeladen und installiert werden.
  - Dazu dient der _package manager_ `Pkg`.
  - Man kann ihn auf zwei Arten verwenden: 
    - als normale Julia-Anweisungen, die auch in einer `.jl`-Programmdatei stehen können:
    ```
    using Pkg
    Pkg.add("PaketXY")
    ```
    - im speziellen pkg-Modus des Julia-REPLs:
    ```
    ] add PaketXY
    ```
  - Anschließend kann das Paket mit `using PaketXY` verwendet werden.
- Man kann auch Pakete aus anderen Quellen und selbstgeschriebene Pakete installieren.

    
### Einige Funktionen des Paketmanagers

| Funktion                | `pkg` - Mode            | Erklärung                                               |
|:------------------------|:--------------------------| :-------------------------------------------------------|
| `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` |


### Installierte Pakete und Environments 

- Julia und der Paketmanager verwalten 
   1. eine Liste der mit dem Kommando `Pkg.add()` bzw. `]add`  explizit installierten Pakete mit genauer Versionsbezeichnung in einer Datei `Project.toml` und 
   2. eine Liste aller dabei auch als implizite Abhängigkeiten installierten Pakete in der Datei `Manifest.toml`. 
- Das Verzeichnis, in dem diese Dateien stehen, ist das `environment` und wird mit `Pkg.status()` bzw. `]status` angezeigt. 
- Im Normalfall sieht das so aus: 

```
(@v1.8) pkg> status
      Status `~/.julia/environments/v1.8/Project.toml`
  [1dea7af3] OrdinaryDiffEq v6.7.1
  [91a5bcdd] Plots v1.27.1
  [438e738f] PyCall v1.93.1
```

- Man kann für verschiedene Projekte eigene `environments` benutzen. Dazu kann man entweder Julia mit 
```shell
julia --project=path/to/myproject
```
starten oder in Julia das environment mit `Pkg.activate("path/to/myproject")` aktivieren. Dann werden `Project.toml, Manifest.toml` dort angelegt und verwaltet. (Die Installation der Paketdateien erfolgt weiterhin irgendwo unter `$HOME/.julia`) 


### Zum Installieren von Paketen auf unserem Jupyter-Server `misun103`:

- Es gibt ein zentrales Repository, in dem alle in diesem Kurs erwähnten Pakete bereits installiert sind. 
- Dort haben Sie keine Schreibrechte.
- Sie können aber zusätzliche Pakete in Ihrem `HOME` installieren. Dazu ist als erster Befehl nötig, das aktuelle Verzeichnis zu aktivieren: 


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

(Man beachte den Punkt!)


Danach können Sie mit `add` im Pkg-Modus auch Pakete installieren:

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


Achtung! Das kann dauern! Viele Pakete haben komplexe Abhängigkeiten und lösen die Installation von weiteren Paketen aus. Viele Pakete werden beim Installieren vorkompiliert. Im REPL sieht man den Installationsfortschritt, im Jupyter-Notebook leider nicht.





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

Julia baut auf die Werkzeuge des _LLVM Compiler Infrastructure Projects_ auf.

:::{.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)
```


