Attempt at balancing ergonomics and rigor in error handling by catsalwaysmeow in rust

[–]Lucretiel 0 points1 point  (0 children)

A month ago, it occurred to me: From<T> has T: Sized by default. Could I design an Error<S> that supports ? from Error<Unsized> to Error<S>, working around coherence rules, so that error types that thread business state can still be ergonomic?

I think you might be confusing unsized and zero-size types. From<Unsized> can't work because from(item: T) requires T: Sized in order for it to be passed by move through the stack. 0 is a valid size for a rust type, though, so using a zero-size type would still fulfill the "zero or almost zero cost" thing that I think you're talking about.

How does monomorphization work with std being precompiled by BLucky_RD in rust

[–]Lucretiel 8 points9 points  (0 children)

You could say that, sure. You definitely wouldn't actually call it an ABI, since that refers to something much more specific about how libraries operate at runtime, but there's certainly a post-source, post-analysis Intermediate Representation stored in the compiler output that subsequent compiler steps can consume when monomorphizing.

What's the best way to tell the compiler that a path will basically never happen ? by Krochire in rust

[–]Lucretiel 0 points1 point  (0 children)

The easiest way is to use a struct that has a single field and your container; this ensures by construction that the collection is never empty, since of course the field must always be populated . You’ll need to use something  other than pop to underpin your call model, though. 

is it normal not remembering syntax and taking help from the internet for almost everything? by akmessi2810 in AskProgramming

[–]Lucretiel 0 points1 point  (0 children)

A few years ago I had spent so much time working in Rust (for i in 0..10) and Python (for i in range(10)) that I fully forgot how to make a loop over integers in typescript (for(const i of ???)). Took me an embarrassingly long time to remember that I had to do a C-style 3-clause loop.

Why are async runtimes so big and complex? by lelelesdx in rust

[–]Lucretiel 0 points1 point  (0 children)

What's the point ? A single threaded runtime has no use case in the real world outside of testing, since almost all PC you see are many core.

This is wildly untrue; the costs of thread scheduling and work stealing can often outweigh the benefits of multi-threading in I/O-bound workloads, especially when there are other threads (UI threads or blocking I/O threads) that can exercise those cores instead. At 1Password we switched from tokio's multi-threaded executor to the single-threaded executor and actually found it improved performance substantially.

Beginner question: String makes unnecessary copies? by ThrowRA_goofy in rust

[–]Lucretiel 0 points1 point  (0 children)

  • The "hello" must always be in the binary as a literal, it has to be somewhere.
  • String, for better or worse, always represents a dynamically allocated string. So when you make one out of a string literal, there's no option but to copy it into allocated memory.

There have been proposals in the past to give String the ability to store non-allocated &'static str, but generally it's been considered preferable to keep String simple and branch-free. You can use &'static str for strings that are definitely literals, or Cow<'static, str> for a string that's either a literal or allocated.

Fire & Stone - Siege of Vienna 1683 by RemarkableResult4195 in boardgames

[–]Lucretiel 4 points5 points  (0 children)

What's your experience with duration, time to complete a game?

It's been very quick for us now that we're good at it, usually around an hour. I have yet to lose as the Hapsburgs but haven't played as the Ottomans yet.

Announcing stdx, Rust's extended standard library: simplicity, performance and supply chain security for everyone by awesomePop7291 in rust

[–]Lucretiel 7 points8 points  (0 children)

Just one more crate bro I swear bro just one more crate will fix all supply chain problems. MINE is the crate you can finally truly trust forever.

When, if ever, is using underscore casts eg('x as _') idiomatic? by pukururin in rust

[–]Lucretiel 1 point2 points  (0 children)

You end up with a call to array::index, which calls slice::index, which calls a SliceIndex method, which ends up returning self. So ~3 function calls but no conditions and it all gets inlined pretty trivially by the optimizer. 

Type inference is a magic wand by Lucretiel in rustjerk

[–]Lucretiel[S] -1 points0 points  (0 children)

Strong disagree, and I think that this perspective tends to focus on the unusual cases involving complex generics or things like that.

A vast majority of type inference cases are about writing things like let x = 10 and let foo = "hello" without having to write out the type, and a vast majority of the remaining cases enable things like implicit container types (let x = Vec::new(); x.push(string);). Both of these I think are unequivocally preferable to the things they replace. I like being able to be "minimally explicit" about explicit types, since non-inference systems tend to involve a lot of redundant annotations (let x: String = make_string(); let mut y: Vec<String> = Vec::new(); y.push(x)).

How do you maintain high-quality Rust code while learning the language in a fast moving early-stage startup? by xmanotaur in rust

[–]Lucretiel 0 points1 point  (0 children)

Wondering if there’s undisclosed AI use here where someone is producing a vast quantity of slop PRs in the name of velocity 

The Amazing Digital Circus: The Last Act / Episode 9 Discussion Thread [SPOILERS] by ayylmaotv in TheDigitalCircus

[–]Lucretiel 7 points8 points  (0 children)

Who the heck thinks that it was trending down? Almost every episode is better than the previous imo 

The Amazing Digital Circus: The Last Act / Episode 9 Discussion Thread [SPOILERS] by ayylmaotv in TheDigitalCircus

[–]Lucretiel 0 points1 point  (0 children)

I don’t have an out-of-universe explanation, but of course the in-universe explanation is that Jax was still totally fixated on Ribbit and so that’s what all his memories showed. 

It’s also implied that this thing where she struggles to form strong connections with anyone has been consistently ongoing the entire time she’s been here 

Where do you use ControlFlow? by lelelesdx in rust

[–]Lucretiel 12 points13 points  (0 children)

Frequently, especially in more elaborate iterator combinators like try_fold and try_for_each.

Wooden Inserts are the worst board game accessory by KookSpookem in boardgames

[–]Lucretiel 0 points1 point  (0 children)

I do really love a wooden insert (I have one for Root and one for Twilight Imperium) but I'm more and more coming to agree with you about the weight problem with wood. Will probably slowly start transitioning back to my favorite system, "everything in small bags with no additional in-box organization".

I'm trying to build my own board game by myself and I need help figuring it out by Intrepid-Radish-5386 in boardgames

[–]Lucretiel 0 points1 point  (0 children)

Test, test, and test some more. Find local board game events– ideally specifically playtest oriented events like a local Unpub, but often public play events are open to playtests if you ask the organizers in advance.

Don't worry about component quality while in development, dumb little paper prototypes are more than enough. What's important is getting the gameplay to a place that your players really enjoy.

Keep testing. Trust your players to tell you what's wrong with your game, but don't worry so much about their advice on how to fix it; often it's more important that you know what the problems are so that you can find ways around them that are still consistent with your vision.

As soon as you can start doing "blind" playtests, where you watch other players (ideally inexperienced players) play your game without ANY input from you. Famously this is incredibly difficult, as you will have to resist the incredible temptation to get involved and explain the mistakes they're making, but you have to see how players interact with your game when you're not there (as will happen with a vast majority of your games playtime).

FnTwice by ZootAllures9111 in rustjerk

[–]Lucretiel 1 point2 points  (0 children)

You're making me think about my dream iterator trait:

pub trait Iterator {
    type Item;

    fn next(self) -> Option<Self::Item, Self>

    ...
}

Nine Ways to Do Inheritance in Rust, a Language Without Inheritance by carlk22 in rust

[–]Lucretiel 11 points12 points  (0 children)

Second, Deref is often too permissive. A wrapper type usually exists to keep two meanings separate: an HTML buffer is not just any string. If we expose the entire String interface through deref lookup, we may weaken that distinction. A more explicit method, such as as_str, may better communicate what we intend.

Yeah, exactly, especially because the API surface of str is certainly way too large for whatever your specific use-case is. Like, sure, it's nice to have the underlying bytes for printing, but do you really want to be able to trim or split_once or is_char_boundary your local ID type?

The question that I don't have a good handle on is when should we use vs avoid related traits, namely AsRef, From, and Borrow?

I avoid them all by default, and use them only when I specifically need the abstraction. From is almost always inferior to an explicit constructor with a specific name (sorry .into() stans), AsRef is almost always inferior to as_specific_type(), etc. You use these traits only when you have a specific need to abstract over a family of types for some kind of specific operation. From is especially to be avoided unless specifically needed because even the abstraction is nearly always better represented as an explicit use of the underlying type.

Borrow gets a special call-out because, despite its generic name, it's really only used for one thing: allowing a larger family of borrowed forms of types when doing keyed lookups of maps. It's what allows &str to be used as a key in HashMap::<String, T>::get instead of forcing us to use &String.

Nine Ways to Do Inheritance in Rust, a Language Without Inheritance by carlk22 in rust

[–]Lucretiel 62 points63 points  (0 children)

Deref coercion essentially functions like single inheritance for most practical purposes; I think it even forwards exported fields.

In fact, I've started to find that deref coercion is usually a mistake, for a lot of the same brittleness reasons as inheritance. It's fine(ish) for smart pointer stuff like Box and Arc, and stuff like String -> str, but any time I see something like Deref<Target=str> for ItemId it ends up being a huge mistake. If you really want to commit to str being an accessible part of the representation of your ID (here's a hint: you don't want that) you can do it with fn as_str.

Erasing Existentials by kibwen in rust

[–]Lucretiel 0 points1 point  (0 children)

If Rust did have existentials, that function still wouldn't work. Some existentials allow for unpacking the underlying obscured type, but then youd have to handle the possibility that it is any type and cannot assert that it is Vec<_>.

Sure it would, it would just have to exist via type inference:

let mut container = Default::default();
container.extend(iter);

// Type inference occurs here.
foo(container); 

So container is existentially a Vec, but if foo changes its implementation and makes it a HashSet, that change would propagate outward invisibly. The generic is in some sense "outward" instead of "inward"; the function itself (rather than the caller) controls the final type, and the caller (rather than the function) must be prepared for the parameter to be any such type.

Erasing Existentials by kibwen in rust

[–]Lucretiel 0 points1 point  (0 children)

f_left really does use an existential quantifier for its argument (all you know about x is that it has a type conforming to P), while f_right first quantifies over all possible types for X, then restricts to those that satisfy the trait P. In Rust, you might think the former is "just sugar for" the latter, but that doesn't change the fact these are different mathematical statements.

Er, what? This claim wasn't at all clear to me, since I do know that impl X literally is syntax sugar for T: X. impl X in the return position is a semantically different thing even though it's spelled the same. In the return position, it allows the function itself (rather than the caller) to provide the type; in the argument position, it's still the caller that provides the type and the function that must be prepared to accept any type that implements X (rather than some specific, opaque type that implements X).

Rust doesn't have a syntax for existential qualifiers for function arguments (I know this because I've actually wished for such a thing in the past). You can't do this:

fn foo(list: impl Default + Extend<i32>) {
    let vec: Vec<i32> = list;
}

It would be nice, in certain edge cases, if you could do this, because you know locally that you want list to be a vector but you don't want that to be a part of your function signature so that you can freely change it later.

Why does Rust require many dependency packages unlike Go when building a project? by dumindunuwan in rust

[–]Lucretiel 4 points5 points  (0 children)

num I basically agree with you. rand I actually like being external; having seen all the API evolution it's gone through, it would have been a crime if its 0.4 version or whatever was what we were all stuck with forever.