![TwoCultureProblem](https://hackmd.io/_uploads/BkTMu3y2A.jpg)
Credit of this fantastic figure to Matthijs Cox's blogs.
---
My goal with this documents is to hopefully convey to people using languages like MATLAB, Python and R with no background in software development or computer science, **the strengths and unique elements of the Julia programming language**.
While a lot of the things presented below can be done in other languages, they cannot be done as easily as in Julia :juggling:.
Meaning that, I hope that more people from the left distribution (scientist/engineers) come to the center (Julia) of the figure above!!
![julia_meme](https://hackmd.io/_uploads/BJWohrf2C.png)
Right now, it is not very well organized and I still need to include some topics. Feel free to contribute :smile:.
TODO:
- Organize information coherently
- Add difference between a function and a method
- Reproducibility: Project.toml, Manifest.toml, Pluto.jl
- Examples in which the fastest way of doing something is in Julia (DiffEq, Tables/Data, etc)
- Examples of type piracy
- JULIA IS A COMPILED LANGUAGE (but interactive, REPL)
- ?? help needed - fell free to add stuff
# Learning Julia
- Modern Julia workflows: https://modernjuliaworkflows.github.io/
- Good scientific code:
- https://github.com/JuliaDynamics/GoodScientificCodeWorkshop
- https://www.youtube.com/watch?v=x3swaMSCcYk
- GPU kernel programming: https://pde-on-gpu.vaw.ethz.ch/lecture10/t
- Matthijs Cox:
- My Target Audience: https://scientificcoder.com/my-target-audience
- The Art of Multiple Dispatch: https://scientificcoder.com/the-art-of-multiple-dispatch
- How to solve the two language problem: https://scientificcoder.com/how-to-solve-the-two-language-problem
- Automate your code quality: https://scientificcoder.com/automate-your-code-quality-in-julia
- Introduction to the Julia programming language (Guillaume Dalle)
- https://www.youtube.com/watch?v=O6CF-UHArMs
- https://juliaepfl.github.io/Website/notebooks/intro-2024.html
- https://juliaepfl.github.io/Website/notebooks/convolution_GPU_example.html
- DataFrames.jl benchmarks: https://h2oai.github.io/db-benchmark/
- Why Julia - a Manifesto: https://github.com/Datseris/whyjulia-manifesto
- Scientific Programming in Julia: https://juliateachingctu.github.io/Scientific-Programming-in-Julia/stable/lecture_08/lab/
- Automatic Differentiation: https://juliateachingctu.github.io/Scientific-Programming-in-Julia/stable/lecture_08/lecture/
- General code: Uncertainty Propagation https://juliateachingctu.github.io/Scientific-Programming-in-Julia/stable/lecture_12/lecture/
```julia
struct Dual{T<:Number} <: Number
x::T
d::T
end
```
```julia
struct GNum{T} where T<:Real
μ::T
σ::T
end
```
- MITMath: https://mitmath.github.io/18337/
# Showcasing Julia
- **Pluto.jl:**
- **KernelAbstractions.jl** -> CUDA.jl, AMDGPU.jl, Metal.jl, oneAPI.jl
- **Enzyme.jl**
- Plots (multiple backends):
- Makie.jl: GPU plotting
- PyPlot.jl
- PlotlyJS.jl
- **JuMP.jl**: Modeling language for Mathematical Optimization (linear, mixed-integer, conic, semidefinite, nonlinear)
- Optimization.jl
- Convex.jl: Stanford
- **DifferentialEquations.jl**
- Unitful.jl: adds units to type, zero overhead
- Flux.jl: Deep Learning
- LinearOperators.jl: https://jso.dev/tutorials/introduction-to-linear-operators/
# Benchmarks
Julia is one of the most cost-effective languages in terms of the amount of necessary code to achieve high-performance. It has been shown many times that Julia can achieve C/C++ levels of performance with **a lot less effort**.
![JuliaBenchmarks](https://hackmd.io/_uploads/HJ4UKhyh0.png)
![JuliaBenchmarksZoom](https://hackmd.io/_uploads/rJB8FhknA.png)
# The Unreasonable Effectiveness of Multiple Dispatch
https://www.youtube.com/watch?v=kc9HwsxE1OY
- There's something unusual about the Julia's ecosystem ...
- there's really large amount of **code sharing** and **code reuse**
![JuliaDiffEqMeasurements](https://hackmd.io/_uploads/HyJdFhy3A.png)
Generic differential equation solver -> Uncertainty measurements -> Uncertainty propagates through DiffEq solver (solution with uncertainty) -> plotting that solution shows error bars
This isn't entirely surprising, multiple dispatch is good at **expressing generic algorithms**.
- Generic algorithms apply to different types
- Common types shared by very different packages
> [!IMPORTANT] How can I explain multiple dispatch and code re-usability in practice?
> Square root and dual numbers
> ```julia
> function mysqrt(a) # <--- My code
> x = a
> for k in 1:100
> x = 0.5 * (x + a / x)
> end
> return x
> end
> ```
> What if I want to compute its derivative?
> $$
> f(x+\delta)=f(x)+\delta f'(x)
> $$
> Let's implement a custom type for this
> ```julia
> struct Dual{T} # Parametric type
> x::T
> δ::T
>end
># Extending a function coming from another package (Base)
>Base.:*(m, a::Dual) = Dual(m * a.x, m * a.δ)
>Base.:+(a::Dual, b::Dual) = Dual(a.x + b.x, a.δ + b.δ)
>Base.:/(a::Dual, b::Dual) = Dual(a.x / b.x, (b.x * a.δ - a.x * b.δ) / b.x^2)
> ```
> https://juliaepfl.github.io/Website/notebooks/intro-2024.html
![JuliaLevelsDispatch](https://hackmd.io/_uploads/HJ3KF21nA.png)
- **No dispatch**: C, one code does exactly one thing `f(x₁, x₂, ...)`
- **Single dispatch**: OOP ` x₁.f(x₂, ...)` (depending on the object $x_1$ the function $f$ is different)
- **Multiple dispatch**: `f(x₁, x₂, ...)` depends on all the combinations of variables
https://scientificcoder.com/the-art-of-multiple-dispatch
![VisualJuliaMultipleDispatch](https://hackmd.io/_uploads/H1A3Y2J2R.png)
![VisualJuliaMultipleDispatch2](https://hackmd.io/_uploads/HkAnK2knR.png)
![VisualJuliaMultipleDispatch3](https://hackmd.io/_uploads/SyR2Y31n0.png)
![VisualJuliaMultipleDispatch4](https://hackmd.io/_uploads/S103Y31nC.png)
![VisualJuliaMultipleDispatch5](https://hackmd.io/_uploads/SygRnFhk3A.png)
![JuliaGenericCode](https://hackmd.io/_uploads/ryVCY313R.png)
> [!IMPORTANT] How to write generic code?
> Remove all types from functions! Only specify the type for dispatch. The types go in the structs.
## Generic code
![JuliaGenericCode2](https://hackmd.io/_uploads/rk9J92khC.png)
It works, but ... we can do better!
![JuliaGenericCode3](https://hackmd.io/_uploads/B1Ce93y2C.png)
![JuliaGenericCode4](https://hackmd.io/_uploads/Sk0echJnR.png)
![JuliaGenericCode5](https://hackmd.io/_uploads/HyAg5n12C.png)
![JuliaGenericCode6](https://hackmd.io/_uploads/BJRec3k20.png)
## Common Types
![JuliaTypes](https://hackmd.io/_uploads/SkNQ92ynA.png)
Inheriting from RGB is ugly, I need to rename the object, and if someone defines a method for RGB, now I need to create a wrapper for MyRGB
![JuliaTypes2](https://hackmd.io/_uploads/H1NXc2k3A.png)
You can give up dispatch (no generic code), or just copy paste code into your code (no code reuse) ...
![JuliaTypes3](https://hackmd.io/_uploads/S1EQ5n120.png)
You can define methods outside of the type
![JuliaType4](https://hackmd.io/_uploads/r1Nmq212R.png)
# The expression problem
![JuliaExpressionProblem](https://hackmd.io/_uploads/HyLs5hkn0.png)
![JuliaExpressionProblem2](https://hackmd.io/_uploads/BkY2c3J2C.png)
![JuliaExpressionProblem3](https://hackmd.io/_uploads/By9pqhy2R.png)
> [!NOTE] Traits in RUST
> My impression was that, while rust functions don’t have multiple dispatch, generic rust traits _can_ have multiple dispatch, which lets you accomplish pretty much the same thing (though it’s more verbose). - Jasha10 Julia Discourse
>
> I think one problem with multipledispatch comparing to a trait system is that the developer needs to know and fully understand the detail of a function in order to let that function use some optimized operation for calculation. E.g. in the "inner" example, one needs to read the code of the function "inner" then can he know the function "inner" uses "*" (multiplication). After that, he can write a specialized "*" for the "OneHotVector". This may be obvious for "inner" but sooner it becomes not obvious for other complicated functions. - @weiyuanwu9044 YouTube comments
Why Multiple Dispatch was not used before? Trade-off with performance, In Julia this is not a problem
# Code reuse
https://www.youtube.com/watch?v=QTCKsqIK6nE
> "I see this (telling people to reuse code) ... like us trying to get people to eat helthy ... this is something that is good for you in the long run" - Jeff Bezanson
Programmers will reliably do two things:
- what is easy
- what runs fast
In other words: people want to eat junk food.
Have we made Cheetos that are good for you?
**broadcast** is the same as **map** for one argument, but it repeats inputs for more arguments.
# Type piracy
> [!WARNING] Type piracy
> You need to own either the **function** or the **type** of one of the arguments `f(arg1, arg2, ...)` to add a method to a function.
# Science and wasted efforts
In science, most programming languages have used this approach of OOP. For example Python. The main issue is, that if you want to solve a new problem, you need to **rewrite the whole algorithm** for your problem:
- We are so used to do this, that we don't question it
- So many resources have been lost in this
- Wan't to do Machine Learning? rewrite your code in PyTorch, JAX or TensorFlow
- TorchNUFFT
- etc
# Julia should be slow
- All type annotations are optional, let the compiler do the magic
- Multiple dispatch: specialised on concrete types
- Compile time: converting code to machine code
- Run time: when this machine code is actually executed
## Julia's compiler
JuliaCon 2024 - Valentin Churavy
![JuliaSourcetoMachineCode](https://hackmd.io/_uploads/rkSlin1nR.png)
![JuliaMacrosIntrospectionCode](https://hackmd.io/_uploads/B1sbsnJhR.png)
## Performance pitfalls
Engineering Julia for Speed | Lionel Zoubritzky | JuliaCon 2018
![JuliaComplierPerformance](https://hackmd.io/_uploads/HJ0fi0ynC.png)
**Type stability**: We can move the cost of type inference from run time to compile time (devirtualization). This is one of the most important aspects of Julia's performance.
![JuliaInlining](https://hackmd.io/_uploads/HkKEi0k3R.png)
![JuliaInlining2](https://hackmd.io/_uploads/rJmriRJ2C.png)
![JuliaInlining3](https://hackmd.io/_uploads/BJ-UoA1nR.png)
![JuliaUnboxing](https://hackmd.io/_uploads/rkSwi0knA.png)
The vector can be stored in an unboxed fashion if **all types are concrete**. Specifying types in methods are good for dispatch and overloading (someone can define a method of that function of their custom type)
![JuliaUnboxing2](https://hackmd.io/_uploads/Syddo0yhC.png)
![JuliaLLVMCodeNative](https://hackmd.io/_uploads/H1OFj0yh0.png)
LLVM 27k https://github.com/llvm/llvm-project
CPython 61k https://github.com/python/cpython
Julia 45k https://github.com/JuliaLang/julia
Code:
```julia hl:2
function add(a, b)
return a + b
end
```
Typed code (Typed IR):
```julia hl:3
julia> @code_typed add(1,1)
CodeInfo(
1 ─ %1 = Base.add_int(a, b):: Int64
└── return %1
) => Int64
```
LLVM IR (C++, Rust, Go, etc.)
```julia hl:7
julia> @code_llvm add(1,1)
; @ REPL[15]:1 within `add`
define i64 @julia_add_428(i64 signext %0, i64 signext %1) #0 {
top:
; @ REPL[15]:2 within `add`
; ┌ @ int.jl:87 within `+`
%2 = add i64 %1, %0
; └
ret i64 %2
}
```
---
CPU/GPU native code (assembly, not really useful to look at):
```julia
julia> @code_native add(1, 1)
.text
.file "add"
.globl julia_add_451 # -- Begin function julia_add_451
.p2align 4, 0x90
.type julia_add_451,@function
julia_add_451: # @julia_add_451
; ┌ @ REPL[15]:1 within `add` # %bb.0: # %top
push rbp
mov rbp, rsp
; │ @ REPL[15]:2 within `add`
; │┌ @ int.jl:87 within `+` lea rax, [rdi + rsi]
; │└ pop rbp ret .Lfunc_end0: .size julia_add_451, .Lfunc_end0-julia_add_451
; └
# -- End function
.section ".note.GNU-stack","",@progbits
```
> [!IMPORTANT] Static analysis
> In [computer science](https://en.wikipedia.org/wiki/Computer_science "Computer science"), **static program analysis** (also known as **static analysis** or **static simulation**) is the [analysis](https://en.wikipedia.org/wiki/Program_analysis "Program analysis") of computer programs performed without executing them, in contrast with [dynamic program analysis](https://en.wikipedia.org/wiki/Dynamic_program_analysis "Dynamic program analysis"), which is performed on programs during their execution in the integrated environment.
# Comparison with Python
![JuliaVsPython](https://hackmd.io/_uploads/r1p9sAJ2R.png)
> You can do the same in Python ... - Anon
Yes, but not as easily :wink:. In Julia you have **direct acess** to the internals, you can even check how Julia Base does something as it si written in Julia.
# Julia coming from MATLAB
> But in MATLAB I do it like this - Anon
Sometimes people do not realize that MATLAB is sometimes the only programming language doing something in a way, it is important to enter this learning journey with an open mind :brain:.
**MATLAB |> Julia JuliaCon2024**: https://pretalx.com/media/juliacon2024/submissions/NCVSZ3/resources/MATLAB2Julia_fyD0c1f.pdf
- **Curiosity is key**: Tools and languages evolve, never stop asking what's new
- **Respect language diversity**: Learning Julia can solidify some concepts
- **Listen before prescribing**: "Julia is fast" only matters if the current approach is perceived as slow
- **Don't ask how can I, ask what is the right way to**: To really get good at a new language, take your time to loose old bad habits
- **Learning is an investment**: Make your peace with being less productive for a while
![EmbracingChange](https://hackmd.io/_uploads/Byh2oCJn0.png)
There is a lot of challenges to change, which are not objective. Transition from Python 2 to 3 took almost 15 years.
- IMPORTANT FOCUS TO: lack of SKILLS, and INCENTIVES
- Older people built their whole careers using MATLAB, why change?
- If we change it, suddenly their expertise goes away ... best approach is map the current methods to the new language.
- How do we know is good? tell people it will not be compatible, developers can opt-out of it.
-
# Roadblocks
- Ranges`t = 0:0.1:2pi` Just like in MATLAB! :) (not allocated! `StepRangeLen`)
- **Broadcasting** `y = sin.(t)` ($\sin:\ \mathbb{R}\rightarrow\mathbb{R}$)
- **Plotting**, `plot(t, y)` needs to import `using Plots` (you need to install stuff!)
- `surf` -> `surface(t, t, y * y')` (In Julia most **functions use complete words**)
- **Generic code can change backends**, `add UniCodoPlots`, then set`unicodeplots()`
- You can define functions like `f(x) = sin.(x)` **similar to math**!
- You can also **pipe** functions `y = x |> f |> f`
- Pluto is **reactive**, can define cells like in Excel (we love excel right?)
- Sliders can be bound to variables, `@bind x Slider(0:10)`
- You can mix Markdown and code with string interpolation `mystring = "x = $x"`
- Order of the cells does not matter!
- For loops have their own scope
```julia
for i in 1:10
print(i)
end
print(i) # Not like in MATLAB!!
```
- Let's do **something more complex**, use VSCode:
- Ctr+Enter: Executes line and shows output inline
- Docs can be seen inside VSCode
- Plots appear in the plot pane
```julia
using ControlSystems
using Plots
n, b, k = 2, 1, 1
P = tf(1, [m, b, k]) # System, mass-spring-damp
C = pid(1,1,0,1) # Controler
G = feedback(P * C) # Feddback loop
plot(step(G, 20))
C_tuned = loopshapingPID(P, 1)
G_tuned = feedback(P * C)
plot!(step(G_tuned, 20)) # No hold on, fun!
# More cool graphs for free
res = step(G_tuned, 20)
plot(stepinfo(res))
```
# Packaging and publishing
- Very well thought package environment and package manager (Pkg.jl, everything is in the CI PkgTemplates.jl)
- It force you to write tests (TestItemRunner.jl)
- Docstrings can be used to create automatic documentations (Documenter.jl)
- Community is very helpful! Julia's Slack and Discourse are an invaluable source of information
- TagBot is very useful for tagging new releases (comment`@JuliaRegister register`)
-
# Benefits of using all of these tools
Tim Holy:
![Impacts of continuous integration](https://hackmd.io/_uploads/By_4TCynC.png)
CI reduces reviewer workload to make it less of a bottleneck.
"Open-source" project generally have no CI
![NoCI](https://hackmd.io/_uploads/rybmTRJ3R.png)
How does it look for Julia?
![Julia strongly encourages OSI license and good coding practices](https://hackmd.io/_uploads/SkTZTAyhR.png)
Julia strongly encourages good coding practices, how? because it is easy -> PkgTemplates.jl
![DocumentationJuliaStatistics](https://hackmd.io/_uploads/HkklaRkh0.png)
Median number of contributors: 2
# Documentation
![Documentation - I can make it work](https://hackmd.io/_uploads/BJO03RyhC.png)
Different types of documentation (David Laing) https://docs.divio.com/documentation-system/
![Documentation types](https://hackmd.io/_uploads/ryjih0k3R.png)
- Julia
- NumPy
- etc
# Why should we use Julia coming from MATLAB?
- Mathematical computations
- GPUs on all architectures
- High-performance computing
- Unparalleled composability
- Reproducible
- Foments good coding practices
- For scientific minded person, Julia is very attractive
- For newbies MATLAB is more attractive
# Take home message
![TwitJuliaYannLecun](https://hackmd.io/_uploads/Sydvn0khA.png)
![MatthijsCoxRemperatureJulia](https://hackmd.io/_uploads/Hkyt2Ak3R.png)
![PersonalityBasedOnProgrammingLanguage](https://hackmd.io/_uploads/HJk93012R.png)