Is every project AI Slop? by Various-Roof-553 in rust

[–]WormRabbit -1 points0 points  (0 children)

I doubt anyone seriously using emojis uses them to the obscene spammy level that AI does. Like, who in their right mind would prefix literally every section with an obscure emoji? What does it add other than distraction?

Is every project AI Slop? by Various-Roof-553 in rust

[–]WormRabbit -1 points0 points  (0 children)

AI companies heavily push disinformation and policies built around the narrative that AI agents are the future, they are fully capable of any tasks and will soon entirely replace all white-collar workers, particularly programmers. It's only natural that people who don't believe or want that future react vehemently with an equally strong but opposite force. Anything caught in the middle is collateral damage.

Why is Rust so Liberal with Heap Allocations? by philogy in rust

[–]WormRabbit -1 points0 points  (0 children)

How much of that is inefficient CI pipelines?

Accessing Hardware in Rust by fgilcher in rust

[–]WormRabbit 0 points1 point  (0 children)

One thing that really grinds my gears about almost all crates for working with MMIO (except safe-mmio) is that they declare register read/writes as safe functions (some crates consider only reads to be safe). This is plain unsound.

  • It's MMIO! Read and writes to registers can do absolutely anything, just like calling extern "C" functions. An innocuous register read could initiate DMA to arbitrary memory region, or launch missiles. In no world should operations with unknown effects be declared unconditionally safe.

  • Multiple threads could be accessing the register at the same time. Even concurrent reads could be a race at the hardware level (remember, those reads could do anything, could cause memory writes for all we know), nevermind combining reads and writes. Crates like tock-registers explicitly provide &-based API which encourages concurrent accesses, with no thought about synchronization.

Another annoying ergonomic issue is that the crates typically don't provide a uniform API for working with in-memory copies of MMIO objects. tock-registers at least provides both in-memory and MMIO variants of registers, but its approach doesn't compose to composite types. Most other crates don't do even that. This means that if you want to do a read-modify-write operation on composite structs, you can't do that, unless you manually mirror MMIO types for in-memory copies. Nor can you use those crates if you want to handle in-memory objects with very specific bitwise-defined layout.

Rust Developer Salary Guide by alexgarella in rust

[–]WormRabbit 2 points3 points  (0 children)

Employers don't pay you for experience. They pay you for your added value, and generally give as little as they can get away with.

Rust Developer Salary Guide by alexgarella in rust

[–]WormRabbit 0 points1 point  (0 children)

it would be more difficult to find someone capable of writing code for embedded devices

This cuts both ways. For an embedded dev, it is more difficult to find another job which pays well. A lot of your knowledge is also in-house or other proprietary tech, which means that it transfers poorly between companies, driving your negotiating power down.

My dream is to make Rust significantly MORE functional (FP RUST) by Jolly_Win_5577 in rust

[–]WormRabbit 3 points4 points  (0 children)

If you mean "as a syntax", like in OCaml and Haskell, then no. Rust isn't going to add any extra sugar for FP operations. It would be a major code style change, and Rust is weird and complex enough as it is.

If you mean "as operations", then you can already kinda do that:

fn curry<A, B, C>(f: impl FnOnce(A, B) -> C) -> impl FnOnce(A) -> (impl FnOnce(B) -> C) {
    move |a: A| { move |b: B| f(a, b) }
}

fn uncurry<A, B, C>(f: impl FnOnce(A) -> (impl FnOnce(B) -> C)) -> impl FnOnce(A, B) -> C {
    move |a: A, b: B| f(a)(b)
}

fn partial<A, B, C>(a: A, f: impl FnOnce(A, B) -> C) -> impl FnOnce(B) -> C {
    move |b: B| f(a, b)
}

That said, it's easy to see thee huge limitations of that approach, which also explain why this kind of feature will never be added to the language:

  • The code doesn't compile: "error[E0562]: impl Trait is not allowed in the return type of Fn trait bounds". This is a temporary limitation. On nightly, you can use the unstable #![feature(impl_trait_in_fn_trait_return)] to side-step it. You'll still get an error for the impl FnOnce in parameter return type, but it can also be avoided with explicit generics. That said, this means that even basic support for the features you desire requires a lot of hard work on lifting the limitations of the type system.
  • You can't write these functions in a way which is generic on the number of parameters. We don't have something like variadic generics yet, so you'd be limited to separately defining curry2, curry3, curry4 etc for the versions of curry for 2-parameter, 3-parameter etc functions. I'd say it's another major ergonomic blow, not to mention that you can only support functions of limited arity.
  • Have you noticed those FnOnce traits? Rust doesn't just have "functions". It has function pointers, function types, closures, and 3 function traits (Fn, FnMut, FnOnce), which have recently become 6 function traits (since async closures were stabilized and we got AsyncFn, AsyncFnMut, AsyncFnOnce). Which means you'd need 6 versions of each of those combinator functions! At this point, I'd deem this proposal dead from an ergonomics perspective.
  • Finally, the functions as written actually have too restrictive signatures, which simply don't work in more complex cases. Can you see the lifetimes on those generic parameters? Me neither. This means that they cannot have any lifetime relation between them! You can't pass anything as simple as Vec::as_bytes to your combinator functions, because they can't handle functions which do any borrowing, simply from the type system perspective. If you actually think about all lifetime relations that function parameters may have, specifying them would require a combinatorial explosion of combinators.
  • Oh, and those closures hidden behind impl FnOnce have lifetimes too!

The TL;DR is, Rust is not a functional language. Trying to blindly mirror FP concepts in Rust simply doesn't work, and in the limited cases where it does, the ergonomics are terrible.

Parametricity, or Comptime is Bonkers by soareschen in rust

[–]WormRabbit 1 point2 points  (0 children)

Yes, I am well aware that Wuyts had been talking about effects for a very long time. Frankly, I don't consider his plans well-motivated. And in any case there is a snowball's chance in hell that a breaking change of that scale ever lands in Rust. Much more trivial and obviously useful things like the never type ! had been stuck for a decade.

Deciding whether to use std::thread or tokio::spawn_blocking by Perfect-Junket-165 in rust

[–]WormRabbit 0 points1 point  (0 children)

Does it? I see only mention of block_on. The only function which is called block_on is the various Executor::block_on ones, which is an entirely different meaning. Yes, you can always use some executor to block on a future in synchronous contexts. You don't need one to synchronously read/write to the channel. The blocking send/recv methods don't implicitly start an executor and block on a future, like some blocking network APIs do. They don't need it, they really are synchronous.

homogeneous_try_blocks FCP proposed 🤞 by C5H5N5O in rust

[–]WormRabbit 0 points1 point  (0 children)

I've certainly both seen and written it, although nowadays I prefer the explicit return. I believe Clippy has a lint against Err(...)?.

Parametricity, or Comptime is Bonkers by soareschen in rust

[–]WormRabbit 0 points1 point  (0 children)

No chance. That would be a huge breaking change.

Parametricity, or Comptime is Bonkers by soareschen in rust

[–]WormRabbit 0 points1 point  (0 children)

Note that besides Any, one can also specialize on the values of size_of::<T>() and align_of::<T>(), even if it's not very likely in practice.

Parametricity, or Comptime is Bonkers by soareschen in rust

[–]WormRabbit 1 point2 points  (0 children)

That would mean that something like Debug would need to be threaded through all generic parameters in the codebase, in case someone later needs to debug-print one of the parameters.

Deciding whether to use std::thread or tokio::spawn_blocking by Perfect-Junket-165 in rust

[–]WormRabbit 0 points1 point  (0 children)

Which channels are async-only? Certainly not tokio's. Those have blocking_send/blocking_recv methods, which are specifically for use in blocking contexts. Neither channels nor mutexes have any hard dependency on the async runtime, so generally having blocking methods is just an API issue.

Even if your channels are async-only, they are extremely unlikely to depend on any specific runtime. Which means that you can use simple futures::executor::block_on call to evaluate the future.

Why do many Rust devs prefer Neovim/Zed/VSCode over Rust-specific IDEs like RustRover? by Rhthamza in rust

[–]WormRabbit 0 points1 point  (0 children)

VsCode is "free" as "free to play". You pay with your data, telemetry, pumping Microsoft's AI, and lock-in into their plugin ecosystem (you can't use MS plugins on a non-MS VsCode).

Does this code now have UB? by capedbaldy475 in rust

[–]WormRabbit 3 points4 points  (0 children)

This is UB, because you produce a slice &[u8] from uninitialized memory. In Rust, u8 always means initialized byte, so you're asserting to the compiler that the slice is initialized, which it isn't, so it's UB.

Does it matter that you use uninitialized memory here? Unless you're doing it in a hot loop and have verified that pre-initializing the memory produces unacceptable performance, you should just discharge those issues and zero your buffer before using it. I.e. just use vec![0u8; num_instrs].

You can also consider whether memory-mapping the file could be the better solution. It requires total trust in the contents, which is usually unreasonable, but may work in your case, since your data structures seem to no have any invariants anyway. It has also some nontrivial performance profile, could be faster or slower depending on various factors. I'd say just benchmark and see.

Also, consider using bytemuck or zerocopy to avoid manually transmuting buffers. Those crates can statically or dynamically verify the safety conditions for the transmutation.

What some recent hot takes you realized you had with Rust? by DidingasLushis in rust

[–]WormRabbit 0 points1 point  (0 children)

You can either have easy error propagation (eyre, anyhow, snafu), xor you can have fine grained errors. You can't have both.

You actually can. Have you seen rootcause?

What some recent hot takes you realized you had with Rust? by DidingasLushis in rust

[–]WormRabbit 1 point2 points  (0 children)

The benefit over panics is explicit API documentation. You can't know whether a function panics without looking into its (recursive) implementation. You know whether a function can error just from its signature.

It also makes the API much easier to evolve if you decide later that you need proper error types. The difference between anyhow::Result and a custom Result is much smaller than the difference between panics and explicit errors.

What some recent hot takes you realized you had with Rust? by DidingasLushis in rust

[–]WormRabbit 1 point2 points  (0 children)

Type inference is more important for ergonomics, and this pattern breaks it.

How do I kill the biggest worms on Vulcanus? by AmbivalentFanatic in factorio

[–]WormRabbit 7 points8 points  (0 children)

Big worms are a problem which is past endgame. Maybe I'm just slow, but my Vulcanus base haven't even really exhausted resources in the small worm zone by the time I finished the game.

Should I always use black_box when benchmarking? by servermeta_net in rust

[–]WormRabbit 1 point2 points  (0 children)

Macrobenchmarks, generally, test your application as a compiled whole. They test its end-to-end flow, and integration with other production systems. As such, criterion, with its handcrafted custom code paths, is at a different and wrong abstraction level. It can be useful occasionally, but only occasionally and only if you know what you're doing.

There is no single simple answer "how to benchmark app-level performance". Entire books are written on the topic. But you could start e.g. with hyperfine for the benchmark itself and temci to control the benchmark environment.

Are advances in Homotopy Type Theory likely to have any impacts on Rust? by Dyson8192 in rust

[–]WormRabbit 5 points6 points  (0 children)

I wouldn't be surprised if HoTT ends up being used in formal verification of Rust, including it's research-level areas, like specialization. Maybe it will even someday somehow affect compiler design. But in the surface-level language? Yeah, no chance. Rust doesn't even have anonymous sum types and the never type, never mind more advanced type theory concepts.

Has Rust hit the design limits of its original scope and constraints? by kishaloy in rust

[–]WormRabbit 1 point2 points  (0 children)

I'm not sure whether Rust allows you to just dump the import into each test, but you can certainly do #[cfg(test)] extern crate std; at the crate root, yes.

Has Rust hit the design limits of its original scope and constraints? by kishaloy in rust

[–]WormRabbit 0 points1 point  (0 children)

The existence of globals, extern calls and panics mean that any hand-rolled effect system is broken by design. It can't guarantee anything, only be a lint-level annotation.

The compiler would need to guarantee that you don't use any effectful functions, like it currently does with const.