I'm still dreaming of a world where Rust had Nim syntax.
I'm still dreaming of a world where Rust had Nim syntax.
Rust has a bigger ecosystem of course, but Nim's is pretty decent and you can use C, C++ and JS libs natively for anything else.
Overall, I like it, but I could not justify using it in an enterprise setting without knowing that the direction of the language is going towards what is now the established minimum safety, which is borrow checking and no UB.
Zig might be a language you are interested in. Simple like C with sensible ways of dealing with UB and bounds checking, as well as options instead of Nulls.
Can you mention which part of the Rust language you found complicated (in real world), excluding the ownership/memory management area (which includes: bck, lifetimes, smart pointers, traits related to synchronization)?
I read a lot of comments about Rust's complexity, and while nobody doubts the complexity of the ownership/memory management, there's a very common lack of details when it comes to the rest of the language.
Not sure what you mean there, there's product types with tuples and objects, and sum types as object variants.
> Pattern matching
Eh, I mean it's just sugar over a case statement.
let
num = 5
str = case num
of 1: "One!"
of 2, 3, 5, 7, 11: "This is a prime"
of 13..19: "A teen"
else: "Unknown" # Compile error if all cases arent covered.
As you say there's libraries that let you deconstruct and partially match more complex types if you need that. Being able to create things like pattern matching, async, and novel multithreading runtimes as a library in Nim shows how powerful (and useful) the metaprogramming is.Enums in Rust are more interesting, but again nothing you can't do with an object variant.
Nim macros are a lot nicer than Rust's, but Rust's trait system is very powerful and expressive. Sure, you can do something like that with Nim's macros, but you can't expect that all third party code is going to play nice.
That's the problem with the macro approach: it's great because it's ultra-flexible, but it also sucks because it's ultra-flexible. Everybody ends up doing their own little DSL that fits their use case or their personal taste, and it adds friction at the interfaces.
Because having tried to explore these questions by studying Nim projects, going through a book and working on a game engine in it the past months; I've found that ufcs+overloading covers the static traits scenario, and it feels like the runtime traits object scenario is better self-rolled (I don't really want the compiler impl'ing vtables underneath me, save deciding to reuse a static dispatch feature for a dynamic one; if I want a struct of func ptrs I will make a struct of func ptrs.) at least for my usage. Various Nim code I come across is usually pretty readable, and I don't need to invent macros willy nilly.
ufcs feels more elegant than needing to decide whether to namespace a function inside a struct or not (or which one), which is what most langs (including Rust) seem to do.
Nim stops race conditions by controlling data passage among threads (disallowing shared data between threads, in general) and always has.
I am not familiar enough with Rust to say that everything rust can do and assure is indeed covered in Nim; however, plain Nim without using the escape hatches (which like Rust unsafe code, exist for those times you must use them) is safe.
Nice.
Do you have more resources on that?
Also, does Nim have a WASM target?
https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc...
https://www.youtube.com/watch?v=aUJcYTnPWCg
https://github.com/stisa/nwasm
You can also go an Emscripten route: https://hookrace.net/blog/porting-nes-go-nim/
Re: borrow checking: https://nim-lang.org/docs/manual_experimental.html#view-type... It's still pretty early and also IME the mix of arc (which is determinstic) with manually managed memory (esp. through some data structure that manages entity data like entt) has been pretty nice.