9 ms·
I think Go has a reasonable approach: time.Sleep(1 * time.Second)
by knowledge-clay 5y ago
I think Go has a reasonable approach:
time.Sleep(1 * time.Second)
- jamestimmins 5y agoI'm not sure why but I have a visceral, negative response to this. It might be the best solution, but it definitely /feels/ like the worst of all the worlds.
- sk0g 5y agoIs it? In most languages you do something like `time.Sleep(1 * 1e6)` instead at which point it could be a second, a few minutes, a day, who really knows? I'm just not seeing any major downsides of this, keep in mind `time.Second` isn't the only one of its kind, you have millisecond, minute, hour, etc etc.
- syntaxfree 5y agoOverloading the asterisk is always weird because multiplication is expected to be associative etc etc.
- ts4z 5y agotime.Second*1 gets the same value; it's not overloaded. Well, ok, so what actually happens is that time.Second is a time.Duration, and Duration*int yields Duration (and int*Duration yields Duration). But the value of time.Second is actually a Duration with value 1000000, IIRC -- it's microseconds. It's just the type that's special, and the int handling here is general over a lot of types. It really is nice in practice.
- ts4z 5y ago(As noted elsewhere it's nanoseconds.)
- xyzzy_plugh 5y agoIt's not overloaded. It's a unit. You can just type time.Sleep(time.Second) but this reads nicely time.Sleep(3 * time.Minute)
- rwcarlsen 5y agoIt's not really overloading. it is associative: 2*time.Hour+1*time.second == time.Second+time.Hour*2
- wtallis 5y agoI believe that's illustrating commutativity, not associativity.
- thaumasiotes 5y agoThe illustration is wrong, but the claim is correct; multiplication between units and scalars is just as associative as you'd expect. Multiplying one kilowatt by an hour gives you exactly the same result as multiplying 1 by a kilowatt-hour.
- Laremere 5y agoThere is no operator overloading here. The type Duration is effectively an int64: https://pkg.go.dev/time#Duration https://pkg.go.dev/time#Duration
- vitus 5y agoI'm not sure I follow. 2 * 3 * time.Second is the same whether you group 2 * (3 * time.Second) or (2 * 3) * time.Second (namely, the implicit grouping under left-associativity). You wouldn't normally write time.Sleep(time.Second * time.Second) because your units wouldn't work out. (Apparently you can write that in Golang; it's just very sketchy and results in a 30-year sleep.)
- thaumasiotes 5y agoBut from a mathematical point of view, the relationship between a unit and its coefficient is that you're multiplying them together. Why would it be weird to overload the multiplication operator to represent multiplication?
- cwojno 5y agoHaving used it extensively, it's actually quite nice.
- oatmeal_croc 5y agoBig fan of this.
- jeroenhd 5y agoRust has a similar-ish API for durations, Duration::from_milis(1000) or Duration::from_secs(1) in the type system, and the method can just take a Duration struct and transform it into whatever internal representation it wants. There is a Duration::new() constructor that's more ambiguous, but it's your choice as a dev to be ambiguous in this instance, and code review should probably catch that.
- ruuda 5y agoYeah, Rust is one of the few languages that gets it right! And before they had the `Duration` type with `thread::sleep(d: Duration)`, there was `thread::sleep_ms(ms: u32)`, which is also unambiguous.
- mfkp 5y agoOr Ruby on Rails: sleep(5.seconds) sleep(1.minute) sleep(2.hours) etc etc
- 33degrees 5y agoIn Ruby that would be sleep 3.seconds Hard to to be more concise than that
- mfkp 5y agoTechnically Ruby only accepts seconds. You're thinking of ActiveSupport from Rails.
- inopinatus 5y agoHere's a fun way to annoy a Rails developer. (Time.now + 1.month).to_i == Time.now.to_i + 1.month.to_i #=> false
- irjustin 5y agoNot sure why that's annoying? The right side doesn't really make sense. Though it does seem pretty easy for a novice to do thinking it's the same, but what does 1.month.to_i even mean!?
- lloeki 5y ago> 1.month.to_i Duration of a month in seconds? Before you balk at the idea, there exists a definition of a constant month duration for accounting stuff. I you hate dates - and yourself - try accounting, there's mind boggling stuff that makes the engineer mind recoil in absolute terror.
- inopinatus 5y agoActually taken almost verbatim from the report summarizing a real and subtle bug (distributed across multiple files) in code written by definitely-not-novices.
- neurostimulant 5y agoI'm not really familiar to RoR. Is is due to Time.now getting called twice and each returns slightly different value?
- 29athrowaway 5y agoI hope late millenials and generation Z rediscover types soon.
- LAC-Tech 5y agohuh? it's us millenials who decided that all dynamic typing was immoral and wrong. Back in the day Gen-Xers on HN and slashdot were talking about how great common lisp and ruby were.
- chrismorgan 5y agoI’m not a Go developer, but I understand that from a type and mathematical theory perspective Go’s time.Duration is extraordinarily awful, because of Go’s simplistic type system. int64 * Duration → Duration and Duration * int64 → Duration both make sense, but I gather this only works with constants. For other values, I believe Go only gives you Duration * Duration → Duration which is just wrong, wrong, wrong, requiring that one of the two “durations” actually be treated as though unitless, despite being declared as nanoseconds. In the end, it’s probably still worth it, but it’s a case of Go trying to design in a certain way for ergonomics despite lacking the type system required to do it properly. I have found this to be a very common theme in Go. Also that it’s often still worth it, for they’ve generally chosen their compromises quite well. But I personally don’t like Go very much.
- svnpenn 5y agoAll that, and yet I don't see a single example of what would be "correct", or an example language that does it better. This just comes off as poorly thought out rant. In my opinion, it is well designed. First of all, who is multiplying time.Duration against itself? I've been programming Go for a few years basically every day, and I've only ever seen the package constants used by themselves, or with untyped constant. I think it's a great syntax, better than any example in the article, as you don't have mystery numbers.
- manwe150 5y agoJust contrived examples, like gravity * t^2 to get distance to fall and such, probably
- bobbylarrybobby 5y agoWhat is correct is that duration ± duration = duration, duration * scalar = duration, timestamp ± duration = timestamp, timestamp - timestamp = duration, and anything else doesn't compile.
- Groxx 5y agoTo call it out specifically: this does not include `duration * duration = duration` Go is currently allowing that, which makes `delaySecs * time.Second` a billion times larger than it appears to intend. I've personally run across code that has this kind of flaw in it... at least several dozen times. It's the kind of thing that's only noticed when it misbehaves visibly while someone is watching it. (I read a lot of other-teams' code, which is in various states of quality and disarray)
- cytzol 5y agoLike many things with Go, its approach seems reasonable and simple at first, but allows you to accidentally write code that looks right but is very, very wrong. For example, what do you think this code will do? delaySecs := 1 * time.Second time.Sleep(delaySecs * time.Second) Now I insist on using the durationcheck lint to guard against this (https://github.com/charithe/durationcheck https://github.com/charithe/durationcheck). It found a flaw in some exponential-backoff code I had refactored but couldn’t easily fully test that looked right but was wrong, and now I don’t think Go’s approach is reasonable anymore.
- deleted 5y ago[deleted]
- aasasd 5y agoPerhaps the function shouldn't accept the unit of sec². Not least because I have no idea what a delay in that unit could signify.
- rsa25519 5y agoNote that the wonderful Go type system interprets time.Second * time.Second as 277777h46m40s with the type time.Second (not sec^2)
- frozenice 5y agotime.Second * time.Second The type of this is `time.Duration` (or int64 internally), not `time.Second` (which is a const with a value). I agree, though, that this is not quite sound, because it can be misused, as shown above with `time.Sleep(delaySecs * time.Second)`. In Kotlin you can do `1.seconds + 1.minutes` but not `1.seconds * 1.minutes` (compilation error), which I quite like. Here is a playground link: https://pl.kotl.in/YZLu97AY8 https://pl.kotl.in/YZLu97AY8
- ironmagma 5y agoIt doesn't actually use units. Everything is in nanoseconds, so time.Second is just another unitless number. const ( Nanosecond Duration = 1 Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute )
- devmunchies 5y agoThat’s similar to Crystal. All numbers have built in methods to convert them to a Time::Span object. So I could have a function that takes a Time::Span instead of an Int, like: def sleep(num : Time::Span) # do something here end I would call it like: sleep 300.seconds
- qurm 5y agoOr Dart Future.delayed(const Duration(seconds: 2) Future.delayed(const Duration(milliseconds: 2000)
- Gwypaas 5y agoGo's time package is famously horrible. First they didn't expose any monotonic clocks only wall time. Then after some public outages, like time travelling backwards for Cloudflare they were forced to act. In the end they managed to fold monotonic clocks into into the original type to cling on to the "Go just works" mantra, but adding even more edge cases. https://pkg.go.dev/time#hdr-Monotonic_Clocks https://pkg.go.dev/time#hdr-Monotonic_Clocks > RRDNS is written in Go and uses Go’s time.Now() function to get the time. Unfortunately, this function does not guarantee monotonicity. Go currently doesn’t offer a monotonic time source (see issue 12914 for discussion). https://blog.cloudflare.com/how-and-why-the-leap-second-affected-cloudflare-dns/ https://blog.cloudflare.com/how-and-why-the-leap-second-affe... > time: use monotonic clock to measure elapsed time https://github.com/golang/go/issues/12914 https://github.com/golang/go/issues/12914