Live data from Hacker News

Easy Mode Rust

llogiq.github.io

21–30 of 59 posts

Re: Easy Mode Rust

#21
post #7

Earlier quoted context omitted.

Rust can: - Do the things C and C++ can do. - Without the memory corruption issues those languages are infamous for. - With the conveniences you'd expect of any post-internet language. (A library ecosystem that's unified around a standard build system and package manager, an async IO story, UTF-8 strings, etc.)

Annoyingly said library ecosystem with the standard build system and package manager becomes a pain to deal with when you're trying to do something like add packages made in the language to distros, requiring a bunch of hacks to do things like just have Cargo not try to reach online to get all the dependencies. Also stuff like the way feature flags are used cause a combinatorial explosion of packages just so you can…

In this particular case, I think it's distros who make life hard for themselves by trying to force a square peg into a round hole. Cargo supports vendoring quite well, so, in my opinion, distros should simply vendor all dependencies of a Rust application into its package together with Cargo.lock file.

It may cause some amount of duplication across all packages, but the final amount is arguably will be quite small when measured in MB. Also new release of an upstream crate may cause several updates of downstream packages even if downstream apps did not release new versions, but distros are not known for quick updates either way, so it should not be a big issue.

Re: Easy Mode Rust

#22
post #7

Earlier quoted context omitted.

Rust can: - Do the things C and C++ can do. - Without the memory corruption issues those languages are infamous for. - With the conveniences you'd expect of any post-internet language. (A library ecosystem that's unified around a standard build system and package manager, an async IO story, UTF-8 strings, etc.)

Annoyingly said library ecosystem with the standard build system and package manager becomes a pain to deal with when you're trying to do something like add packages made in the language to distros, requiring a bunch of hacks to do things like just have Cargo not try to reach online to get all the dependencies. Also stuff like the way feature flags are used cause a combinatorial explosion of packages just so you can…

> becomes a pain to deal with when you're trying to do something like add packages made in the language to distros, requiring a bunch of hacks

The package managers in distros are pretty awful for a language like rust though. They are designed for dynamically linked C code, not a language like rust where small, developer published libraries are the norm and there’s no dynamic linking. Distro package managers also don’t support rust’s feature flags well (C programs with compile time config often has the same problem).

Apt, rpm and friends’ biggest problem is they’re awful for developers. If I write a program or library for people to use, now I’m expected to test and keep up-to-date packages (or at a minimum build instructions) for like, 6 different operating systems. “On Debian, apt install packages X and Y. Z is also needed but it’s out of date so install that from source. On Ubuntu it’s nearly the same but library Z is usable in apt. On redhat everything is available but named differently. And gentoo. And arch. And nixos. And FreeBSD pkg. Also here’s the configure script. And CMake, visual studio project files, Xcode project files, homebrew and a windows installer too.

What version of rust is even available on Debian and redhat? Is it 2 months old or 2 years old? Do my rust project’s dependencies work on that version of rustc? Are they available in apt? Urgh just kill me.

Cargo means I can just ship my project in the form I use while developing. Users get all the latest packages, chosen by me, no matter their OS. And I know their build environment is sane. Hate on cargo if you want, but cargo, npm and friends are the only sane way to ship cross platform code.

Re: Easy Mode Rust

#23
post #9

Earlier quoted context omitted.

How do the distro packages work? Are they trying to provide dependencies as pre-built binaries? I didn't know Cargo could consume binaries like that.

I can't speak for other distros, but at least in Fedora what happens is that library code is distributed in various devel packages, where the base package for, say, "futures-io" contains the actual code. So that's the "rust-futures-io-devel.noarch". After this, you get various "subpackages" for each feature. These are mostly there so that you can declare in a package that you need certain features, these packages are…

I installed a few rust binaries the other day, like wasm-tools and the typst compiler. I installed them from cargo. Each program probably had 30-50 dependencies which were downloaded and compiled from cargo.

Do fedora and apt try to mirror all of the packages from crates.io? Are they kept up to date? Is this a manual process, where a human picks and chooses some packages and hopes nothing is missing, or is it a live mirror? If it’s done by hand, what are the chances all the dependencies for some given project will even be available?

Re: Easy Mode Rust

#24
post #13

The self-modifying code mentioned in the Macros section could be automated in an IDE! That is, your IDE should be able to show you the expansion of a macro at that specific place. This feature would help me much more to understand what's going on than navigation to the macro source. I'm not sure if there are any IDEs supporting (temporary) macro expansion already. The output showing all macros expanded is usually too…

[deleted]

Re: Easy Mode Rust

#25
post #18

Cool cheatsheet. As someone new to Rust, what are the benefits versus Go, C++, and C?

A sibling comment already mentioned the type system as a whole, but I wish to highlight one specific feature: Rust has algebraic data types. The term sounds academical, but I honestly can't see a modern, programmer-friendly language not having proper discriminated union types in 2024. Go's lack of sum types is not simplicity. It's a glaring omission, forcing programmers to rely on "idioms" like using tuples to return…

> I honestly can't see a modern, programmer-friendly language not having proper discriminated union types in 2024

Does that really need to be part of the language though, or as long as you can code it, or have it in the standard library, it's fine?

What can Rust's unions do that std::variant cannot?

Re: Easy Mode Rust

#26
Saving this article to point to next time someone asks me yet again "why not rust". I think one could explain the entirety of C in fewer words than this "easy mode" rust.

Re: Easy Mode Rust

#27
post #25
post #18

Earlier quoted context omitted.

A sibling comment already mentioned the type system as a whole, but I wish to highlight one specific feature: Rust has algebraic data types. The term sounds academical, but I honestly can't see a modern, programmer-friendly language not having proper discriminated union types in 2024. Go's lack of sum types is not simplicity. It's a glaring omission, forcing programmers to rely on "idioms" like using tuples to return…

> I honestly can't see a modern, programmer-friendly language not having proper discriminated union types in 2024 Does that really need to be part of the language though, or as long as you can code it, or have it in the standard library, it's fine? What can Rust's unions do that std::variant cannot?

Rust's language-level support for pattern matching (including exhaustiveness checking) is very nice. Most languages with sum types have this feature. It's hard to imagine one without the other. I haven't used `std::variant` much, but I remember finding it unergonomic. Real-world C++ code uses `std::variant` way less often than Rust/functional code uses sum types. Probably, for that reason

UPDATE: also, some advantages coming from the interaction of enums with other Rust language features:

- Because Rust doesn't have a stable ABI, the compiler is free to agressively optimize the layout of enums. The size of an enum is often equal to (rather than greater than) the size of the largest variant, if the variant has some "impossible" bit values (like null pointers and non-UTF8 chars) that can be used for storing the tag.

- Because Rust traits can (and must) be implemented outside of the type definition, you can implement a trait directly for an enum and then use that enum as a polymorhpic "trait object". In C++, if you want to polymorphically use an `std::variant` as a subclass of something, you need to define an ackward wrapper class that inherits from the parent.

Re: Easy Mode Rust

#28
post #20
post #13

The self-modifying code mentioned in the Macros section could be automated in an IDE! That is, your IDE should be able to show you the expansion of a macro at that specific place. This feature would help me much more to understand what's going on than navigation to the macro source. I'm not sure if there are any IDEs supporting (temporary) macro expansion already. The output showing all macros expanded is usually too…

Rustrover (IntelliJ) can do some of this. You can use quick actions to expand a macro inline in the IDE.

As can rust-analyzer, btw. It's very useful sometimes.

Re: Easy Mode Rust

#29
This:

> add .await after every function call, and then remove it again wherever the compiler complains

Should be something Rust (and JS runtimes!) should somehow check/complain. It's just too easy to forget to await on a function returning a Future/Promise. Rust at least will complain if the returning types don't match some expected value and hint a helpful "help: consider `await`ing on the `Future`". Typescript, well tslint, has "no-floating-promises" which is also helpful.

Re: Easy Mode Rust

#30
post #25
post #18

Earlier quoted context omitted.

A sibling comment already mentioned the type system as a whole, but I wish to highlight one specific feature: Rust has algebraic data types. The term sounds academical, but I honestly can't see a modern, programmer-friendly language not having proper discriminated union types in 2024. Go's lack of sum types is not simplicity. It's a glaring omission, forcing programmers to rely on "idioms" like using tuples to return…

> I honestly can't see a modern, programmer-friendly language not having proper discriminated union types in 2024 Does that really need to be part of the language though, or as long as you can code it, or have it in the standard library, it's fine? What can Rust's unions do that std::variant cannot?

`std::variant` is very awkward to use, and has design compromises because it doesn't have language support. Besides, the ability to write something like `std::variant` as a pure library type first requires you to have a very complex type system, more complex than Rust's, and certainly more complex than a "simple" language such as C or Go would ever consider adopting.

C++ is going to have pattern matching "any year now", and it's going to make `std::variant` more ergonomic to use, but on the other hand any pattern matching feature will have to make design compromises in order to support `std::variant` and other mutually-incompatible variant-like library types of which C++ has a bunch of (pointers, unions, `std::optional`, `std::any`, `std::expected`, did I miss any?) Add to that all the zillions of third-party variant-like types (including boost::variant) that exist in the wild because the code base predates C++17 and/or doesn't want to use C++17 features for whatever reason. All this complexity could've been avoided had the language just supported real sum types from the start. Or at least from C++11 up or whatever.

As a sibling commenter noted, algebraic data types and pattern matching with compile-time exhaustiveness checking go hand in hand; I meant to mention the latter in my original comment, but left it out because I consider the latter almost implied by the former.

Post reply on HN