# Does knowing Rust make you a better Julia programmer

**URL:** https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668
**Category:** Offtopic
**Tags:** rust
**Created:** [November 15, 2024, 9:41am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668 "2024-11-15T09:41:03Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![marquito](https://avatars.discourse-cdn.com/v4/letter/m/ee7513/32.png) [@marquito](https://discourse.julialang.org/u/marquito)
#### Post date: [November 15, 2024, 9:41am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/1 "2024-11-15T09:41:03Z")

</div>

I am interested in the usual “does knowing X make you better at Y” theme,  
where X=Rust and Y=Julia, as someone who more or less knows Julia (and basic C programming), but has no experience with Rust yet.

If you think that knowing Rust does not necessarily make you a better Julia programmer, what does this say about the design of Julia and the art or science of writing good/idiomatic Julia code (i.e. no allocations, runtime dispatch, cache invalidation).

---

<div class="post-metadata">

### Author: ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)
#### Post date: [November 15, 2024, 10:51am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/2 "2024-11-15T10:51:24Z")

</div>

> [@marquito](#):
>
> what does this says about the design of Julia and the art or science of writing good/idiomatic Julia code

When I have to code in rust, I clearly feel, that I am fighting the language. Every `borrow` makes me angry… Or is the language fighting me?

When I enjoy doing poetry in Julia it’s just a good time. I see solutions and reliefs.

That’s my experience emphasized.

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [November 15, 2024, 12:15pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/3 "2024-11-15T12:15:59Z")

</div>

From my own experience then yes, learning Rust did make me a better Julia programmer.

I think part of this is just that learning new programming languages that does things differently makes you a better programmer. You get to see which language constructs are basic (like loops and functions), and which vary a lot between languages (like the inheritance or object model). You get to see which code patterns work well in one language and poorly in another, and which aspects of languages and poorly and well designed.

With Rust in particular, it _might_ be especially useful to know. I can’t tell because I don’t know a lot of languages, but:

- It’s a practical language, which makes it more useful to learn than e.g. J or brainfuck. Like, you don’t really learn a lot about practical language design from an impractical language
- It’s just very, very well designed, both in the macro aspects, but also, it’s just full of well designed, ergonomic and hard-to-misuse APIs. It’s been _so often_ that I’ve seen an API in Rust and thought “wow this is much better than Julia, and now I’m kind of sad Julia’s is so much worse by comparison”.
- It has a lot of ‘niceties’ of different programming languages: A bunch of functional programming, algebraic data types, a flexible trait system. Also some tooling nicities like a good, built-in formatter and linter, and a good package manager.
- The borrowchecker is unique and interesting to get under your skin

So yeah, go for it!

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [November 15, 2024, 3:52pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/4 "2024-11-15T15:52:06Z")

</div>

Just out of curiosity, which APIs do you consider better in Rust and why?  
Imho, especially multiple-dispatch can and has been used for some very clean APIs in Julia.

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [November 15, 2024, 4:07pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/5 "2024-11-15T16:07:01Z")

</div>

Several examples are in this [blog post](https://viralinstruction.com/posts/badjulia/), especially vis a vis Rust. I agree with most (maybe all?) of it.

I didn’t find the borrow checker so burdensome in the end. You have to make an effort to absorb the rules. But I suppose your experience with the borrow checker depends strongly on the type of code you have to write. For some projects it may be more difficult.

I suspect that Julia has a lot of more applied like things in it and this has taken a lot of resources. For example `Base` has a lot of things to support technical computing and on low and high levels. My impression is Rust devs were more focused on designing a coherent, core, language. Julia developers also wanted to make an interactive tool for numerical computing. I didn’t do any kind of audit to back this up.

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [November 15, 2024, 8:05pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/6 "2024-11-15T20:05:44Z")

</div>

Ah ok, that’s were your coming from. Was thinking more about ease of use and composability of APIs where I find Julia often nicer than Rust.

In any case, adding to the original question of this thread: Learning another programming language is always good, especially if it requires/provides a different perspective on programming. Rust has a strong focus on correctness and builds on modern developments in type theory. Imho, it is more similar to Haskell than to Julia in this respect. Julia shows more of a Lisp heritage with dynamic typing, REPL driven workflows and multiple dispatch with implicitly defined interfaces (called protocols in Common Lisp). Overall, this can lead to quite different designs and not every best practice of Rust will work well in Julia (and vice-versa).

---

<div class="post-metadata">

### Author: ![sbuercklin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sbuercklin/32/15728_2.png) [@sbuercklin](https://discourse.julialang.org/u/sbuercklin)
#### Post date: [November 15, 2024, 10:10pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/7 "2024-11-15T22:10:36Z")

</div>

Learning how Rust handles traits and features via wrappers really changed how I think about project architecture in Julia. Rust and Julia both use composition as a core technique for building complex systems, and learning how to build systems that compose in Rust really enforces a lot of structure that I wish we had in Julia.

I think the borrow checker gets entirely too much focus when people discuss Rust. Instead, I’m a major proponent of Julia needing some sort of interface abstraction, in large part thanks to how Rust handles them.

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [November 15, 2024, 10:36pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/8 "2024-11-15T22:36:32Z")

</div>

I agree that the type system in Rust is nice. Yet, Julia is considerably more open in that every function is generic and can potentially be re-defined. Further, as data types are values even dispatch on specific values is possible and e.g., used to implement chain-rules or inverses for functions.  
To me, a major difference is that Rust distinguishes between generic functions – which have a single implementation – and methods – with multiple definitions for different types (had discussed that difference [previously](https://discourse.julialang.org/t/specifying-function-contract/108983/4) in the context of Haskell). Thus, more thought is required up-front about what should be extensible and what not, which might be a good thing, but also restricts potential combinations/re-use when these had not been considered.

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [November 16, 2024, 10:29am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/9 "2024-11-16T10:29:06Z")

</div>

Some APIs that I think are better in Rust:

- The `Path` API, which we just don’t have in Julia. I think that’s a straight up design mistake on Julia’s side.
- Rust’s iterators which are consistently lazy, while also being extremely efficient. Many of the useful APIs on iterators are also more easily available because they’re not behind an `Iterators` sub-module: In Julia, you often have to do this:

```julia
itr = get_my_itr(x)
itr = Iterators.map(foobar, itr)
itr = Iterators.filter(foofilter, itr)
itr = Iterators.drop(itr, 3)

# or alternatively
itr = Iterators.drop(Iterators.filter(foofilter, Iterators.map(foobar, get_my_itr(x))), 3)

```

Whereas in Rust:

```julia
let mut itr = get_my_iter(x).map(foobar).filter(foofilter).skip(3)

```

Note also how the dot-chaining makes the Rust iterator much easier to read (at least in my opinion).

There’s more stuff about iterators, of course: In Julia, it’s quite hard to implement something like `Iterators.Stateful`, for two reasons:

- Everything breaks when you try to do it, because the whole ecosystem somehow just false assumes iterators are stateless
- It’s difficult to figure out what field type the state of an iterator should be. That is - when the `Stateful` should store the state of the iterator it wraps, what type is that? It’s unknowable. This is because Julia requires you to handle the iteration state, while _also_ claiming the iterator state is a private object.

Rust’s slice type (e.g. `&[u8]`) is super basic and extremely useful. We don’t have something like this in Julia but we absolutely should have. And then we should implement major parts of Julia using that type.

In a similar vein, I like how Rust defines most of its string API on `&str` instead of `String`. That makes it much more consistent in avoiding string allocations compared to Julia, where the choice is typically either a slow, generic `AbstractString` fallback, and an optimised `String` method that requires allocating a new `String`.

Oh and another - I’ve been recently looking into Rust’s IO API compared to Julia’s unstructured collection of IO-related functions that we could call an “API”. Here they’re almost incomparable: Rust has a carefully documented set of 5 (!) methods that does nearly all the heavy lifting. Julia has a spawling, inconsistently designed mess that literally no-one understands.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [November 16, 2024, 10:32am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/10 "2024-11-16T10:32:51Z")

</div>

> [@jakobnissen](#):
>
> The `Path` API,

What’s that for?

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [November 16, 2024, 10:39am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/11 "2024-11-16T10:39:53Z")

</div>

Operating on paths. IMO, we should have had `@p_str` defined in Julia, such that you should do `open(p"/my/path") do ...`

There are a bunch of code smell in Julia that arises from not having a path type. E.g.:

- Why are there so many functions with `path` in the name? Like `joinpath`, `splitpath`, `abspath` etc. Isn’t that a bit like if there were `sumvector`, `mulvector`, `divvector` etc? That to me suggests it should instead be `join(::Path)`, `split(::Path)` etc.
- There is no reason I know of why `open("abc/def/ghi.txt")` shouldn’t work on Windows. The separator `/` is just a convention - it really is the “same” path as `abc\\def\\ghi.txt`.
- A lot of methods take an `AbstractString`, then interpret it as a path, in a quite dubious manner. E.g. `eachline(::String)`, which weirdly doesn’t iterate the lines of the string. Instead, it opens a file at the _path_ given by the string and iterates lines from that file. Similar with `copyuntil`. In practise, that means you have to instantiate `IOBuffer`s just for dispatch purposes, which is slow and inefficient.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [November 16, 2024, 11:41am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/12 "2024-11-16T11:41:00Z")

</div>

Apologies, this reply has gotten much longer than I originally intended!  
TL;DR: Once you’re familiar with “regular” Rust, take a look at `async` and how it works under the hood. At the very least, the differences in usecases this was designed for should definitely further your understanding of general programming topics. So my take is that “knowing Rust” not only makes you a better Julia programmer, but a better programmer in general. Not because Rust is so much better than Julia, but because it exposes you to different paradigms.

* * *

One Rust API that’s probably pretty unknown to Julians that I think follows the same trend as the IO API mentioned above (in terms of being at least designed) is their async API (although I’m _very_ sure that this is a controversial take 🙂 ).

Async functions in Rust don’t run at all until something actively polls them. In essence, the use of an async function in Rust is lowered to an implicit statemachine, where waiting on a task is equivalent to transitioning to another state in that statemachine. This allows custom so-called executors to be written that can make different decisions in how the tasks are run & scheduled (e.g. think of an async scheduler on an embedded system, which has very different requirements from one designed for web-request throughput!). This also means that this implicit statemachine can be (up to a point) manipulated to provide additional guarantees, e.g. by guaranteeing a specific (even reproducible) order of execution.

This design leads to the very curious result that Rust-async can compete with actual RTOS in terms of performance on embedded hardware! For some more information on how & why this is, see this blogpost:

> **[Async Rust vs RTOS showdown! - Blog - Tweede golf](https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown)**
>
> It's time for another technical blog post about async Rust on embedded.
> This time we're going to pitch Embassy/Rust against FreeRTOS/C on an STM32F446 microcontroller.

The current Julia runtime/`@async` machinery can’t even begin to compete here, for a number of reasons that I won’t get into here so that this reply doesn’t grow more than it already has 🙂

Julia runs `@async` blocks eagerly and everything is hidden behind the actual Julia runtime, which means that the implicit statemachine can’t be manipulated and scheduling decisions depending on the blocking state of individual `Task` objects can’t be influenced. I tried writing such a Rust executor once for Julia, but ran into the problem that not everything that blocks a `Task` yields back into the scheduler (`write` on a non-`stdout`/`stderr` file doesn’t, for example). Not to mention that the Julia scheduler wouldn’t be aware of this either, which means that when it resumes a previously blocked task, the task wouldn’t then call back into my own scheduler for the actual scheduling decisions.

Further, composing `async` functions in Rust feels a bit easier than doing the same in Julia with `@async`/`@spawn`, where fetching the result of a `Task` is necessarily type unstable at the moment, which also means that composing tasks can often be much slower than necessary due to the forced dynamic dispatch.

Of course, that’s not to say that the async API in Rust is perfect - far from it. It’s certainly a difficult topic, and I’d wager most Rustaceans would agree that the current state of async is not at all satisfactory. Still, I’d like to think that even with all its warts, it’s a bit closer to “good API” than what we have at the moment. If you’re interested in what the current state of async in Rust is, this is a good in-depth summary:

> **[The State of Async Rust: Runtimes | corrode Rust Consulting](https://corrode.dev/blog/async/)**
>
> Recently, I found myself returning to a compelling series of blog posts titled
> Zero-cost futures in Rust
> by Aaron Turon about what would become the foundation of Rust’s async ecosyste…

Although you might want to wait with diving into this until you’re more familiar with Rust - quite a large part of the issues of `async` in Rust are due to the interactions with the borrow checker and lifetimes, so having a fairly good grasp on that is pretty much required to understand all of the nuances.

---

<div class="post-metadata">

### Author: ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)
#### Post date: [November 16, 2024, 11:53am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/13 "2024-11-16T11:53:07Z")

</div>

I would also add that we need AbstractPath to allow polymorphic implementations, which can be used with clouds and archives. I have also used AbstractPath to define the hashing of a directory at load and save serialising methods that reduces code duplication.

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [November 16, 2024, 10:03pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/14 "2024-11-16T22:03:59Z")

</div>

Thank you, that is very interesting and helpful.  
Iterators are indeed a bit tricky in Julia and I usually reach for [Transducers.jl](https://github.com/JuliaFolds/Transducers.jl) instead. Imho, this is the right abstraction in that it decouples the actual traversal from the specification of desired operations. Also agree that pathnames could benefit from a proper abstraction (probably not super easy though, i.e., in Common Lisp it seems to be a running joke that someone always wants to fix pathnames there, but these come from a time with more diverse operating systems and various implementations of the language standard with slightly different interpretations).

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [November 16, 2024, 10:12pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/15 "2024-11-16T22:12:25Z")

</div>

I can do this:

```julia
julia> (1:10).map(x -> x + 1).filter(iseven).drop(2).collect()
3-element Vector{Int64}:
  6
  8
 10

```

And it’s efficient:

```julia
julia> @btime (1:10).map(x -> x + 1).filter(iseven).drop(2);
  0.991 ns (0 allocations: 0 bytes)

```

But it’s still only a curiosity. It’s not general or elegant to implement:

```julia
using DotCall
import Base.Iterators: Filter
import Base.Iterators: Drop
import Base.Iterators: drop as idrop
import Base: collect, Generator

function rmap(itr, f)
    Iterators.map(f, itr)
end

function rfilter(itr, f)
    Iterators.filter(f, itr)
end

@dotcallify UnitRange (map=rmap, collect)
@dotcallify Generator (map=rmap, collect, drop=idrop, filter=rfilter)
@dotcallify Filter (map=rmap, collect, drop=idrop, filter=rfilter)
@dotcallify Drop (map=rmap, collect, drop=idrop, filter=rfilter)

```

This is partly due to a few easy improvements that could be made to `DotCall`. (Eg, the macro can’t handle a non-Symbol name like `Iterators.map`.) But even then I doubt it would be very composable.

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [November 16, 2024, 10:34pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/16 "2024-11-16T22:34:07Z")

</div>

> [@jakobnissen](#):
>
> There are a bunch of code smell in Julia that arises from not having a path type

Could [FilePathsBase.jl](https://github.com/rofinn/FilePathsBase.jl) be of interest?

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [November 16, 2024, 10:37pm UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/17 "2024-11-16T22:37:39Z")

</div>

> [@rafael.guerra](#):
>
> Could [FilePathsBase.jl](https://github.com/rofinn/FilePathsBase.jl) be of interest?

> [@Blog post: Rust vs Julia in scientific computing](https://discourse.julialang.org/t/blog-post-rust-vs-julia-in-scientific-computing/101711/87):
>
> Can you show some example(s) of those type instabilities in cases where they are actually relevant (not by design)? I think type instabilities that are by design are still problematic. For one, they prevent static analysis of your program. Both by blocking inference and by spamming the JET output so you miss the real issues Eventually, they might also prevent compilation of your program to static binaries (but let’s see). Some examples of this are: Spurious instabilities in Base. These ten…

@jakobnissen and others have also mentioned the lack of composibility because it’s not adopted ecosystem-wide.

EDIT: There is a good discussion in this Discourse post: [Better handling of pathnames](https://discourse.julialang.org/t/better-handling-of-pathnames/36792)  
One comment asked why methods are not included for functions taking filenames in `Base`. I started from scratch following the example of Rust’s `std::path` with a type `Path` and `PathBuf`. It was relatively little work to add wrapper methods for many functions in `Base` (that for some reason are not wrapped in `FileSystemBase`). `PathBuf` is used for constructing paths and wraps `IOBuffer`. Rust’s `std::path` is more focused on efficiency and minimizing allocation. It may also be simpler in a way than `FilePathsBase`. There is no equivalent of a type hierarchy (which would be implemented with traits). It’s just two types each of which wraps a string. (Rust’s approach to mutability means it doesn’t need an `IOBuffer` for `PathBuf`.) A large amount of `std::path` wouldn’t make sense in Julia because of different language semantics. Still, I think it’s worth exploring. But I can’t invest much time at the moment.

---

<div class="post-metadata">

### Author: ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)
#### Post date: [November 17, 2024, 2:09am UTC](https://discourse.julialang.org/t/does-knowing-rust-make-you-a-better-julia-programmer/122668/18 "2024-11-17T02:09:46Z")

</div>

> [@jakobnissen](#):
>
> The `Path` API, which we just don’t have in Julia. I think that’s a straight up design mistake on Julia’s side

My understanding is that the path API was inspired by the corresponding Python API at the time and never revised since, the problem is that Python got a much better API shortly after with a proper path type and we got stuck with the old design. Had that been designed a few months after we’d probably have had something different 😅
