# Blog post: Rust vs Julia in scientific computing

**URL:** <https://discourse.julialang.org/t/blog-post-rust-vs-julia-in-scientific-computing/101711>\
**Category:** Offtopic\
**Tags:** rust\
**Created:** [July 17, 2023, 10:17pm UTC](https://discourse.julialang.org/t/blog-post-rust-vs-julia-in-scientific-computing/101711 "2023-07-17T22:17:20Z")\
**Posts on this page:** 1\
**Showing post:** 55

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 19, 2023, 2:38am UTC](https://discourse.julialang.org/t/blog-post-rust-vs-julia-in-scientific-computing/101711/55 "2023-07-19T02:38:38Z")

</div>

> [@Mo8it](#):
>
> `std::thread` in Rust is low level and not comparable with `@threads` in Julia because you don’t have to manually spawn and join threads, maintain a thread pool etc.
> 
> Since the standard library is “thin” by design, it is very common in Rust to use crates for rather simple things like generating random number with `rand` and work-stealing multi-threading with a thread pool using `rayon`.

I would make a similar argument about Julia Base. It’s frustratingly bare in some areas and quite difficult to add new functionality to it. With respect to `Base.Threads.@threads`, I have very low expectations of it.

> [@Mo8it](#):
>
> Such “core crates” are actually maintained by people very close to the standard library and compiler development. The coauthor of `rayon` for example is Niko Matsakis, the [team leader in the language team](https://www.rust-lang.org/governance/teams/lang).

This argument also applies to ThreadsX.jl and Tranducers.jl. The author, Takafumi Arakaki, @tkf, is a Postdoctoral Associate of the Julia Lab at MIT: [Current members](https://julia.mit.edu/people/) .

> [@Mo8it](#):
>
> What you suggest would imply that I have to implement a random number generator for a fair comparison of generating random numbers in Rust and Julia.

My suggestion is that if you are going to show “core” crates in Rust that you should compare to them to “core” packages in Julia. Admittedly, the concept of a “core” crate or package is a bit fuzzy.

> [@Mo8it](#):
>
> @Benny As you mentioned, `fill`, `zeros` and `ones` are not the same as preallocation with `undef`. The three functions have an overhead caused by overwriting the memory with the respecting value first. Plus, using `undef` is an [official recommendation in a performance tip](https://docs.julialang.org/en/v1/manual/performance-tips/#Pre-allocating-outputs) that I link to in the blog post. I don’t see how criticizing an official recommendation is inaccurate.
> 
> I would happily edit the blog post if the official recommendation is changed 🙂
> 
> Even if it was not an official recommendation. Just having this “feature” in the language is a problem if we want to prevent _undefined behavior_ in Julia. I would suggest marking it as deprecated to save the Julia community hours of horrible debugging of undefined behavior.

There an important nuance here. Allocating uninitialized memory is not undefined behavior.

Here’s an example straight out of the [Rust documentation](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#examples). Note that it says _this is not UB_.

```julia
use std::mem::MaybeUninit;

// Create an explicitly uninitialized reference. The compiler knows that data inside
// a `MaybeUninit<T>` may be invalid, and hence this is not UB:
let mut x = MaybeUninit::<&i32>::uninit();

```

What is undefined behavior is attempting to read that memory before it has been initialized.

Zero initializing memory may not incur overhead in all circumstances, although Julia’s `Base.zeros` always does. One of my critiques of Julia is that `zeros` in Julia Base is implemented with an explicit `memset` rather than `calloc`. Depending on the operating system, libc implementation, and perhaps the amount of memory being allocated, `calloc` may not incur _additional_ overhead because the OS or libc may already know that already zero initialized memory exists. New memory pages allocated to a process must be zeroed out as to not leak data from one process to another. I’ve elaborated on this in the discussion of [ArrayAllocators.jl](https://discourse.julialang.org/t/ann-arrayallocators-jl-integrating-calloc-and-aligned-memory-into-array-construction/80356/1).

The [history](https://github.com/JuliaLang/julia/issues/24595) of the `ArrayType{T}(undef, sz...)` syntax may be of interest here. Basically, we wanted some indicator that something `undefined` was happening here. Some advocated for a shorter syntax such as `ArrayType{T}(sz...)`, but it was felt that this did not sufficiently alert that user about what they were doing. The term `undef` was chosen over `uninit` or `uninitialized`. Essentially, the use of `undef` is meant to be regarded as similar to `unsafe`.

The performance recommendation you cite correctly uses this as it does initialize the memory before using it.

---

_[View the full topic](https://discourse.julialang.org/t/blog-post-rust-vs-julia-in-scientific-computing/101711)._
