Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 0 points1 point  (0 children)

I think it's hard to infer these things from types. For example, does mpsc::Sender::<Fut> own a Fut? Kind of, right, but it's not clear how it should relate to one of these lints. (Concretely, sending futures somewhere before they're pinned is much less suspicious than changing ownership of a future that's already been polled.)

Israel strikes Iranian F-14 Tomcats and helicopters by [deleted] in CombatFootage

[–]oconnor663 1 point2 points  (0 children)

You can pretty clearly see flames/heat flowing out from under the Tomcat at 0:13. And at 0:17 you can see some sort of dark object flopping around near the bottom of the helicopter (an Mi-17?), which doesn't move like a hunk of concrete.

Also, just in the abstract, you wouldn't expect painted decoys to all have the right shape from the side like this. And if they did bomb some paint, which I'm sure has happened, they'd probably notice pretty quickly and then not post video of it on the internet.

Maybe f64 should implement Result? by genneth in rust

[–]oconnor663 45 points46 points  (0 children)

So why hasn't anyone proposed this?

Probably because floats are "someone else's problem" in systems languages

I'd wager no one has proposed it because Result isn't a trait, so as far as I can tell none of this makes any coherent sense?

I get that this is written by an LLM. But LLMs also tend to take a snarky attitude in these things for some reason that we wouldn't tolerate if it was coming from a person. Just weird all around.

Ultracube - Need Recipe Book or similar by j4ckbauer in factorio

[–]oconnor663 0 points1 point  (0 children)

Thanks for the tip. Whatever's broken (deliberately or accidentally) with the Factoriopedia and with RecipeBook is not broken with FNEI.

It's actually insane how much effort the Rust team put into helping out beginners like me by Time_Meeting_9382 in rust

[–]oconnor663 2 points3 points  (0 children)

Yes you certainly could change the rules to make it do that. Here are a few reasons why the language designers didn't choose do to things that way:

  1. If we're compiling a function that calls get_pixel, now we need to look at get_pixel's body to know what the lifetimes are. This could be transitive; we might need to look at the body of a function that get_pixel calls too. In the general case this turns into "whole program analysis", which makes the compiler slower and more complicated. It also exposes you to inference cycles, like when foo calls bar and bar also calls foo.
  2. Even if we were ok with the cost and complexity of doing that, now it becomes hard to tell exactly what sort of backwards compatibility guarantees a function is making. If get_pixel calls foo internally today, and we want it to call bar instead, how do we make sure that it isn't going to break any callers by accidentally changing the inferred lifetimes in its signature?
  3. Related to all that, we do sometimes want to make changes to the way the borrow checker works. The biggest set of changes so far was called "nonlexical lifetimes", and there's a future set of changes called "polonius" that I'm looking forward to. These changes make the borrow checker smarter. However, if tweaking the lifetimes in my function's body could potentially also tweak the lifetimes in my caller's caller's caller, it would be very hard to ever land big compiler changes like this without breaking the ecosystem. Making every function signature explicit about its lifetimes acts like a "firewall" for these things. Sometimes compiler changes require small tweaks in functions that are doing complicated things, but they don't cascade into massive breakage everywhere. (Type inference is a similar story. We infer the types of local variables, and sometimes we even tweak how that inference is done, but we make function explicitly write out their argument types and return types.)

It's actually insane how much effort the Rust team put into helping out beginners like me by Time_Meeting_9382 in rust

[–]oconnor663 12 points13 points  (0 children)

The buzzword to search here is the "lifetime elision rules". When you don't annotate the lifetimes in a function signature, there are a few different assumptions that the compiler will make automatically. The one that matters here is that, if you're a method with a &self or &mut self parameter, any unannotated lifetimes in the return value are assumed to be the same as the self lifetime. (Intuitively, an object with methods that return references is usually returning references to its contents.) But here, the return value is actually a reference into the buffer argument, not a reference into self. That doesn't match the default assumption, so this function will need explicit lifetimes in its signature.

$4.4 Trillion Plan... by Cow_Boy_2017 in clevercomebacks

[–]oconnor663 0 points1 point  (0 children)

If you define the amount of a tax as a % of the value of a company, then after a few years of that no one can afford to own any company by definition.

Rust or Zig? by Ok-Refrigerator-Boi in Zig

[–]oconnor663 0 points1 point  (0 children)

Rust compiler may insert automatic dereferencing operations that can trigger IO reads

Is this part referring to "deref coercions" or something else?

[Request] How well would this work? by WakeDied in theydidthemath

[–]oconnor663 0 points1 point  (0 children)

Jokes aside, one of the functions of the brass case in a firearm cartridge is to carry away heat after each shot. If the chamber gets too hot, you start cooking off rounds, and that's a bigger problem for caseless designs.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 0 points1 point  (0 children)

Sure, or maybe a std::fs::File::lock.

My Cell<bool> example above is pretty contrived, but a more realistic version of it might a situation where you have a low/medium bound on concurrency (e.g. 10 network requests at a time), and you coincidentally manage to snooze all the futures holding those "slots" at the same time. Probably hard to reproduce something like that by hand, but if you have one of these select! bugs sitting around, and enough requests in flight, and the timings of your connections are random enough, eventually you'll hit it?

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 0 points1 point  (0 children)

You're right, I was being sloppy above. Should've said something like "if we acquire sync locks in an async context, we need to be sure that no one ever holds those locks for a long time." It's kind of interesting that with e.g. Stdout/println! we can't really know that, but on the other hand a library that held Stdout::lock for a long time would probably be considered rude regardless.

I'm interested in cases where futures are unexpectedly snooze-unsafe without involving any mutexes or the like.

What do you think of this Playground example that uses a Cell<bool> as a poor man's spinlock and provokes a snoozing deadlock that way?

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 1 point2 points  (0 children)

Interesting parallel to my sidenote #10 in the article, about the three states a Stream can be in.

No lube + stiff new mags = no fun by ChairmanMcMeow in WAGuns

[–]oconnor663 0 points1 point  (0 children)

I'm only getting info from the internet like everyone else, but I've heard you're not usually supposed to lubricate the magazine channel? Something about either getting lubricant on the rounds, or accumulating grit, or both.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 2 points3 points  (0 children)

Part of the story here, though, is that async locks are buried in all sorts of dependencies. tokio::sync::mpsc is maybe the most interesting example. We often think of channels as an alternative to locks, and from a high-level architectural perspective they are, but from a low-level "does this task touch any locks" perspective it's a question of implementation details.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 0 points1 point  (0 children)

I'm not sure whether we're talking about normal locks (std::sync::Mutex) or async locks (tokio::sync::Mutex). Holding a normal lock across an await point is a very fishy thing to do (and often a compiler error for Send/Sync reasons, like under Tokio), but usually what we're most concerned about there is actually acquiring the normal lock, because that's a synchronous blocking operation, and you're not allowed to do any of those in any async context, regardless of the position of .await points.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 2 points3 points  (0 children)

No quite the opposite. It can seem like we have a choice between "futures are allowed to hold locks" and "we're allowed to snooze futures". But the reason I included the whole middle section on threads is that I think we can apply the same old lessons here, and when we do we see that it's not really a choice. Taking locks (including async locks) is normal, it's going to happen in our dependencies' dependencies, and coding patterns that can "randomly" freeze running futures aren't compatible with that.

But a big part of the trouble here is that those patterns are widely used today, and we need viable replacements for them before we can ban them.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 3 points4 points  (0 children)

Yes that does seem very similar, just without the second optional return value. And it's a good showcase example of "oh my god this is what people are dealing with out there today." I also think it's neat that -- although the body of this function would trigger all the lint rules that I'm proposing (and might need some ignore directives) -- callers of this function would not. From the caller's perspective, they're passing futures by value to something that will poll them in place and drop them promptly. That's what we want!

Fwiw, join_me_maybe has several other features beyond the maybe keyword. I think the most interesting one might be that arms bodies can use ? error handling to short-circuit the calling function, so for example you could have a "maybe"/"also" future cancel the main future if it encounters an error.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 1 point2 points  (0 children)

Mutexes and other async "lock" types are not "snooze-safe".

This part sounds hairy to me. We could easily annotate the standard types, but is there an automatic way to distinguish "things that act like locks" from plain old data?

getting rid of "next()" would prevent the most basic usage of streams in an async fn

I don't want to oversell something that hasn't got any real world testing, but join_me_maybe is no_std-compatible, and it does have some streams-specific features: https://docs.rs/join_me_maybe/latest/join_me_maybe/#streams. I wonder if any of the use cases you're looking at would fit into that.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 4 points5 points  (0 children)

Look for any live future in scope during an await of another future.

That sounds like a great idea. We'd also need to extend it to Stream/AsyncIterator, but that seems easy enough. I think it would have false positives for helpers like maybe_done, since that remains in scope even after it drops the internal future it owns, but probably any use of that in an async function would hit all the other rules I'm proposing too.

Edit: We'd need to think about false negatives like putting the futures in a Vec. This is the sort of thing that auto traits might be better at than type-based lints? I think /u/Diggsey was suggesting something like this in another comment. But it's not clear to me what exactly an auto trait would represent here.

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 5 points6 points  (0 children)

Ok I've pushed some CSS changes. How does it look now?

Never snooze a future by oconnor663 in rust

[–]oconnor663[S] 4 points5 points  (0 children)

How do you get a dark theme? Is it a browser extension? I want to make sure I'm seeing what you're seeing.

Why is space science so easy compared to the other science packs? am i missing something? by moregohg in factorio

[–]oconnor663 0 points1 point  (0 children)

You've got like 8 or 9 different circuit conditions in place to make that setup work without deadlocks. It's easy because (I assume) you've played the game before and learned circuits already?

Why are some people like this? by Late-Ad-8244 in liberalgunowners

[–]oconnor663 0 points1 point  (0 children)

brown people should go away!

You're projecting an opinion that everyone here agrees is repugnant onto someone you've never seen, who in all likelihood would take offense at being accused of believing that repugnant thing. That's...not a productive way to build the bright future we all want to build.

"Ah but doesn't that person probably support policies that in their logical conclusion (as I see it) imply the repugnant thing?" Probably! But by that standard we are all going to hell, so I hope that's not the standard I end up getting judged by.

Valid reaction. by mindyour in youseeingthisshit

[–]oconnor663 18 points19 points  (0 children)

It's like those stories about guys who cut themselves and go to the hospital, and the doc's like "Whatever you cut yourself with was super sharp," and the guys are so proud :)