sum_of_squares(v) = sum(x^2 for x in v)
v = randn(1_000_000)
# first call: includes compilation
@elapsed sum_of_squares(v)0.00999075
Julia was built to solve what its authors called the two-language problem (Bezanson et al. 2017): you prototype in a high-level, productive language (R, Python) and then, when the code is too slow, rewrite the bottleneck in C, C++ or Fortran. The result is that the library you use and the code you write are written in different languages — which makes the inside of a package opaque to its user.
In Julia, vegan would be written in Julia. That matters to an ecologist for three practical reasons:
metaMDS does something unexpected, the answer is in Fortran. In Julia, @edit drops you into readable source.These benefits are not free, and this book will not pretend otherwise. Let me lay out some of the gains and the costs.
| What you gain | What you give up |
|---|---|
| Fast loops without vectorizing | The community-ecology ecosystem (vegan, picante, FD) |
| Readable package source | Generalized additive models (mgcv) |
MixedModels.jl, with lme4’s formula syntax |
DHARMa-style residual diagnostics |
| Composition through multiple dispatch | Critical mass of tutorials and Stack Overflow answers |
One reproducible environment (Project.toml + Manifest.toml) |
Compilation latency on first call |
The right-hand column is an assessment of the Julia ecosystem as of August 2026, made by checking the public package registries. Ecosystems change. Before concluding that something does not exist, check — and if you find a package that fills one of these gaps, this chapter is wrong and should be corrected. I will try to update it regularly, but I certainly won’t manage to keep everything current.
If your analysis is essentially vegan::adonis2() followed by metaMDS(), use R. This book stops at GLMs precisely because that is as far as the “use Julia” recommendation holds without caveats.
Julia compiles each method the first time it is called with a given set of types. That is what makes the second (third, fourth, …) call fast, and the first one slow.
sum_of_squares(v) = sum(x^2 for x in v)
v = randn(1_000_000)
# first call: includes compilation
@elapsed sum_of_squares(v)0.00999075
# second call: execution only
@elapsed sum_of_squares(v)0.000493
The difference between the two is compilation time. In a real analysis session you pay that cost once. In a short script that runs a single time and exits, the compilation cost can have a noticeable impact. It is worth understanding the phenomenon a little before concluding that “Julia is a slow language”.
juliaup and reproduce the latency example above. How long does your first call take?