Add no-value DropGuard::new(|| ...) - #161550
Conversation
|
r? @clarfonthey rustbot has assigned @clarfonthey. Use Why was this reviewer chosen?The reviewer was selected based on:
|
| /// Not publicly nameable outside libcore and not on track for stabilization. | ||
| #[unstable(feature = "drop_guard_unit_fn", issue = "none")] | ||
| #[allow(missing_debug_implementations)] | ||
| pub enum UnitFn {} |
There was a problem hiding this comment.
Not sure how I feel about this hack.
There was a problem hiding this comment.
What about having a UnitFn<F> wrapper? Then that wrapper would have this "feed ()" logic attached to it (whilst remaining non-constructible and non-path-nameable from downstream), and the impl would become:
impl<(), F: FnOnce()> DropGuard<(), UnitFn<F>> {
/// Convenience for <code>[Self::with]\((), |()| f()\)</code>.
pub fn new(f: F) -> Self {
Self::with((), UnitFn(f))
}
}Feels more honest w.r.t. all that happens, here
| /// // print its value when dropped. | ||
| /// let s = String::from("Chashu likes tuna"); | ||
| /// let mut s = DropGuard::new(s, |s| println!("{s}")); | ||
| /// let mut s = DropGuard::with(s, |s| println!("{s}")); |
There was a problem hiding this comment.
Would it be possible to call this something other than with? Separately from this, I'm working to to propose making with a reserved keyword for an effects notation in the next edition.
That of course has not been accepted, and the lang team hasn't given any indication they'd like this to happen. But still: it feels pretty bad if the first API added to the stdlib called "with" in 11 years is one I ended up helping introduce, only to advocate we rename it a couple of months later 😅
There was a problem hiding this comment.
Although, looking at existing uses of with in the stdlib all seem to be methods on the instance, not used for constructors. The exception seems to be with_hasher, but that feels different from a bare with method?
To throw something out there: perhaps something like with_value could work here instead?
There was a problem hiding this comment.
Although, looking at existing uses of
within the stdlib all seem to be methods on the instance, not used for constructors. The exception seems to bewith_hasher, but that feels different from a barewithmethod?
There's also a large number of with_capacity (and some with_capacity_and_hasher) ctors.
(this is not to say that I'm particularly fond of plain with)
There was a problem hiding this comment.
There is also the possibility, as this is a mere convenience constructor, to have it be a From impl?
let a = DropGuard::new(state, |state| { … }));
let b = DropGuard::from(|| { … });This also hints a bit more about there being some "adjustment" happening when doing this construction/conversion.
Another option which was mentioned somewhere was DropGuard::from_fn(|| { … }).
FWIW, either way I wouldn't recommend using new() for the convenience, narrower, case.
There was a problem hiding this comment.
@danielhenrymantilla I honestly quite like DropGuard::from/DropGuard::from_fn for this case. That's a great suggestion, thank you!
…they
Use `drop_guard` in some places in {core,alloc,std}
- Tracking issue: rust-lang#144426
- Will conflict with rust-lang#161520
- rust-lang#161550 would also be cool occasionally
Didn't touch the places where manual `impl Drop`s had `#[inline]` on their `fn drop` or where the guard type had other `impl`s beside `Drop` and/or was named a lot.
No LLMs used, only pure human slop.
|
Looking at #161702 which migrates a number of existing drop guards in the Rust codebase to In #161550 (comment) @danielhenrymantilla suggests using |
At least in some places I could write let a = expr1;
let b = expr2;
let guard = DropGuard::new((), |()| {
// code that uses `a` & `b`
});instead of let guard = DropGuard::new(
(expr1, expr2),
|(a, b)| {
// code that uses `a` & `b`
},
);but the latter seemed a bit more clear about where the values are used. My personal dream scenario here would probably be explicit lambda captures and value-less let guard = DropGuard::from_fn(
[a = expr1, b = expr2] {
// code using `a` & `b`
},
);(Out of all suggested names, I like Explicit captures are a dream of mine either way because currently Rust only has what is effectively Another let guard = DropGuard::new((expr1, expr2, expr3), |(a, b, c)| { /* ... */ });
let (a, b, c) = &mut *guard;Not sure what could be done here to improve the ergonomics. |
Tracking issue: #144426
According to #144426 (comment), in some projects
DropGuard<(), ...>is the common case.