Introduce a sleep!() macro

Hi! Is it worth putting together an RFC to introduce a simple sleep!() macro? This could be useful during debugging where I currently need to look up the documentation for std::thread::sleep and std::time::Duration . I'd be interested in implementing it too.

  1. How would if be used?
  2. I don't see the value in syntactic sugar for sleep, why is this important?

How would if be used?

Something along the lines of this:

sleep!(0.1);
std::thread::sleep(std::time::Duration::from_secs_f64(0.1));

sleep!(1);
std::thread::sleep(std::time::Duration::from_secs(1));

why is this important?

I often use want something to sleep while debugging things, having a simple, easy to remember syntax would be nice. Maybe it's not important enough for std, but I like the idea of it so I thought I'd ask the community :slight_smile:

Well, we can't disambiuate based on types in macros, so it can't work. But I don't think that this should go in std. Seems too niche.

4 Likes

I think a simple sleep crate could definitely be nice, but I think it's a bit too niche / sugary for std.

Still, have you thought of just making this a freestanding function? Something like:

fn sleep_secs<T: SleepDuration>(time: T) { std::thread::sleep(time.into_duration()) }
trait SleepDuration {
    fn into_duration(self) -> std::time::Duration;
}
// impl SleepDuration for f64, f64, u32, etc.
2 Likes

It's a pretty bad idea to have functions which take an untyped time parameter; this is a common source of bugs, since the "standard unit" (is it seconds, millis, or micros?) is very context dependent (on Unix, it might be seconds, but in my normal embedded context, it's micros). If you want such a thing, you should publish a crate (though I will underline that it is a foot-gunny API).

Abseil is a good example of a library with similar feelings about time (though std does not provide a way to deal with civil time.) https://abseil.io/docs/cpp/guides/time

1 Like

We can - we duck type the macro like how write! works.

There was a PR to undeprecate sleep_ms and add it to the prelude for the same reason as this thread, it was rejected though.

2 Likes

I don't think we should have this in std. It might make sense in a library crate, if used often enough.

I'm curious, though: what makes sleep particularly common when debugging, and could we introduce a mechanism that helps with that instead?

8 Likes

There are many different ways to sleep (e.g. syscall, awaiting a future, busy spinning). Syscall sleep is often undesired in async contexts, and async is growing more popular, so adding another way to do a sync sleep doesn't seem very valuable.

I'm curious, though: what makes sleep particularly common when debugging, and could we introduce a mechanism that helps with that instead?

I occasionally use very long sleeps (100+ seconds) as a way to inspect the current state of the program without having to break out gdb.

I don't think that's a good idea.

In async functions blocking the thread is problematic. When you import std::thread::sleep you at least see it's thread-related, and not an async-friendly sleep. If there was a built-in macro, I wouldn't blame anyone for expecting async-safe magic from it.

A built-in macro in the prelude can be seen as a strong endorsement, but sleeping is in many cases a bad idea. It's abused as a fudge for covering up race conditions. It can take down servers that need to process transactions quickly.

And it's so easy to make yourself that macro if you really want it.

7 Likes

Tangentially related:

Just a thought on syntax if you were going to make the macro, though I agree that it probably shouldn't be std, you could disambiguate the time unit by requiring a unit after the number, such as:

sleep!(10s);
sleep!(3min);
// ... ect.
2 Likes

I think you've all convinced me this doesn't belong in std. I think the most compelling reason for me is that there are different ways to sleep in different contexts, this isn't something I've thought about much coming from dynamic languages like Ruby.

Thanks for the input everyone :slight_smile:

Just for completeness this is the code I'd been playing with locally. I don't think it's worth making into a crate because you may as well just look up the docs for sleep (or remember them!).

trait Sleep {
    fn sleep(self);
}

impl Sleep for f64 {
    fn sleep(self) {
        std::thread::sleep(std::time::Duration::from_secs_f64(self));
    }
}

impl Sleep for u64 {
    fn sleep(self) {
        std::thread::sleep(std::time::Duration::from_secs(self));
    }
}

macro_rules! sleep {
    ($seconds:expr) => {
        Sleep::sleep($seconds)
    };
}

fn main() {
    sleep!(1);
    sleep!(0.2);
}
2 Likes

Isn't it will be better to add support for SI units to constants? E.g. 100 as ms, 1.5 as s, 20 as m, 100 as € etc. It will improve usability of Rust for real world calculations.

See previous discussions on "units of measure" for that kind of discussion. Current TLDR IIRC: see how far just a crate with const generics can push it. Newtypes are already powerful.

1 Like

Extension traits can do something pretty similar to that. Using the time crate, it's possible to do thread::sleep(5.seconds()) assuming you had the appropriate trait in scope.

I don't really see any way this could be cleaner, but I'm also the one that created it.

1 Like

SI, and other measurement systems, defines units, e.g. s - seconds of time, m - meters of length, g - grams of weight, b - bits, B - bytes, B - bel, and common prefixes, e.g. M for mega - 1000, m for milli - 1/1000, k for 1000, Ki for 1024, etc.

It's fairly easy to implement units of time, but not prefixes. It's why such functions as sleep_ms() are exists instead of single sleep() for all prefixes.

IMHO, ideal solution will be a syntax sugar, e.g. 1_s, or 1000_ms, 1_m, 1000_mm.

Non-ideal solution will be to implement prefixes and units using type system, e.g. 1 as s (s - type), 1000*m as s (1000 ms), 1 as m, but it will not work for 1000*m as m (conflict between milli and meter).

See https://github.com/Boddlnagg/units for example. See http://people.csail.mit.edu/jaffer/MIXF/ for units and prefixes.

1 Like

Anything other than time units is not in the scope of this post, however. I was just showing that it's possible to do something reasonably readable today. Feel free to create an RFC if you think there's something workable that hasn't been dismissed before!