[HN Gopher] Please put units in names
       ___________________________________________________________________
        
       Please put units in names
        
       Author : todsacerdoti
       Score  : 1175 points
       Date   : 2022-03-21 01:51 UTC (21 hours ago)
        
 (HTM) web link (ruudvanasseldonk.com)
 (TXT) w3m dump (ruudvanasseldonk.com)
        
       | valbaca wrote:
       | > Option 2: use strong types
       | 
       | This should've been Option One
        
       | xyzzy_plugh wrote:
       | Or join the ranks of your peers who have seen the light and use
       | types.
       | 
       | Documentation should always be secondary to an obvious,
       | descriptive interface. We've evolved beyond register positions
       | and phonebook-style paper documentation. Use the tools available
       | to you.
        
         | justinhj wrote:
         | That would be the second paragraph in the article
        
         | fouc wrote:
         | the article mentions strong types
        
         | verandaguy wrote:
         | The article addresses this somewhat using Python's type hints.
         | If I give you his signature, can you intuitively tell me what
         | unit is being taken in by the function?                   void
         | addPadding(int height) {              }
         | 
         | Types are useful, and even as a Python programmer I gravitate
         | towards type hints for all new code, but any application where
         | a programmatic type maps to a real-world type with common
         | conversions (like, say, pixels, em, en, millimetres,
         | centimetres, or inches in the above example) tends to be a
         | victim of the same issue, where the type system isn't
         | expressive enough to clearly describe the real-world type being
         | assumed by the function.
        
           | matsemann wrote:
           | That's because your not using the type system at all in your
           | example. Change it to "addSomething(Length height)", and have
           | constructors for Length.ofCm(2), Length.ofMeters(5) etc.
        
             | verandaguy wrote:
             | Sure, but this isn't a solution that's unique to
             | statically-typed languages, and the syntax can get more
             | awkward if you use a language without good OO support.
             | 
             | I also haven't come across a thorough implementation of
             | unit conversions to do stuff like this (not that it's not a
             | pattern that works -- I personally like this); it might be
             | common in domains where dealing with real units is central
             | to the business, but in industries where that's done
             | incidentally, convenience classes like this just aren't
             | around (in my experience).
        
       | [deleted]
        
       | dmurray wrote:
       | Next step, please don't call your variables ..._percent but
       | interpret 0.5 as meaning 50% of the reference value.
        
         | ______-_-______ wrote:
         | I 100% agree.
         | 
         | That said, "percent" is a common and precise word, and I
         | haven't come up with anything quite as good for variables in
         | range [0,1]. I generally use "ratio," but I don't love the
         | word. Is there anything better?
        
           | munch117 wrote:
           | I use "andel", but if you don't write your variable names in
           | Danish, then it might look a little strange. "Share" would be
           | the direct translation, but that word usually means something
           | else in programming. In English, I use "ratio" also; in
           | context the meaning is always clear enough.
        
             | ______-_-______ wrote:
             | That's actually not a terrible idea! German is known for
             | having words for concepts other languages lack, and I guess
             | that applies to Danish by extension. Maybe I should ditch
             | the thesaurus and teach myself German.
        
           | FreeFull wrote:
           | Maybe "fraction" would be suitable.
        
           | WorldMaker wrote:
           | From one perspective it is the "normalized" unit, so _not_
           | giving it a name makes as much sense as trying to find a word
           | for it: if you were going to call something ProgressPercent
           | the normalized float /double form is just Progress. This is
           | probably the closest to what I try to stick too, but it can
           | be hard especially if you have six other things that also
           | want to be called "Progress" that aren't normalized
           | floats/doubles.
           | 
           | (Another name for the "normalized" unit is sometimes the
           | "unit" unit. ProgressUnit sounds dumb, but is an available
           | option in English and shorter than ProgressNormalized.)
        
         | BurningFrog wrote:
         | Bad naming is a universe of programming flaws, much of which
         | boils down to not thinking about how a different person might
         | read your code the first time.
         | 
         | Unfortunately "Theory of Mind" is weak in people on the
         | spectrum.
        
         | Mazzen wrote:
         | How do you mean?
        
           | stilley2 wrote:
           | Not GP, but 0.5% == 0.005, not 0.5.
        
           | dmurray wrote:
           | Suppose our application deals with classifying cheese, and
           | has a field for how much fat a given sample has, maybe it
           | needs 20% to be classified as Grade A Ste-Madeleine-de-la-
           | Foo. Some developers like to call this field
           | MinimumFatContentPercent and set it to 0.2.
        
       | wyldfire wrote:
       | I would go one step further and suggest that all physical
       | quantities should either have the units in the identifier name or
       | encoded in the type system. Meters, seconds, milliamps, bytes,
       | blocks, sectors, pages, rpm, kPa, etc. Also it's often useful to
       | explicitly distinguish between different unit qualifications or
       | references. Seconds (duration) versus seconds-since-epoch, for
       | example. Bytes versus page-aligned bytes, for another.
       | 
       | Having everything work this way makes it so much easier to review
       | code for errors. Without this means that as a reviewer you must
       | either trust that the units and conversions are correct or you
       | should do some spelunking to make sure that the inputs and
       | outputs are all in the right units.
        
         | albrewer wrote:
         | Have you come across a system or language that handles units
         | and their combinations / conversions well? I have a project I
         | want to undertake but I feel like every time I start to deal
         | with units in the way I feel is "proper" I end up starting to
         | write a unit of measure library and give up.
        
         | wpietri wrote:
         | And let's not forget money. Martin Fowler has been (correctly)
         | banging this drum for years:
         | https://martinfowler.com/eaaCatalog/money.html
        
         | dgb23 wrote:
         | You don't need a type system to do this. Generic
         | operators/functions and composite structures are sufficient and
         | more flexible. Some languages let you encode this in type
         | systems as well, but that's an orthogonal feature.
        
         | DiogenesKynikos wrote:
         | The Python package astropy extends numpy arrays to include
         | units.[0]
         | 
         | It can convert between equivalent units (e.g., centimeters and
         | kilometers), and will complain if you try to add quantities
         | that aren't commensurate (e.g., grams and seconds).
         | 
         | The nice thing about this is that you can write functions that
         | expect unit-ful quantities, and all the conversions will be
         | done automatically for you. And if someone passes an incorrect
         | unit, the system will automatically spit out an error.
         | 
         | 0. https://docs.astropy.org/en/stable/units/index.html
        
         | teddyh wrote:
         | There are usually libraries for doing this. For Python, there
         | are several, for instance "Pint".
        
           | BlueTemplar wrote:
           | I was excited when I found Pint, but then was disappointed :
           | too much extra overhead for the project I was then working
           | on.
           | 
           | (I settled on units in variable names instead, was essential
           | when some inputs were literally in different units of the
           | same physical dimension.)
           | 
           | EDIT : more on this, and on astropy (which I was not aware of
           | and/or didn't exist back then) :
           | 
           | https://github.com/astropy/astropy/issues/7438
        
         | bnegreve wrote:
         | > physical quantities should [...] be encoded in the type
         | system.
         | 
         | But types are not just useful to specify the content of a
         | variable, they are also useful to specify the required
         | precision.
         | 
         | So, if there is a type for seconds in the type system, should
         | it be a 32 bits int or a 64 bits float? Only the user can say.
        
           | valleyer wrote:
           | A generic type would be useful then:
           | 
           | type DurationSeconds<Value> where Value: Numeric { ... }
           | 
           | DurationSeconds<UInt32>
           | 
           | DurationSeconds<Float64>
        
             | account42 wrote:
             | This is exactly what C++ 11 did with std::chrono [0] except
             | it goes one step further and makes the period generic too.
             | 
             | [0] https://en.cppreference.com/w/cpp/chrono/duration
        
         | jeffparsons wrote:
         | 100%. This is a baseline requirement where I work. If you don't
         | either include the units in the identifier name, or use the
         | type system where possible, your code is not getting merged.
         | 
         | The only people I've ever met that think this is unnecessary
         | are also the same people that ship a lot of bugs for other
         | people to fix.
        
           | Aeolun wrote:
           | What does a type for 'seconds' do that an 'integer' doesn't?
           | 
           | I may be misunderstanding this.
        
             | lrem wrote:
             | You can construct a linter that will prevent you from
             | trying to add seconds to dollars.
        
               | CamperBob2 wrote:
               | Isn't there an implicit conversion?
        
               | akdor1154 wrote:
               | A better example would be seconds to minutes. I think i
               | recall a jwt related cve related to timestamps being
               | misinterpreted between sec/ms for example.
        
               | taneq wrote:
               | Adding seconds to minutes can actually make sense. A
               | minute plus 30 seconds is 90 seconds, or 1.5 minutes.
               | Whether your type system allows this, though, is up to
               | the project.
               | 
               | You can't add seconds to kilometers, or to temperature,
               | or to how blue something is.
        
               | OtomotO wrote:
               | Ideally you have a compiler that simply refuses to
               | compile ambiguous code
        
               | eurasiantiger wrote:
               | Ideally, there is no compiler.
        
               | _flux wrote:
               | Ideally, you would detect all errors before runtime.
               | Usually the compiler is the last gate to make that
               | happen.
        
               | eurasiantiger wrote:
               | _Ideally,_ hardware execution would happen on a language
               | that can be proven correct and does not allow the
               | programmer to make syntactic or semantic errors.
               | 
               | The world is far, far from ideal.
        
             | davisoneee wrote:
             | if you type check, then it ensures that only a 'second' can
             | be passed to the function. This requires you to either
             | create a second, or explicitly cast to one, making it clear
             | what unit a function requires.
             | 
             | As per the article, if you dont have proper names and just
             | an 'int', that int can represent any scale of
             | time...seconds, days, whatever.
             | 
             | In python youd need something like mypy, but in rust you
             | could have the compiler ensure you are passing the right
             | types.
        
               | huynhhacnguyen wrote:
               | Having a type system to figure this out for us would be
               | great, but there are languages where this may not be
               | possible. As far as I know, Typescript is one such
               | example, isn't it?
        
               | kaoD wrote:
               | Depends. Yes, newtyping is pretty awful in TS due to its
               | structural typing (instead of nominal like Rust for
               | example).
               | 
               | You could perhaps newtype using a class (so you can
               | instanceof) or tag via { unit: 'seconds', value: 30 } but
               | that feels awful and seems to be against the ecosystem
               | established practices.
               | 
               | This is indeed one of my gripes with TS typing. I'm
               | spoiled by other languages, but I understand the design
               | choice.
        
               | smichel17 wrote:
               | The pattern you want here is _branding_.
        
               | hurflmurfl wrote:
               | I was recently dealing with some React components at
               | work, where the components would accept as an input the
               | width or the height of the element.
               | 
               | Originally, the type signature was                   type
               | Props = {height: number}
               | 
               | This naturally raises the question - number of what? Does
               | "50" mean `50px`, `50vw`, `50em`, `50rem`, `50%`?
               | 
               | I've ended up changing the component to only accept
               | pixels and changed the argument to be a string like this:
               | type Props = {height: `${number}px`}
               | 
               | Of course, if passing a "0" makes sense, you could also
               | allow that. If you want to also accept, say, `50em`, you
               | could use a union-type for that.
               | 
               | I think this could actually work for other units as well.
               | Instead of having `delay(200)`, you could instead have
               | `delay("200ms")`, and have the "ms" validated by type
               | system.
               | 
               | Maybe the future will see this getting more popular:
               | type WeightUnit = 'g' | 'grams' | 'kg' | ...;
               | type WeightString = `${number}${WeightUnit}`;
               | function registerPackage(weight: WeightString): void;
        
               | Izkata wrote:
               | > This naturally raises the question - number of what?
               | Does "50" mean `50px`, `50vw`, `50em`, `50rem`, `50%`?
               | 
               | Because it's React, the expectation is "px", using a
               | string with a suffix to override it:
               | https://reactjs.org/docs/dom-elements.html#style
        
               | spion wrote:
               | I tried to solve this problem in a way that's reasonably
               | pleasant here https://github.com/spion/branded-types
        
               | dbrgn wrote:
               | You can do something like this:                   export
               | interface OpaqueTag<UID> {             readonly __TAG__:
               | UID;         }         export type WeakOpaque<T, UID> = T
               | & OpaqueTag<UID>;
               | 
               | And then use it like this to create a newtype:
               | export type PublicKey = WeakOpaque<Uint8Array, {readonly
               | PublicKey: unique symbol}>;
               | 
               | To create this newtype, you need to use unsafe casting
               | (`as PublicKey`), but you can use a PublicKey directly in
               | APIs where a Uint8Array is needed (thus "weak opaque").
        
               | mirekrusin wrote:
               | You can simulate type opaqueness/nominal typing with
               | unique tag/branded types in ts. We're using it on high
               | stake trading platform and it works very well.
        
             | kitd wrote:
             | A function might take multiple integer arguments, each in
             | different units. Separate types for each unit guarantees
             | you won't pass the wrong integer into the wrong argument.
             | 
             | Eg                 func transferRegularly(dollars(10000),
             | days(30))
             | 
             | Meaning clear.                 func
             | transferRegularly(10000, 30)
             | 
             | Meaning obscure, error prone and potentially costly
        
               | necovek wrote:
               | With some languages like Python, you can use keyword
               | arguments too (even out of order).
               | 
               | Eg. you could simply do
               | transferRegularly(amount=10000, period_in_days=30)
               | 
               | I am always amazed how new languages never pick up this
               | most amazing feature of Python.
               | 
               | Though obviously, this code smells anyway because 1.
               | repetitive transfers are usually in calendar units (eg.
               | monthly, weekly, yearly -- not all of which can be
               | represented with an exact number of days), so in Python
               | you'd probably pass in a timedelta and thus a distinct
               | type anyway, and 2. amounts are usually done in decimal
               | notation to keep adequate precision and currency rounding
               | rules (or simply `amount_in_cents`).
               | 
               | Still, I am in favour of higher order types (eg.
               | "timedelta" from Python), and use of them should be
               | equally obligatory for unit-based stuff (eg. volume, so
               | following the traditional rule of doing conversions only
               | at the edges -- when reading input, and ultimately
               | printing it out).
        
               | steelframe wrote:
               | > transferRegularly(amount=10000, period_in_days=30)
               | 
               | dollars(10000) is still better than this example,
               | because: 10000 what? Pennies? USD? EUR?
        
               | necovek wrote:
               | Someone else caught me out on that too by suggesting
               | making it `amount_in_dollars` elsewhere in the thread ;)
               | 
               | Now you can say how there are also AUD, CAD...
               | 
               | The point was simply that if units are needed due to lack
               | of specific type being used, it's nicer to have that in
               | the API when language allows it.
        
               | dotancohen wrote:
               | PHP got this property in PHP 8.
               | 
               | One problem with this approach is refactoring. If you
               | wanted to refactor your example with the parameter
               | "amount_in_dollars" then you would either have to
               | continue maintaining the legacy "amount" argument, or
               | break existing code.
        
               | necovek wrote:
               | So you mean just like with, eg. renaming a function? I
               | agree it's an issue compared to not doing it, but a very,
               | very minor one IMHO, and legibility improvements far
               | outweight it.
        
               | dotancohen wrote:
               | Renaming a function comes with the explicit implication
               | that the API has changed. But it might not be clear to
               | someone maintaining a Python application that changing a
               | parameter name might change an argument - that is not the
               | case in any other language (until PHP 8).
               | 
               | Guess how I discovered this issue :)
        
               | necovek wrote:
               | Well, if the approach was more pervasive, you'd be used
               | to it just like seasoned Python developers are. :)
        
               | kitd wrote:
               | I see keyword arguments as slightly different though. The
               | keyword is like the parameter name. The value is still a
               | plain integer and (theoretically) susceptible to being
               | given the wrong integer. In contrast, unit types allow
               | for hard checking by the compiler.
               | 
               | In practice, with good naming it won't make much
               | difference and only shows up when comparing the docs (or
               | intellisense) for an API with how it is actually used.
        
               | [deleted]
        
             | GuB-42 wrote:
             | The type is "duration", not "seconds". "seconds" is the
             | unit. You can think of the unit as an operator that
             | converts an integer to a duration.
             | 
             | The advantages are:
             | 
             | - An integer doesn't tell you if you are talking about
             | seconds, milliseconds or anything like that. What does
             | sleep(500) means? Sleep 500s or 500ms? sleep(500_ms) is
             | explicit
             | 
             | - It provides an abstraction. The internal representation
             | may be a 64-bit number of nanoseconds, or a 32-bit number
             | of milliseconds, the code will be the same.
             | 
             | - Conversions can be done for you, no more "*24*60*60"
             | littered around your code if you want to convert from
             | seconds to days, do fun(1_day) instead.
             | 
             | - Safety, prevents adding seconds to meters for instance.
             | Ideally, it should also handle dividing a distance by a
             | duration and give you a speed and things like that.
             | 
             | Under the hood, it is all integers of course (or floats),
             | which is all machine code, but handling units is one of the
             | things a high level language can do to make life easier on
             | the human writing the code.
        
             | Cthulhu_ wrote:
             | What does the integer represent? Nano, milli, microseconds,
             | seconds, minutes, hours, days?
        
             | indymike wrote:
             | Tells you what the integer represents, so you aren't off by
             | several orders of magnitude.
        
             | jsnell wrote:
             | Most answers here are answering your question literally,
             | and explaining why you'd add a type for "seconds". But in
             | reality you shouldn't create a type for seconds, the whole
             | premise of the question is wrong.
             | 
             | Instead of a type for seconds, you'd want a type for all
             | kinds of duration regardless of the time unit, and with
             | easy conversion to integers of a specific time unit. So
             | your foo() function would be taking a Duration as an input
             | rather than seconds, and work correctly no matter what unit
             | you created that duration from:
             | foo(Duration.seconds(3600))         foo(Duration.hours(1))
             | foo(Duration.hours(1) + Duration.seconds(5))
        
             | atoav wrote:
             | Well your function could then accept multiple types
             | (Miliseconds, Seconds, Minutes, Hours) and do the
             | conversion between those implicitly.
             | 
             | The units are also extremely clear when they are carried by
             | the type instead of the variable name, where a developer
             | could e.g. change some functionality and end up with a
             | variable called `timeout_in_ms` while the function that
             | eats this variable might expect seconds for some reason.
             | 
             | If it is typed out you can just check if the function
             | performs the right action when passed a value of each time
             | unit type and then you only ever have to worry about
             | mistakingly declaring the wrong type somewhere.
             | 
             | But wether you should really do all that typing depends on
             | how central units are for what you are doing. If you have
             | one delay somewhere, who cares if it is typed or not. If
             | you are building a CNC system where a unit conversion error
             | could result in death and destruction, maybe it would be
             | worth thinking about.
        
           | nightfly wrote:
           | What type of industry/product do you work in/on? And what
           | sort of languages do you work in?
        
             | DocTomoe wrote:
             | Not OP, but I see that a lot in the aerospace and heavy
             | industry sectors.
             | 
             | We keep laughing about "if we engineered bridges as we
             | engineer software" ... the truth is that the areas where
             | correct software matters tend to write very robust code,
             | and the rest of the industry would be well advised to take
             | notice and copy what they see.
             | 
             | Of course, writing robust code is a skill, and it takes
             | extra time.
        
               | dotancohen wrote:
               | I'm certain that the Mars Climate Orbiter had a lot to do
               | with this practice.
        
               | mhaberl wrote:
               | > and the rest of the industry would be well advised to
               | take notice and copy what they see
               | 
               | I don't agree.
               | 
               | There is a good reason that aerospace industry writes
               | robust code - in invests time (money) to avoid disasters
               | that could cause, among other things, loss of human life.
               | 
               | On the other hand if for example some webform validation
               | fails because the code was written as fast (as cheap) as
               | possible, who cares really.
               | 
               | That is just a tradeoff, in aerospace industry you spend
               | more to lower the risk, somewhere else you don't.
        
               | thfuran wrote:
               | >On the other hand if for example some webform validation
               | fails because the code was written as fast (as cheap) as
               | possible, who cares really.
               | 
               | Who knows. Maybe a billion dollar company that can't
               | fulfill orders. Maybe a million people who suddenly can't
               | use their bank online.
        
               | a9h74j wrote:
               | Yes, as a comparison, let's just take all the units (em,
               | px, %) out of writing CSS and see how fun that becomes to
               | review and troubleshoot.
        
               | mhaberl wrote:
               | Yes, sure, but a "billion dollar company" in this case
               | does not represent the whole industry.
               | 
               | You can probabbly find a some specific non-critical case
               | in aerospace industry, but surely based on that example
               | one would not suggest that the whole aerospace industry
               | should just copy what they see in frontend dev.
               | 
               | Context matters, there are exceptions, but the standard
               | practices are based on average scenario, not on extremes.
        
               | regularfry wrote:
               | It takes time to learn, and to learn the value, and time
               | to agree with the team that it's sensible. With this sort
               | of thing - proper naming of variables - I disagree that
               | it takes longer at point of use.
        
             | physicsguy wrote:
             | Not the commenter, but I work in scientific software
             | development and it's just a minefield of different units,
             | so being explicit is generally very useful. Even if you can
             | assume you can stick to metric (you can't), what different
             | users want varies across countries. For e.g. here in the UK
             | we often want to represent data as millilitres, but in
             | France the same measurements are often centilitres.
             | 
             | I don't use libraries to enforce it though, we did try this
             | but found it quite clunky:
             | https://pint.readthedocs.io/en/stable/
        
               | LeifCarrotson wrote:
               | It varies across different users from the same city! The
               | same family, even!
               | 
               | One piece of equipment I just finished working on
               | measured and displayed vacuum at different sensors in
               | PSIg, kPa, Pa, mmHg, and inHg. The same machine, the same
               | measurement at different stages in the process, five
               | different units!
        
             | wffurr wrote:
             | Also not OP, but I work on graphics software and we
             | frequently deal with different units and use strict naming
             | systems and occasionally types to differentiate them.
             | 
             | Even more fun is that sometimes units alone aren't
             | sufficient. We need to know which coordinate system the
             | units are being used in: screen, world, document, object-
             | local, etc. It's amazing how many different coordinate
             | systems you can come up with...
             | 
             | Or which time stream a timestamp comes from, input times,
             | draw times (both of which are usually uptime values from
             | CLOCK_MONOTONIC) or wall times.
        
               | ReleaseCandidat wrote:
               | As a bonus, coordinate systems can be left-handed or
               | right-handed, and the axes point in different directions
               | (relevant when loading models for example).
        
           | michaelt wrote:
           | _> The only people I 've ever met that think this is
           | unnecessary are also the same people that ship a lot of bugs
           | for other people to fix._
           | 
           | I find feelings about this depend a lot on how much ceremony
           | the type system involves; and just how many units and
           | references to them there are in the system.
           | 
           | Asking bash coders to write "sleep 5s" instead of "sleep 5" -
           | I doubt you'd get any objections at all.
           | 
           | But if you're putting a foo.bar.Duration on a
           | getDefaultTimeoutFromEnvironment on a setConnectTimeout on a
           | HttpRequest on a HttpRequestInitializer on a NetHttpTransport
           | on a ProviderCredential to make a simple get request? People
           | who've come from less ceremony-heavy languages might feel
           | less productive, despite producing 10x the lines of code.
        
             | rowanajmarshall wrote:
             | > I find feelings about this depend a lot on how much
             | ceremony the type system involves; and just how many units
             | and references to them there are in the system.
             | 
             | Ideally it'd be as simple as:
             | 
             | typealias Dollars = BigDecimal
             | 
             | typealias Cents = Long
             | 
             | that's valid Kotlin, but the equivalent is doable in most
             | languages nowadays (Java being a big exception).
        
               | stefs wrote:
               | don't do this!                   typealias Cents = Long
               | typealias Meters = Long                  Cents(3) +
               | Meters(4) = 7L
               | 
               | that's exactly the thing we want to prevent.
               | 
               | the classes shouldn't be for units at all, the type
               | should represent the type of unit.
               | 
               | so instead of a class Seconds you should have a class
               | Duration, instead of class Meters you should have a type
               | Distance. that's because the unit of the different types
               | can be converted between each other.
               | 
               | Dollars and Cents are a bit of a bad example because
               | currencies can't be easily converted between each other,
               | as conversion is dependent on many factors that change
               | over time. meters, yards, feet, lightyears, miles, chain,
               | furlongs, whatever describe a multiple of the same thing
               | though, so a different type for each unit isn't
               | necessary, as the input that was used to create the
               | instance isn' usually needed. the counter example would
               | be datetime with timezones - a datetime with a timezone
               | convers a lot more information than the datetime
               | converted to UTC.
        
               | dragonwriter wrote:
               | > typealias Dollars = BigDecimal
               | 
               | > typealias Cents = Long
               | 
               | If I ever have to deal with monetary values in a program
               | where someone thought this was a good idea, ... well, it
               | really won't be the worst thing I've ever dealt with,
               | but, still.
               | 
               | (If you have dollars and cents as types in the same
               | program, they darn well better work properly together,
               | which is unlikely to work if they are both just aliases
               | for basic numeric types.)
        
               | dtech wrote:
               | I recommend against that, and use proper (wrapper) types.
               | 
               | I don't know Kotlin, but in most languages if you alias 2
               | types to the same base type, for example Seconds and
               | Minutes to Long, the compiler will happily allow you to
               | mix all 3 of them, defeating the protection full types
               | would bring.
        
               | stefs wrote:
               | that's correct. typealiases are the wrong solution here.
               | the better solution would be value classes, but of
               | course, the unit shouldn't be the type.
        
             | [deleted]
        
             | contravariant wrote:
             | Well ignoring the silly stuff this would just boil down to
             | something like:                   request =
             | NetHttpTransport.Request()         request.setConnectTimeou
             | t(getDefaultTimeoutFromEnvironment().seconds)
             | 
             | which is verbose, but at least it's fairly clear.
             | 
             | And yes I'm calling a class named HttpRequestInitializer
             | silly, I don't care if some language decided it should
             | exist.
        
               | sethammons wrote:
               | This is where I divert. You just hard coded seconds into
               | your test. Now your tests that cover this must take
               | seconds to finish; thankfully you were not testing hours
               | or days!
               | 
               | My last shop was a Go shop and one test I think shows
               | this off was an SMTP server and we needed to test the
               | timeouts at different states. The test spun up half a
               | dozen instances of the server, got each into the right
               | smtp state and verified timeouts in under 10ms.
               | 
               | The environment that set the timeout would either be
               | "timeout_ms=500" or "timeout=500ms" (or whatever). This
               | is where you handle that :)
        
               | catlifeonmars wrote:
               | This is actually revealing a different problem: the
               | system clock as an implicit dependency. YMMV depending on
               | support of underlying libraries, but I will typically
               | make the clock an explicit dependency of a
               | struct/function. In Go, usually it's a struct field `now
               | func() time.Time` with a default value of `time.Now`.
        
               | dnadler wrote:
               | The test could simply mock the default value to something
               | reasonable like '.1 seconds' and test that duration
               | instead, so I don't think this is a real problem.
        
               | hansvm wrote:
               | If you're testing things with timeouts it's often a good
               | practice to mock out the system clock anyway. That allows
               | testing your timeouts to be nearly instantaneous and also
               | catches edge cases like the clock not moving forward,
               | having a low resolution, moving backward, ...
               | deterministically.
        
               | dahfizz wrote:
               | Many timeout functions take seconds as a floating point.
               | So you could time out on 0.05 seconds (5 milis). But now
               | the code is clear and less prone to bugs.
        
               | sethammons wrote:
               | In Go, you don't pass a float, you pass a duration
        
               | catlifeonmars wrote:
               | Which is unitless, hence there is no problem.
               | `time.Duration.Seconds()` returns a floating point.
        
               | contravariant wrote:
               | Not sure I fully understood your objection, but the
               | reason I specified seconds is because I presumed the
               | setConnectTimeout to be part of the default HTTP library,
               | which likely doesn't adhere to the same conventions, and
               | that it expected seconds (which seem to be the usual for
               | http libraries as far as I can tell).
               | 
               | Of course if the setConnectTimeout method was part of the
               | same application you could just pass the timeout
               | directly, but at the boundary of your application you're
               | still going to have to specify at some point which unit
               | you want.
        
               | michaelt wrote:
               | A class named 'HttpRequestInitializer' and taking 10
               | lines to set a timeout on a HTTP request isn't merely
               | hypothetical: https://developers.google.com/api-client-
               | library/java/google... - and that's not counting any
               | import statements.
               | 
               | (although getDefaultTimeoutFromEnvironment was artistic
               | license on my part)
        
               | contravariant wrote:
               | True, but like I said that doesn't make it _not_ silly.
               | Just harder to fix.
               | 
               | Edit: Also, overriding a class method dynamically inside
               | a function? I usually program python these days and even
               | I think that's wild.
        
               | jsight wrote:
               | Its an interface with only method. I suspect that most of
               | us would just us a lambda now.
        
               | contravariant wrote:
               | I'll never quite understand why it wasn't simply a
               | function in the first place.
        
               | dtech wrote:
               | Java pre-8 only had anonymous classes, there were no
               | lambdas
        
               | fiddlerwoaroof wrote:
               | And Java lambdas are still syntax sugar for one-method
               | anonymous classes.
        
               | gregmac wrote:
               | request.setConnectTimeout(getDefaultTimeoutFromEnvironmen
               | t().seconds)
               | 
               | This is actually a very good example of what not to do,
               | with the mistake being in whoever implemented
               | setConnectTimeout()
               | 
               | I actually don't know this particular API, but I'm used
               | to timeouts being in milliseconds, so that code looks
               | wrong to me.
               | 
               | Much better API, and what the article is talking about,
               | is to change this to:                   .setConnectTimeou
               | tMilliseconds(getDefaultTimeoutFromEnvironment().seconds)
               | 
               | Now the mistake is obvious, and even if the original
               | developer doesn't notice it will stick out in a PR or
               | even a causal glance.
        
               | makapuf wrote:
               | This example is nice but if you put arguments metadata in
               | the function name, you have to have one main argument,
               | the function name can prove cumbersome if you have 3 or 4
               | arguments with units like                   .setPricePerM
               | assInCentsPerKilogramsWithTimeoutInMilliSeconds(100,2,300
               | )
        
               | elcomet wrote:
               | I think you should rather do
               | .setPrice(priceInCents=100, massInKg=2, timeoutInMs=300)
        
               | gregmac wrote:
               | I'd argue there are better API patterns for this though
               | -- keeping in mind this values code readability (and
               | correctness) over micro-optimization:
               | .setPriceInCents(100);         .setMassInKilograms(2);
               | .setTimeoutInMilliseconds(300);
               | 
               | or                   .calculate({
               | priceInCents = 100,             massInKilograms: 2,
               | timeoutInMilliseconds: 300,         });
        
               | LgWoodenBadger wrote:
               | That's one of the benefits of having it exposed as a
               | type-enforced parameter. setConnectTimeout() could take a
               | Duration, which contains the amount and the unit, and
               | therefore wouldn't care if consumer A provided a timeout
               | in seconds, and consumer B provided a timeout in
               | milliseconds.
        
               | gregmac wrote:
               | Totally agree, but then I would expect the code would be:
               | request.setConnectTimeout(getDefaultTimeoutFromEnvironmen
               | t())
               | 
               | with getDefaultTimeoutFromEnvironment() returning a
               | Duration.
               | 
               | Ideally this is consistent throughout the codebase, so
               | that anything that uses a primitive type for time is
               | explicitly labelled, and anything using a Duration can
               | just be called "Timeout" or whatever.
        
               | contravariant wrote:
               | All fair points. In this example I was suggesting what
               | this might look like at the border of the application
               | where you need to talk to some (standard) library which
               | doesn't use the same convention.
        
             | vvillena wrote:
             | The 80/20 approach of renaming "timeout" to
             | "timeoutSeconds" or "timeoutMillis" is also valid. They key
             | takeaway is to not make assumptions.
        
         | geokon wrote:
         | I'm sorry, but this whole comment section is in some collective
         | psychosis from 2010. You don't need to mangle variable names or
         | create custom types (and then the insane machinery to have them
         | all interact properly)
         | 
         | Have none of you ever refactored code..? Or all of your writing
         | C?
         | 
         | Your library should just expose an interface/protocol
         | signature. Program to interfaces. Anything that is passed in
         | should just implement the protocol. The sleep function should
         | not be aware or care about the input type AT ALL. All it
         | requires is the input to implement an "as-milliseconds()"
         | function that returns a millisecond value. You can then change
         | any internal representation as your requirements change
        
           | gpderetta wrote:
           | premature abstraction is the root of all evil.
        
           | flohofwoe wrote:
           | That's also a custom type. But for libraries, custom types
           | for everything in interface definitions are problematic.
           | Let's say you use library A which has some functions that
           | take a time delta, and another library B, that also has
           | functions which take time deltas. Now both library would
           | define their own time delta type, and you have two types for
           | time deltas in your application and most likely need to add
           | an additional 'meta time delta type' which can be converted
           | to the library specific time deltas types. This will explode
           | very quickly into lots of boilerplate code and is a good
           | reason to use 'primitive types' in interfaces.
           | 
           | If you replace 'time delta' with 'strings' then the problem
           | becomes more apparent. Each library defining its own string
           | type would be a mess.
        
             | [deleted]
        
             | geokon wrote:
             | If you are working with a crappy language then that's
             | probably true. But it doesn't have to be a lot of
             | boilerplate and it can be local in scope. In Clojure it's a
             | one-liner.                   (extend-protocol
             | libA/stringable         myLib/InputThing         as-string
             | [x] (myLib/to-string x) )              (libA/some-func
             | (myLib/make-a-thing))
             | 
             | And sure it can just be doing something as simple as
             | returning an internal value directly or calling some common
             | stringifying method. You do have a good point that you may
             | have redundant stringifying protocols across libraries -
             | which sucks.
             | 
             | > This will explode very quickly into lots of boilerplate
             | code and is a good reason to use 'primitive types' in
             | interfaces.
             | 
             | I feel you were so close and missed :) The natural
             | conclusion would be to have primitive interfaces - not
             | primitive types. This way libraries only need to agree to
             | adhere to an interface (and not an implementation)
        
           | thrwyoilarticle wrote:
           | 'Why do at build time what you could do with bugs at
           | runtime'?
        
           | qayxc wrote:
           | > Have none of you ever refactored code..? Or all of your
           | writing C?
           | 
           | You seem to ignore the much broader context here: the article
           | wasn't just about code. It included configuration files and
           | HTTP requests.
           | 
           | It's also worth noting that depending on the language in
           | question and the usage pattern of the function/method, using
           | interfaces or protocols can cause considerable overhead when
           | simply using a proper descriptive name is free.
        
           | ReleaseCandidat wrote:
           | > [...] create custom types (and then the insane machinery to
           | have them all interact properly)
           | 
           | That's an argument against languages with type-systems that
           | make this a PITA, not against the idea itself.
        
           | pif wrote:
           | > You don't need to ... create custom types > > All it
           | requires is the input to implement an "as-milliseconds()"
           | function
           | 
           | A.k.a. custom type!
        
         | Gigachad wrote:
         | I love when types are used to narrow down primitive values. A
         | users id and a post id are both numbers but it never makes
         | sense to take a user id and pass it to a function expecting a
         | post id. The code will technically function but it's not
         | something that's ever correct.
        
         | HideousKojima wrote:
         | >Having everything work this way makes it so much easier to
         | review code for errors.
         | 
         | Had one making me pull my hair put the other day in C#. C#
         | datetimed are measured in increments of 100 nanoseconds elapsed
         | since January 1st 1 AD or something like that. Was trying to
         | convert Unix time in milliseconds to a C# datetime and didn't
         | realize they were using different units. My fault for not
         | reading the docs but having it in the name would have saved me
         | a lot of trouble.
        
           | osigurdson wrote:
           | What precisely could have been changed to make you realize
           | that C# DateTime is not the same as Unix time? Perhaps Ticks
           | could be renamed to Ticks100ns but I'm not sure how to encode
           | the epoch date such that it is not necessary to read any
           | documentation. I suppose the class could have been named
           | something like DateTimeStartingAtJan1_0001 but obviously
           | would have been ridiculous.
           | 
           | Naming is an optimization problem: minimize identifier length
           | while maximizing comprehension.
        
             | justsomehnguy wrote:
             | > how to encode the epoch date such that it is not
             | necessary to read any documentation
             | 
             | And you need to read the docs to know why some systems use
             | 1970 as the reference point. Should we rename it to
             | Unix1970datetimeepoch everywhere?
        
           | kqr wrote:
           | I'm not sure I agree. When I convert fields to DateTime, I
           | remove the unit suffix from the name. The DateTime is
           | supposed to be an implementation-agnostic point in time. It
           | shouldn't come with any units, and nor should they be exposed
           | by the internal implementation.
           | 
           | The factory method used to convert e.g. Unix timestamps to
           | DateTimes, now that should indicate whether we're talking
           | seconds or milliseconds since epoch, for example, and when
           | the epoch really was.
        
             | stevesimmons wrote:
             | How does the C# DateTime type distinguish between dates and
             | a point in time whose time just happens to be midnight?
             | 
             | Much of the C# code I've seen uses names like start_date
             | with no indication of whether it really is a date (with no
             | timezone), a date (in one particular timezone), or a
             | datetime where the time is significant.
             | 
             | I'm certainly not a C# developer, though my quick reading
             | of the docs suggests that the DateOnly type was only
             | introduced recently in .NET6.
        
               | Sharparam wrote:
               | Yeah, before the new DateOnly (and TimeOnly) types, there
               | was no built-in way in C# to specify a plain date.
               | NodaTime[1] (a popular third-party library for datetime
               | operations) did have such types though.
               | 
               | [1]: https://nodatime.org/
        
             | gregmac wrote:
             | They do:                   .ToUnixTimeSeconds()
             | .ToUnixTimeMilliseconds()
             | DateTimeOffset.FromUnixTimeSeconds(Int64)
             | DateTimeOffset.FromUnixTimeMilliseconds(Int64)
             | 
             | https://docs.microsoft.com/en-
             | us/dotnet/api/system.datetimeo...
             | 
             | https://docs.microsoft.com/en-
             | us/dotnet/api/system.datetimeo...
        
           | pharmakom wrote:
           | F# has unit support in the type system :)
        
             | S04dKHzrKT wrote:
             | An example for unfamiliar folks.
             | 
             | Many Languages                 var lengthInFeet = 2;
             | var weightInKg = 2;              var sum = lengthInFeet +
             | weightInKg; // Runs without issue but is an error
             | 
             | F#                 [<Measure>] type ft       [<Measure>]
             | type kg              let lengthInFeet = 2<ft>       let
             | weightInKg = 2<kg>            let sum = lengthInFeet +
             | weightInKg // Compile time error
             | 
             | More info at https://fsharpforfunandprofit.com/posts/units-
             | of-measure/
        
           | eyelidlessness wrote:
           | What the heck is with MS and weird datetime precision? I
           | figured out some bug with a third party API was due to SQL
           | Server using 1/300th seconds. Who would even think to check
           | for that if you're not using their products?
        
             | justsomehnguy wrote:
             | Who would even think to check if the system is counting
             | from 1970/01/01 you're not using _their_ products?
        
               | eyelidlessness wrote:
               | If they're using ISO format I don't really care what
               | they're counting from. But I care if some ISO dates are
               | preserved exactly and some are rounded to another
               | value... especially when that rounding is non-obvious. It
               | took me months to even identify the pattern clearly
               | enough to find an explanation. Up to that point we just
               | had an arbitrary allowance that the value might vary by
               | some unknown amount, and looked for the closest one.
        
               | onlyrealcuzzo wrote:
               | This is an established standard.
               | 
               | It's really not any stranger than starting dates at 1 CE,
               | or array indexes starting at 0.
        
               | jodrellblank wrote:
               | https://devblogs.microsoft.com/oldnewthing/20090306-00/?p
               | =18...
               | 
               | Windows uses the Gregorian Calendar as its epoch.
        
               | justsomehnguy wrote:
               | > This is an established standard.
               | 
               | Established doesn't mean it is understandable without
               | documentation. Anyone who is not familiar with it doesn't
               | know why it starts in 1970 and counts seconds. You need
               | to actually open the documentation to know about that,
               | and it's name (be it unix time, epoch, epoch time or
               | whatever) _doesn 't_ help in understanding what it is and
               | what unit it is using.
        
               | hannasanarion wrote:
               | The metric system is also not understandable without
               | documentation, byt you don't need to explain it every
               | time because every living person should have gotten that
               | documentation drilled into them at age ten.
               | 
               | UNIX time is an easy international standard, everybody
               | with computer experience knows what it is and how to work
               | with it.
        
               | justsomehnguy wrote:
               | > everybody with computer experience knows what it is and
               | how to work with it.
               | 
               | Thanks for the laugh.
               | 
               | The only ones who needs to know about unixtime is:
               | 
               | developers when they do something which takes it/produces
               | it
               | 
               | *nix sysadmins
               | 
               | Everyone else with "computer experience" could live all
               | their life without _the need_ to know what unixtime is.
        
               | hannasanarion wrote:
               | Yeah, that's what I meant. People who program or do
               | sysadmin, ie anybody who will ever need to call a sleep
               | function, should know what a unixtime is.
        
             | spyspy wrote:
             | God speed trying to parse dates from excel. They have bugs
             | _intentionally built in_
        
             | osigurdson wrote:
             | 1/300 seconds is an odd one for sure. In the case of
             | DateTime however, I'd say it is designed to hit as many use
             | cases as possible with a 64 bit data structure. Using a
             | 1970 epoch as is (logically) used for Unix system times
             | naturally misses even basic use cases like capturing a
             | birthdate.
             | 
             | It is quite hard actually to disagree with the 100ns tick
             | size that they did use. 1 microsecond may have also been
             | reasonable as it would have provided a larger range but
             | there are not many use cases for microsecond accurate times
             | very far in the past or in the future. Similarly using 1
             | nanosecond may have increased the applicability to higher
             | precision use cases but would have reduced the range to 100
             | years. Alternately, they could have used a 128 bit
             | structure providing picosecond precision precision from big
             | bang to solar system flame out with the resultant
             | size/performance implications.
        
         | cb321 wrote:
         | You might find this interesting:
         | https://github.com/SciNim/Unchained
        
         | deepsun wrote:
         | Nitpicks:
         | 
         | Why would your type system have encoded unit for kilo-pascal,
         | but not hecto-pascal, mega-pascal, micro-pascal etc?
         | 
         | If you only encode base units (e.g. seconds), then we should
         | use exact-precision arithmetic instead of f32 or f64, which is
         | sometimes an overkill.
         | 
         | If encoding all the modulos (kilo/milli/mega etc) I feel like
         | there are some units may have name clashes (e.g. "Gy" -- is it
         | giga-years, or gray)?
         | 
         | Should we encode only SI units, or pounds/ounces/pints as well?
        
           | BlueTemplar wrote:
           | Isn't floating point specifically for dealing with large
           | orders of magnitude ?
           | 
           | (Economics of floating vs fixed point chips might distort
           | things though ?)
           | 
           | Also, in the case that you meant this : you might need
           | fractions of even base units for internal calculations :
           | 
           | IIRC banking, which doesn't accept _any_ level of
           | uncertainty, and so uses exclusively fixed precision, uses
           | tens of cents rather than cents as a base unit ?
        
           | sparkie wrote:
           | Does the type system handle equivalent units (dimensional
           | analysis)? eg, N.m = kg.m^2.s^-2.
           | 
           | Does the type system do orientational analysis? If not you to
           | assign a value of _work_ to a value of _torque_ and vice
           | versa, as they both have the above unit.
           | 
           | There are several other similar gotchas with the SI. I think
           | descriptive names are better than everyone attempting to
           | implement an incomplete/broken type system.
        
             | gpderetta wrote:
             | This is the answer from boost units:
             | 
             | https://www.boost.org/doc/libs/1_78_0/doc/html/boost_units/
             | F...
             | 
             | tl;dr is uses some sort of pseudounits to make
             | dimensionally similar but incompatible units, well,
             | incompatible.
        
             | DiogenesKynikos wrote:
             | The Python package astropy does all these things. There's a
             | graph of equivalencies between units.
             | 
             | 0. https://docs.astropy.org/en/stable/units/index.html
        
               | sparkie wrote:
               | I see dimensional analysis, but in this table[1], torque
               | and work have the same unit, and that unit is J.
               | 
               | The SI itself states[2]: "...For example, the quantity
               | torque is the cross product of a position vector and a
               | force vector. The SI unit is newton metre. Even though
               | torque has the same dimension as energy (SI unit joule),
               | the joule is never used for expressing torque."
               | 
               | [1]:https://docs.astropy.org/en/stable/units/index.html#m
               | odule-a...
               | [2]:https://www.bipm.org/documents/20126/41483022/SI-
               | Brochure-9-...
        
               | nuccy wrote:
               | Speaking of astropy units. I had a hilarious issue last
               | week, which was quite hard to identify (simplified code
               | to reproduce):                 from astropy import units
               | as u       a = 3 * u.s       b = 2 * u.s       c = 1 *
               | u.s       d = 4 * u.s       m = min([a, b, c, d])       a
               | -= m       b -= m       c -= m       d -= m
               | print(a,b,c,d)
               | 
               | Output: 2.0 s 1.0 s 0.0 s 4.0 s
               | 
               | Note the last 4.0, while min value is 1.0
               | 
               | The issue is that _a_ , _b_ , _c_ , _d_ are objects when
               | astropy units are applied and min (or max) returns not
               | the value but an object with the minimal value, thus _m_
               | is _c_ (in this particular case _c_ has the smallest
               | value) so _c -= m_ makes _m = 0_ , so _d_ remains
               | unchanged. It was very hard to spot especially when
               | values change and occasionally either one of _a_ , _b_ ,
               | _c_ or _d_ has the smallest value.
               | 
               | In-place augmentation of a working code with units may be
               | very tricky and can create unexpected bugs.
        
               | DiogenesKynikos wrote:
               | This is really an issue with Python in general
               | (specifically, mutable types).
               | 
               | You'd get the exact same behavior with numpy _ndarrays_
               | (of which astropy _Quantities_ are a subclass).
        
               | dragonwriter wrote:
               | > This is really an issue with Python in general
               | (specifically, mutable types).
               | 
               | Unit-aware values as a type where assignment as mutation
               | is an odd choice though (normal mutable types _do not_
               | exhibit this behavior, it's a whole separate behavior
               | which has to be deliberately implemented.) It may make
               | sense in the expected use case (and as you note reflects
               | the behavior of the underlying type), but more generally
               | it 's not what someone wanting unit-aware values would
               | probably expect.
        
               | necovek wrote:
               | That sounds like a bug in astropy type definitions: did
               | you get a chance to report it as one?
               | 
               | While it can sometimes be undefined behavior (a minimum
               | of incompatible units), in cases like these it should
               | DTRT.
        
           | gpderetta wrote:
           | Given a powerful enough type system, you can parameterize
           | your types by the ratio to the unit and any exponent. Then
           | you can allow only the conversions that make sense.
        
           | usrusr wrote:
           | You'll want to leave the point floating to floating point
           | numbers, but whenever you interact with legacy APIs or
           | protocols you want a type representing the scale they use
           | natively. You wouldn't want to deal with anything based on
           | TCP for example with only seconds (even if client code holds
           | them in doubles), or with only nanoseconds. But you certainly
           | won't ever miss a type for kiloseconds.
        
           | stinos wrote:
           | _(e.g. "Gy" -- is it giga-years, or gray)_
           | 
           | In my opinion this is not a real problem, since ideally no-
           | one should such meaningless abbreviations in code. Just write
           | giga_years or GigaYears or whatever your style is, problem
           | solved, doesn't get any clearer than that.
        
             | timthorn wrote:
             | In defence of Gy, it isn't meaningless in astronomy - it's
             | a very well used unit. Though I do agree that it might be
             | less common in code.
        
               | gattr wrote:
               | I myself can't remember seeing Gy in astronomical papers,
               | but I've seen Ga (gigaannum).
               | 
               | https://en.wikipedia.org/wiki/Year#SI_prefix_multipliers
        
               | timthorn wrote:
               | Ga is indeed used as well.
               | https://en.wikipedia.org/wiki/Billion_years
        
               | Aeolun wrote:
               | Isn't Gy a bit much even in astronomy? With 15 Gy you
               | have the age of the universe right?
        
               | em3rgent0rdr wrote:
               | Your comment piqued my curiosity, and I looked at https:/
               | /en.m.wikipedia.org/wiki/Future_of_an_expanding_unive...
               | and found:
               | 
               | "Stars are expected to form normally for 10^12 to 10^14
               | (1-100 trillion) years"
               | 
               | So it seems Gy and even Ty units will be a reasonable
               | scale for events during the period of star formation.
        
               | Aeolun wrote:
               | Ah, that is a good point. For some reason I was thinking
               | only backwards. I never considered that there's orders of
               | magnitude more time in front of us.
        
           | Juliate wrote:
           | Why wouldn't the type system be able to take care of that?
        
           | jltsiren wrote:
           | The standard symbol for a year is "a". Using "y" or "yr" is
           | non-standard and ambiguous, and they should be avoided in
           | situations where precision and clarity matter.
        
           | resonious wrote:
           | I don't think the parent meant to exclude hecto-pascals from
           | their hypothetical type system.
        
           | Ekaros wrote:
           | Time units are messy.
           | 
           | Once we get to Gigayears, what is the size of single year?
           | Just 365 days? Or which of Julian, Gregorian, Tropical,
           | Sidereal? At even kilo prefix the differences do add up. Or
           | would you need to specify it?
           | 
           | Days, weeks and months are also fun mess to think of.
        
             | BlueTemplar wrote:
             | This is going to depend on the precision that you need.
             | 
             | (Calculations without associated uncertainty calculations
             | are worse than worthless anyway - misleading due to the
             | inherent trust we tend to put in numbers regardless of
             | whether they are garbage.)
        
             | dragonwriter wrote:
             | > Once we get to Gigayears, what is the size of single
             | year?
             | 
             | The appropriate system of units is context-dependent. The
             | astronomical system, for instance, has Days of 86,400 SI
             | seconds and Julian years of exactly 365.25 Days; if you
             | have a general and extensible units library, then this
             | isn't really a difficulty, you just need to make a choice
             | based on requirements.
        
         | necovek wrote:
         | If your use of a value in units lives for so long as for it to
         | not be clear in what unit it is in or should be in (eg. spans
         | more than 20 lines of code), I think you've got a bigger
         | problem with code encapsulation.
         | 
         | I think the practical problem stems from widespread APIs which
         | are not communicating their units, and that's what we should be
         | fixing instead: if APIs are clearer (and also self-documenting
         | more), the risks you talk of rarely exist other than in badly
         | structured code.
         | 
         | Basically, instead of having `sleep(wait_in_seconds)` one
         | should have `sleep_for_seconds(wait_time)` or even
         | `sleep(duration_in_seconds=wait_time)` if your language allows
         | that.
         | 
         | But certainly use of proper semantic types would be a net win,
         | but they usually lose out in the convenience of typing them out
         | (and sometimes constructing them if they don't already exist in
         | your language).
        
         | Too wrote:
         | Add to this any type of conversion or relations between units.
         | 
         | PIXELS_PER_INCH or BITS_PER_LITER rather than
         | SCREEN_SCALE_FACTOR and VOLUME_RESOLUTION, avoids all kinds of
         | mistakes like inverting ratios etc.
        
         | ranaexmachina wrote:
         | I think you would enjoy programming in Ada.
        
           | ajdude wrote:
           | When I first started to learn Ada, I found it one of the most
           | verbose languages I've ever used. Now I find myself
           | practicing those wordy conventions in other languages too.
        
         | ReleaseCandidat wrote:
         | I _really_, _really_ like F#'s 'unit of measure':
         | https://docs.microsoft.com/en-us/dotnet/fsharp/language-refe...
        
           | fluid_ident wrote:
           | This. I really miss it when working outside of F#. I work on
           | scientific code bases with a lot of different units and have
           | been burned by improper conversions. Even with a high
           | automated test coverage and good naming practices, such
           | problems can go undetected.
        
           | ok123456 wrote:
           | It's a big omission that it doesn't support fractional units.
           | These come up in things like fracture mechanics for stress
           | intensity.
        
             | ReleaseCandidat wrote:
             | Are you talking about ksi[?]in or MPa[?]m? That is not a
             | problem.
        
               | ok123456 wrote:
               | F#'s units don't support 1/2 dimensions. So you can't do
               | dimensional analysis through the type system.
        
         | sandreas wrote:
         | For everyone using Python and willing to try this:
         | 
         | https://pint.readthedocs.io/en/stable/
        
         | wildzzz wrote:
         | In my software project, all measurements exist as engineering
         | units since they all come from various systems (ADCs or DSP
         | boxes). We pass the values around to other pieces of software
         | but are displayed as both the original values and converted
         | units. We have a config file that contains both units and
         | conversion polynomials, ranging from linear to cubic
         | polynomials. Some of the DSP-derived values are at best an
         | approximation so these have special flags that basically mean
         | "for reference only". Having the unit is helpful for these but
         | are effectively meaningless since the numbers are not precise
         | enough, it would be like trying to determine lumens of a desk
         | lamp from a photo taken outside of a building with the shades
         | drawn.
        
         | philsnow wrote:
         | Having units as part of your types improves legibility for
         | whoever's writing code too, not just reviewing. You won't make
         | (as many) silly mistakes like adding a value in meters to
         | another in seconds.
        
         | jweir wrote:
         | The wonder elm-units is such a pleasure to work with and does
         | just that.
         | 
         | https://package.elm-lang.org/packages/ianmackenzie/elm-units...
         | 
         | Even if you don't work in Elm take a moment to look at it.
        
         | Beltiras wrote:
         | This is just about the best justification I have heard for type
         | calculus.
        
         | valbaca wrote:
         | > Option 2: use strong types
        
         | EdwardDiego wrote:
         | God I love F#'s unit types. C# is okay and all, but F# is, IMO,
         | the best FP-language-on-a-corporate-backed-VM ever, even if the
         | integration with the underlying VM and interop can get a bit
         | fiddly in places (Caveat, my opinion is about 7 years old).
         | 
         | Yeah, you heard me Scala.
        
           | pjmlp wrote:
           | Sadly it hardly got better, C# gets all the new .NET toys, VB
           | less so, C++/CLI still gets some occasional love (mostly due
           | to Forms / WPF dependencies), and then there is F#.
        
       | rzimmerman wrote:
       | When I put together Kal (a compile to JavaScript language, now
       | defunct), I was particular about this and used the sleep syntax:
       | pause for 3 seconds
       | 
       | With some other options for units.
       | https://github.com/rzimmerman/kal#asynchronous-pause
        
       | userbinator wrote:
       | _but how can we keep the code readable even for people who
       | haven't encountered time.sleep before?_
       | 
       | Contrarian opinion: You don't. You make people look up and
       | internalise such information; that way they'll actually learn, as
       | otherwise they'll forever stay within the realm of "beginner".
       | Perhaps that's a goal for those who want to make programmers
       | fungible (and I suspect a lot of the "readability" movement is
       | merely an extension of that), but I don't think that's something
       | we should encourage.
        
         | jitl wrote:
         | Perhaps sleep in $YOURLANG is essential/trivial so there's an
         | argument that you should memorize it. OF course! It's just one
         | bit of info. But there are more APIs than sleep that take a
         | number. Are they guaranteed to be consistent? No. What about
         | `someVendorApi.setTTL(ttl: number)`? Is this also another thing
         | to be looked up and internalized? What if there are hundreds of
         | APIs that take numbers?
         | 
         | I would rather have my team spend time internalizing good
         | design rather than the trivia of what units are associated with
         | every numeric argument in every codebase.
        
         | l33t2328 wrote:
         | You'd prefer we made our code as hard to read as possible to
         | increase job security?
        
         | Spivak wrote:
         | Although there is some merit to learning by repetition and
         | using memorization to keep core concepts top of mind, this is a
         | very bad example of it since it's literally just trivia. There
         | is nothing at all fundamental about time.sleep being seconds.
         | People memorize it because the have to and have used it enough
         | times.
         | 
         | If time.sleep took a timedelta it becomes _impossible_ to use
         | incorrectly with a type checker since the caller specifies
         | their own units. There is no merit to worshiping ambiguous
         | design.
        
         | tharkun__ wrote:
         | Disagree.
         | 
         | What you say works at a small startup. Absolutely.
         | 
         | My reality and lots of other people at companies with larger
         | code bases: you need to constantly look at code you have never
         | seen before in one of many languages used at your company using
         | one framework or another that is out of date by years or just
         | came around the corner and you just heard the name of for the
         | first time.
         | 
         | This is the reality of many an architect or team lead or
         | principal engineer. Of course you will say: why make everything
         | better for them, works fine for me who I only ever work in
         | language X with framework Y? I agree that makes sense for the
         | you of now. Why care?
         | 
         | Think about the future you. The principal engineer you. The
         | architect you. Heck even just the 9 months from now you when
         | you have moved on to the next framework. Never mind any other
         | changes.
        
         | jackblemming wrote:
         | People have died because airplane mechanics thought they were
         | working with one unit instead of another. Don't be a macho
         | tough guy who thinks you'll never slip up.
        
         | gpderetta wrote:
         | Sure, but how does the reader of the code know if the writer of
         | the code did internalize this information or just made a
         | mistake?
        
         | rhinoceraptor wrote:
         | How is rote memorization of the arguments the stdlib of a
         | language the difference between a beginner and an expert? I
         | forget those kinds of things all the time, even for the
         | language I use 99% of the time.
        
       | Karellen wrote:
       | Yes, don't use Magic Numbers, but use named constants instead.
       | 
       | http://catb.org/jargon/html/M/magic-number.html
       | 
       | https://en.wikipedia.org/wiki/Magic_number_(programming)
       | delay_ms = 300;         [...]         Thread.sleep(delay_ms);
       | 
       | Works in any programming language.
        
         | Someone wrote:
         | Fails in any programming language, too.
         | delay_seconds = 300;         [...]
         | Thread.sleep(delay_seconds);
         | 
         | This kind of bug can easily surface if you need the constant
         | for calls taking different units and can be hard to spot.
        
           | gpderetta wrote:
           | Yes; still parent solution is better than nothing if you have
           | to deal with an existing API. At least if you make a mistake
           | there is a chance someone else might spot it instead of
           | wondering what the original intent was.
        
       | macinjosh wrote:
       | When I learned Objective-C I remember being flabbergasted at all
       | the method and argument names that were exceedingly wordy. At
       | some point I read a blog post[0] that said while this is out of
       | the ordinary when it comes to most code having long, descriptive
       | names helps when reading code.
       | 
       | Some people complain that it involves too much typing or takes up
       | too much space. In reality, we spend much more time reading code
       | than we do writing it, so names that provide context, direction,
       | and fore-shadowing are really useful.
       | 
       | I still tend to write method names and important variable names
       | like that to this day in pretty much any language I use. IMHO,
       | its a great hack.
       | 
       | An extreme example is in the NSBitmapImageRep class [1]
       | 
       | [0]: https://www.cocoawithlove.com/2009/06/method-names-in-
       | object...
       | 
       | [1]:
       | https://developer.apple.com/documentation/appkit/nsbitmapima...
        
         | wnoise wrote:
         | Autocomplete handles the "too much typing" case.
        
       | [deleted]
        
       | adolph wrote:
       | _The Unified Code for Units of Measure (UCUM) is a code system
       | intended to include all units of measures being contemporarily
       | used in international science, engineering, and business. The
       | purpose is to facilitate unambiguous electronic communication of
       | quantities together with their units. The focus is on electronic
       | communication, as opposed to communication between humans. A
       | typical application of The Unified Code for Units of Measure are
       | electronic data interchange (EDI) protocols, but there is nothing
       | that prevents it from being used in other types of machine
       | communication._
       | 
       | http://unitsofmeasure.org
       | 
       | An example of use is in the FHIR (Fast Healthcare
       | Interoperability Resources (hl7.org/fhir)) standard as a
       | valueset.
       | 
       | https://www.hl7.org/fhir/valueset-ucum-units.html
       | 
       | [edit to remove dupe linke]
        
       | rbanffy wrote:
       | On a related, but not quite the same, it'd be quite cool to be
       | able to express number literals as: 2K (for 2000), or 2K4 (for
       | 2400), or 1Ki for 1024.
        
       | TeeWEE wrote:
       | I love the Duration class that Dart has:
       | https://api.flutter.dev/flutter/dart-core/Duration-class.htm...
        
       | some_random wrote:
       | Maybe this is just me, but this suggestion seems worse than the
       | problems                 def frobnicate(timeout: timedelta) ->
       | None:           ...            timeout = timedelta(seconds=300)
       | frobnicate(timeout)
       | 
       | Now instead of remembering that frobnicate takes an argument of
       | seconds, one now needs to remember it takes a completely
       | different type, the constructor for which now also needs to be
       | memorized. When the main problem presented is one of
       | memorization, this seems obviously worse?
        
         | belval wrote:
         | I suppose that it varies depending on the project/person, but I
         | agree that using timedelta is less intuitive than just using
         | seconds (as is done everywhere in Python).
        
         | tehwebguy wrote:
         | Your editor will just tell you the type you need, no?
        
         | AllegedAlec wrote:
         | > the constructor for which now also needs to be memorized
         | 
         | This seems less like a memorisation problem and more of an IDE
         | one. If I'm presented with a type in my IDE, I can just look
         | through its constructors and methods to find the one I require;
         | no need for memorisation.
        
         | wpietri wrote:
         | The problem is one of readability, not memorization. A lot of
         | readability amounts to taking what the initial author already
         | knows and expressing it so that it's easy for everybody who
         | comes after to know too.
         | 
         | Making implicit units explicit is a great example of that. Look
         | at Martin Fowler's writings on Money types, for example. Or
         | look at the $125 million failure of a space probe because
         | people used implicit units:
         | https://www.simscale.com/blog/2017/12/nasa-mars-climate-orbi...
        
       | bennyp101 wrote:
       | Is this not what comments are for?
       | 
       | frobnicate(300) // Duration in seconds to do X
       | 
       | Sure, change the variable names or whatever as well, but ...
       | kinda seems we already have a way to make less obvious things
       | obvious?
        
         | Aeolun wrote:
         | Problem with this is that you now need to ensure everyone adds
         | that comment everywhere the function is used.
         | 
         | If it's in the parameter name it's impossible to use it without
         | doing it correct, which is almost always preferable.
        
         | berkes wrote:
         | It helps. Even more so if documented with the function
         | signature so documentation (in your editor or ide) can
         | communicate it.
         | 
         | But one better than documenting comments is no documenting
         | comments. Selfdocumenting code is certainly not always
         | feasible. But in this case it's both possible and easy.
        
       | teddyh wrote:
       | > _Don't design your config file like this:_
       | 
       | > _request_timeout = 10_
       | 
       | > _Accept one of these instead:_
       | 
       | > _request_timeout = 10s_
       | 
       | > _request_timeout_seconds = 10_
       | 
       | What does "s" imply? Can I write "10m" for 10 minutes, or is that
       | 10 months? Non-standardized syntax is dangerous.
       | 
       | For config files, I use RFC 3339 duration syntax; i.e. "PT5M" for
       | five minutes. It was the most standardized syntax for semi-human
       | readable time periods which I could find.
        
         | pikzel wrote:
         | Had I seen PT5M I would have never guessed it meant five
         | minutes, so you would need to refer to the RFC then.
        
         | hkolk wrote:
         | `m` is not a legal value, should be either `min` or `mo` for
         | minutes or months respectively.
         | 
         | `s` is actually one of the SI base units:
         | https://en.wikipedia.org/wiki/International_System_of_Units#...
         | 
         | edit: actually, month should never be used for the case
         | described anyway... 28-31 days?
        
           | teddyh wrote:
           | If the syntax isn't obvious without looking at the manual,
           | you might as well use an actual standardized syntax. For
           | months (without context, and where you need an absolute
           | interval), I just interpret it as 4 weeks.
        
             | int_19h wrote:
             | If the syntax isn't obvious, you should use however much
             | verbosity it takes to make it obvious, because people will
             | still ignore the standard and make mistakes.
        
             | tremon wrote:
             | _I just interpret it as 4 weeks_
             | 
             | Funny, I would interpret a month as 30 days (since the
             | lunar cycle is slightly over 29.5 days).
        
       | Karliss wrote:
       | One more related problem is coordinate systems for positions in
       | any kind of robotics software or even 2d UI applications.
        
       | munk-a wrote:
       | PHP offers sleep[1] and usleep[2] which sleep for a period in
       | either seconds or microseconds respectively. I don't know why
       | every other programming language ever hasn't adopted this habit.
       | (There's also time_nanosleep[3] which definitely could be better
       | defined, but it's PHP, sleeping for some amount of time between a
       | nanosecond and a microsecond is pretty hilarious when you're
       | running on an interpreter).
       | 
       | 1. https://www.php.net/manual/en/function.sleep.php
       | 
       | 2. https://www.php.net/manual/en/function.usleep.php
       | 
       | 3. https://www.php.net/manual/en/function.time-nanosleep.php
        
       | antisthenes wrote:
       | Well, the only correct way to do it then is the way Python does
       | it.
       | 
       | The SI unit is seconds. So unless you have some weird aversion to
       | using decimals to represent smaller units, any kind of delay
       | function should take input in seconds.
       | 
       | Not sure if this should be a cautionary tale about using units so
       | much as using the correct units in the first place.
       | 
       | Apparently there's a Java function that lets you specify time
       | units as secondary input. Use that to make in unambiguous.
        
         | mmis1000 wrote:
         | Well, no. There are language's default unit is milliseconds.
         | 
         | The foundation of web, javascript is one of them. Send seconds
         | in api to a frond-end without documenting is just confusing and
         | hugely ambiguous.
         | 
         | And it makes more sense from the GUI's perspective. What did
         | you mean paint next frame after 0.016s? Isn't it much easier to
         | read when write it as 16ms?
        
       | suhlig wrote:
       | dimensioned[1] got me interested in Rust. I'm not far enough to
       | recommend it, but the concept seems right.
       | 
       | [1] https://github.com/paholg/dimensioned
        
       | blenderdt wrote:
       | In a lot of software you can enter units into input fields. For
       | example in Blender I can move an object in a direction by
       | entering something like: `(1m+5inch)/2`. Or I can set the max
       | render time to `20sec` or `2min`.
       | 
       | When the input box is a function the only unit you need to know
       | is 'distance'. So I don't completely agree with the article. A
       | sleep function does not need the unit in it's name but should
       | accept a domain unit: duration. The function itself can convert
       | it to something the function can handle.
       | 
       | `sleep(2s+5ms)` should just sleep 2 seconds and 5 milliseconds.
        
       | hmaarrfk wrote:
       | I typically stick to "SI" units.
       | 
       | Then, somebody asks me to code in the temperature of a system.
       | And I have to think: "Is now really the time that I want to teach
       | people the difference a kelvins and celsius?"
       | 
       | So my rule becomes, SI "except" temperature. Sigh...
        
         | jeffparsons wrote:
         | But you're still including the units in your identifier names
         | (or encoded in type system), right?
        
           | hmaarrfk wrote:
           | No. Typically SI is implicit. Everything else is explicit.
        
             | mminer237 wrote:
             | SI doesn't prescribe that you have to use a single unit for
             | all measurements. Are distance in meters or kilometers?
             | Weights in kilograms or grams?
             | 
             | I assume you always just use the base units? kg, m, s,
             | etc.? (I always think it odd that _kilo_ gram is the base.)
             | I feel like could get weighty for some applications of a
             | different scales when milligrams, millimeters, kilometers,
             | days, etc. could be clearer. And even if you use "standard"
             | units, if you aren't clear about what standard you use and
             | what that makes that units, people won't always guess the
             | correct option.
        
         | sorisos wrote:
         | There should be a exception in every code standard that says SI
         | units are OK where otherwise all lower case is enforced.
         | Example to use mega (M) vs milli (m).
        
         | jjgreen wrote:
         | MKS or CGS?
        
           | WinterMount223 wrote:
           | CGS is so the sixties!
        
         | nvader wrote:
         | I'm confused, because one delta degree Celsius is exactly the
         | same as one delta degree Kelvin. And you can convert with an
         | offset.
        
           | nine_k wrote:
           | In thermodynamic calculations you likely need absolute
           | (Kelvin) values. But in many calculations where only
           | temperature _difference_ is used, either unit works equally
           | well.
        
             | xmprt wrote:
             | That sounds like a case for Kelvin. I still don't see why
             | Celsius is the one exception that isn't SI.
        
               | hmaarrfk wrote:
               | I'll take a survey tomorrow to see how many people know
               | what kelvin to C conversion is off the top of their head.
               | 
               | The other issue is when you get to Candelas!
        
               | xmprt wrote:
               | How often are you doing the conversion manually? It seems
               | like the sort of thing that should happen in the
               | presentation layer so people never see the actual Kelvin
               | amount. If you have a system where you always use SI then
               | it's strange the have a single exception for temperature.
        
               | hutzlibu wrote:
               | Hm, is it wrong to dream of a world, where this along
               | with other basic science, would be considered basic
               | knowlege?
               | 
               | Not blaming anyone who does not know it, but I would
               | argue for more and better science education ..
        
         | notatoad wrote:
         | which is great when you're writing from scratch, but as soon as
         | you have to start calling a library with functions based in
         | non-SI units then you've got some ambiguity.
        
         | kralos wrote:
         | We also strictly stick to SI however we usually say kilograms
         | in var names to be clear.
         | 
         | Haven't come across temperature however we would probably stick
         | with kelvin.
         | 
         | We use a strict set of units in databases and while processing,
         | conversions are localized if necessary only at the view layer.
         | 
         | We also only use UTC for date/times.
         | 
         | We only use E164 format (without spaces etc) for phone numbers:
         | e.g. +12345678901 for an example number in OH, US. see National
         | format
         | https://libphonenumber.appspot.com/phonenumberparser?number=...
         | 
         | We only use iso3166-1 country codes and iso3166-2 region codes
         | and translate on view.
        
         | joshvm wrote:
         | This is actually an issue with thermal imaging cameras.
         | Typically you'll get calibrated readings back in Kelvin, not in
         | Celsius. Usually it's well documented by the camera
         | manufacturer, but if you're providing an API to users you need
         | to make them aware what the units are and make a decision on
         | what you're going to return. For example this crops up if the
         | sensor only provides counts which you need to convert into a
         | temperature.
         | 
         | From a hardware perspective it makes sense to use K because you
         | can encode the image directly using unsigned numbers plus some
         | gain to allow for fractional measurements.
        
         | arpa wrote:
         | This, one million times this. Use SI units. Don't measure
         | distance in hotdogs, time in fortnights and speed in hotdogs
         | per fortnight! It is as stupid as it sounds.
         | 
         | If you do, be explicit about it either in parameter or function
         | name. I'm not going to put you on my shitlist if you're naming
         | your function `microsleep`, but if I have to go look into
         | implementation to see that you count timeout on your database
         | in microseconds (looking at you, couchbase, like you ever could
         | return something from a larger dataset in microseconds, lol)
         | or, even worse, cache expiry time in minutes (hello unknown
         | developer), I am going to go on the internet and complain about
         | you.
        
       | usrbinbash wrote:
       | _*cough*_ Golang _*cough*_                   time.Sleep(42 *
       | time.Millisecond)         time.Sleep(42 * time.Second)
       | time.Sleep(42 * time.Nanosecond)         time.Sleep(42 *
       | time.Hour)
        
         | conradludgate wrote:
         | The trouble with Go is that you can't multiple ints by
         | Durations, leading to people doing `time.Sleep(time.Duration(x)
         | * time.Second)` which is fine by itself, but then I see often
         | people refactor and accidentally remove the second part.
         | 
         | The fact you can go from int to duration without specifying the
         | unit does not give you the strong benefits. It's better than
         | nothing though
        
           | usrbinbash wrote:
           | > The fact you can go from int to duration without specifying
           | the unit
           | 
           | The unit that is converted in, is in the first sentence of
           | the two-sentence documentation of time.Duration():
           | A Duration represents the elapsed time between two instants
           | as an int64 nanosecond count.
           | 
           | https://pkg.go.dev/time@go1.18#Duration
        
             | conradludgate wrote:
             | Yes, in the documentation. But if I'm reading the original
             | code and refactoring, having the docs open might not be my
             | top priority
        
         | int_19h wrote:
         | time.Sleep(time.Second * time.Second)
        
       | numlock86 wrote:
       | https://web.mit.edu/jemorris/humor/500-miles
       | 
       | Somewhat relevant.
        
       | scottmcdot wrote:
       | Does anyone else like to put data types in their variable names?
       | Sometimes in finance I come across dollars and cents presented as
       | an int and sometimes as decimal(18,2). So I don't confuse them I
       | do something like payment_amt_d1802 or payment_amt_int.
        
       | BurningFrog wrote:
       | I end up writing this function in most projects I work on. Python
       | version:                   @lru_cache(maxsize=None)  # memoize
       | def seconds(time_code):             """number of seconds defined
       | in DNS format: '2m30s' = 2 min 30 sec = 150s. h = hour, d = day,
       | w = week"""             result = 0             number = ""
       | for char in time_code:                 if char.isdigit():
       | number += char                 else:                     secs =
       | {"s": 1, "m": 60, "h": 3600, "d": 24 * 3600, "w": 7 * 24 *
       | 3600}[char]                     result += int(number) * secs
       | number = ""             return result
        
       | athenot wrote:
       | And if you're working with an existing system that doesn't
       | accomodate the suggested options, a well placed comment can go a
       | long way. Provide the unit as well as WHY that value exists.
       | # Session inactivity, in seconds         time.sleep(300)
       | # Prevent pileup of unprocessable requests, in seconds
       | request_timeout = 10
        
         | refactor_master wrote:
         | Comments are misunderstood far too often as some sort of
         | accompanying inner monologue. Instead, I see a lot of noise
         | like                   # Sleeps before continuing
         | time.sleep(...)              # Time before request timeout
         | timeout = ...
        
       | DubiousPusher wrote:
       | Probably already suggested but I'm a big fan of .Net attributes
       | or other such decorators. A system level Units decorator which
       | was respected in argument passing and maybe even automatically
       | printed would be dope.
        
       | yummypaint wrote:
       | For an example of physical units done right check out the GEANT4
       | monte-carlo system. It pretty much "just works"
       | 
       | https://geant4.web.cern.ch/sites/default/files/geant4/collab...
        
       | asimpletune wrote:
       | A while back I made a units and dimensions library where I
       | worked. Everything was built into the type system, with a
       | required SI conversion for each unit of a certain dimension.
       | 
       | This did the job really well, but it was incomplete. Being able
       | to create new types dynamically, when multiplying/dividing was
       | something that was always missing. I guess now you could probably
       | do this with macro programming, but back then I don't think my
       | language had it.
        
       | Leherenn wrote:
       | Most people are talking about time here, but the one I've seen
       | that has caused the most issues in my experience is deg/rad. UI
       | are pretty much always going to be in degrees, and trigonometric
       | functions in radians, but if you forget to convert it's not
       | always going to be obvious.
        
       | pdimitar wrote:
       | In Elixir you can use an unused variable pattern matching:
       | Process.sleep(_milliseconds = 300)
       | 
       | I started using it more and more because it makes the code more
       | readable.
        
       | gumby wrote:
       | C++ gets this right for time durations, and has packages that do
       | it for other units as well.
        
         | omoikane wrote:
         | Perhaps you mean one of these?
         | 
         | https://en.cppreference.com/w/cpp/chrono/duration
         | 
         | https://abseil.io/docs/cpp/guides/time#time-durations
        
           | carlsborg wrote:
           | user defined literals
           | 
           | using namespace std::chrono;
           | 
           | std::this_thread::sleep_for(30s);
        
           | gumby wrote:
           | Yes, the first being part of the standard and the abseil one
           | a 3P implementation.
           | 
           | Boost units add all sorts of dimensional analysis.
        
       | rubenbe wrote:
       | For C++ you can use boost units. It is basically built up of
       | template magic which only compiles when your units are correct.
       | The disadvantage: when it doesn't, it explodes in a huge template
       | error. But when it does, you can be pretty certain (depending on
       | the actual calculation) that your code is correct. It is also
       | fully verified at compile time, so there is no runtime overhead.
       | 
       | https://www.boost.org/doc/libs/1_78_0/doc/html/boost_units.h...
        
       | hoten wrote:
       | just today I wasted some debugging cycles when my problem was
       | using "sleep(500)" vs "usleep(500 * 1000)" (500 seconds vs 500
       | ms).
       | 
       | "why isn't my code doing anything?!"
        
       | armchairhacker wrote:
       | Built-in unit types are underrated. F# has them. Other languages
       | should seriously consider adding them, despite the fact that
       | feature bloat is a serious language problem and they're
       | relatively niche: they are that useful, and I honestly don't
       | think they would interfere much with other features.
       | 
       | Something like:                   unit type Meters = m
       | unit type Seconds = s              function sleep(time: Int[s]):
       | void              val speed = 5.4 m/s // Type = Float[m/s]
       | val distance = parseFloat(prompt('enter time')) * 1 m // Convert
       | unitless to meters just by multiplying         val time =
       | distance / speed // Type = Float[s]         print("${time}") //
       | Prints "# s"         print("${time / 1 s} seconds") // Prints "#
       | seconds"              val complexUnit = 7 * 1 lbf/in2 // 7
       | lbf/in2         // != 7 psi (too hard to infer) but you can write
       | a converter function         function toPsi<N : Numeral>(value:
       | N[lbf/in2]): N[psi] {             return value * 1 psi*in2/lbf
       | }
       | 
       | It requires extending number parsing, type parsing (if the
       | brackets aren't already part e.g. in TypeScript), and extending
       | types to support units of measurement at least if they are
       | statically known to be subtypes of `Numeral`.
       | 
       | Naming variables with their units doesn't solve the issue of mis-
       | casting and using units incorrectly, and newtypes are too
       | inconvenient (and sometimes impossible without affecting
       | performance) so nobody uses them. Even as a very software-focused
       | programmer I encounter units like seconds, bytes, pixels, etc.
       | all the time, they are almost never newtypes, and I get bugs from
       | forgetting to convert or converting incorrectly.
        
         | stefs wrote:
         | your example is a bit confusing because you mislabeled the
         | prompt for distance in                   val distance =
         | parseFloat(prompt('enter time')) * 1 m // Convert unitless to
         | meters just by multiplying
        
         | lf-non wrote:
         | Yup, I have been using branded types in TS to avoid similar
         | issues, and I still do miss F# units of measure.
         | 
         | Even though branded types prevent assignment of values with
         | invalid units, opaque types are inferior in that the compiler
         | doesn't know the relationship between the types (as exemplified
         | in the parent comment) and you need a slew of helper functions
         | & casting.
        
           | WorldMaker wrote:
           | I just realized that you could probably do a decently complex
           | unit algebra (at least to the basic level of F#'s unit of
           | measure support) using the unit strings as brands and
           | Typescript's template string types to match them. I'm not
           | sure if that's a good idea or not in practice, but after
           | seeing Wordle done with template string types I'm more
           | certain than ever it is possible to do some interesting
           | things with it.
        
           | eyelidlessness wrote:
           | I use a variant of branding in TS for this too, but it's very
           | much shoving semantics into the language that aren't meant to
           | be there. Subclasses of primitive types would be semantically
           | closer to F#, but at the expense of being able to ever treat
           | the values as values
        
         | perth wrote:
         | My Ti-89 has this. It's actually really useful because I don't
         | always remember the magical ways units fit together and it
         | solves and simplifies the units for me.
        
         | saeranv wrote:
         | Can someone break this down for me? val speed = 5.4 m/s // Type
         | = Float[m/s]
         | 
         | I understand that the speed variable is automatically assigned
         | a type of Float[m/s] based on the m/s there, but I'm confused
         | about how the units are just placed at the end of the value
         | assignment: val speed = {value} {unit}
         | 
         | Is this just a F# property that units can be added at the end
         | of value assignment, and F# interprets them as units correctly?
         | 
         | Also, anyone know of methods for incorporating units as types
         | in Python? It would be great to have an equivalent method as
         | demonstrated here, where dividing types automatically creates a
         | new type unit, and perhaps even associates with a related type,
         | i.e: type(kg / (m * m * m)) == density
        
           | AaronFriel wrote:
           | I think the syntax for expressions was extended to allow a
           | `<unit expression>`, with or without angle brackets, at the
           | end of any numeric expression. They're erased at compile
           | time, so at runtime or via reflection you can't inspect the
           | dimensions of a value. The only value of the units - which
           | isn't insignificant - is the compile time checking.
           | 
           | Unfortunately the same isn't as easily done in Python:
           | 
           | 1. You would need to reify these units as actual constants
           | with overridden operators to track values, and some wacky (if
           | even possible) mypy type shenanigans.
           | 
           | 2. The types aren't erased and so would impact the
           | performance of any critical code. F# isn't quite used in high
           | frequency trading, but it does target numeric heavy users
           | like those wanting to write scientific workloads, and units
           | help improve correctness there. But if the types are computed
           | at runtime and not erased, it would be an enormous hit to
           | performance.
           | 
           | Unless you can figure out some way to get "3.0 * m" to be a
           | plain old datatype (float) in Python while still retaining
           | type info in mypy/pylance/pyrite. Perhaps there's a way, but
           | I'm not sure.
           | 
           | Edit: This Python library seems to be trying to solve for
           | these issues! https://pint.readthedocs.io/en/0.10.1/
           | 
           | I'm not sure if they've actually solved the runtime
           | performance problem, but I suppose as long as you're not
           | doing unit assignment/conversion in a loop, it should be
           | fine.
        
         | gpderetta wrote:
         | In C++ units can, and often are, implemented on top of the
         | existing type system.
         | 
         | See std::duration/time_point specifically for times, and
         | boost.units for generalized unit support.
         | 
         | It is implemented via (templated) wrappers, but they are very
         | close to zero overhead if not completely free. User defined
         | literals also allow for a very succinct syntax, but to be
         | honest, I usually don't bother. I normally write:
         | auto delay = std::chrono::seconds{3};
         | 
         | instead of:                   auto delay = 1s;
        
           | [deleted]
        
           | ChrisLomont wrote:
           | In C++ you can use user defined literals to make the units
           | stuff compile time checked, similar to this
           | https://github.com/bernedom/SI for example.
        
         | cycomanic wrote:
         | So from your example I understand that F# doesn't know how to
         | do more complex unit conversion? Does it know N=kg m/s^2 for
         | example? That's related to the issue I often encountered with
         | unit types. They work great for simple use cases, and give you
         | a sense of security, but then fail and you end up writing lots
         | of code just to make the unit types happy (you might argue that
         | it makes the code safer, but it can be a lot of time spend).
         | One cthing that falls over in pretty much all implementations
         | I've encountered is log units (dBm, dBW,...)
        
           | int_19h wrote:
           | > Does it know N=kg m/s^2 for example?
           | 
           | F# does if you tell it, i.e.:                  [<Measure>]
           | type kg = g        [<Measure>] type m        [<Measure>] type
           | s        [<Measure>] type N = kg * m / s^2
           | 
           | Although, of course, in practice you'd probably just use
           | whatever's defined in https://fsharp.github.io/fsharp-core-
           | docs/reference/fsharp-d...
           | 
           | Not for log units tho.
        
           | [deleted]
        
         | eurasiantiger wrote:
         | In the land of JavaScript, one could implement unit types as a
         | babel plugin.
        
           | lf-non wrote:
           | I don't see how you'd go about doing this. Babel doesn't have
           | a type checker, and for type level features you'd need
           | support from typescript.
           | 
           | So you need a typescript plugin - however the typescript
           | compiler api (which btw is not officially supported) is not
           | flexible enough to support new type syntax (for things like
           | m/s) so you'd a fork.
        
             | eurasiantiger wrote:
             | babel-plugin-typecheck, babel-plugin-tcomb and babel-
             | plugin-jsdoc-type-checker (among others) are able to do
             | similar things, so there must be a way. And I don't see why
             | not, since babel is "just" an AST parser/transformer.
        
               | lf-non wrote:
               | Those plugins primarily help with with runtime type
               | validations - the static type checking is delegated to
               | Flow/TS.
               | 
               | The benefits around F# units of measure that the parent
               | talks about are primarily focused on static type
               | checking.
               | 
               | If you are fine with the overhead of runtime boxing, it
               | is relatively straightforward to have different container
               | classes for different units and have bridge apis to
               | convert/operate between them. A babel plugin could
               | potentially help with operator overloading here, but this
               | is quite far removed from F# units of measure at this
               | point.
        
               | eurasiantiger wrote:
               | Is writing a static unit type checker as a plugin a
               | daunting task, then? I've never thought of it in detail,
               | but it would seem that unit type checking rules for basic
               | operations like add/subtract and multiply/divide would be
               | straightforward, and everything else could be derived
               | from there. The laborious task is just formulae.
        
           | _flux wrote:
           | Going from "could" to actually doing it are two very
           | different things, however.
        
         | aspaceman wrote:
         | See https://unyt.readthedocs.io/en/stable/ in Python. This sort
         | of feature fits really well within Python's featureset.
        
       | cryptos wrote:
       | Java has a good library that supports a variety of measurement
       | units: javax.measure
       | https://docs.google.com/document/d/12KhosAFriGCczBs6gwtJJDfg...
       | http://unitsofmeasurement.github.io/unit-api/site/apidocs/ja...
       | 
       | The java.time API goes in the same direction, but is obviously
       | limited to things around time.
       | 
       | I think units should be really expressed with the type system,
       | because types give meaning _and_ safety. If used APIs require
       | typed units you wouldn't even need a coding convention to put the
       | unit in a variable name.
        
       | [deleted]
        
       | lkxijlewlf wrote:
       | three_seconds=3000
       | 
       | ...
       | 
       | time.sleep(three_seconds)
        
       | MadVikingGod wrote:
       | Ahh the cycle continues. We have lost touch with the lore of ages
       | past, and only the old crones know of the Hungarian notation [1].
       | As we discover the ruins of old we glean their knowledge, and
       | take up their practices because they were from a more civil time.
       | What we don't recognize is that the creators of old didn't solve
       | these problems and they were always in competition with
       | themselves over which path is righteous. This ultimately led to
       | their downfall, and the ruins you have discovered.
       | 
       | Take heed young adventurer: This balm will not solve all your
       | ills. It will be your hard work, compassion, and perseverance
       | that will bring the new golden age and sustain it.
       | 
       | TLDR: We've done this before, it solves some problems and causes
       | other.
       | 
       | 1: https://en.wikipedia.org/wiki/Hungarian_notation
        
       | MrYellowP wrote:
       | Ridiculous. You're supposed to _know_ what you 're doing. He
       | should stop coding instead and do something that fits his skills.
       | 
       | When it's already too hard knowing the units of the function
       | you're _supposed to know_ , then why does he think he's supposed
       | to code in the first place?
       | 
       | Bat-shit ridiculous. Of course people with low skills will be all
       | over this, happily embracing it, _but it 's still absolutely
       | ridiculous_.
       | 
       | If you can't even remember _this_ , then you should not be
       | programming in the first place!
        
         | aembleton wrote:
         | Wouldn't it help other to learn though if it's clearer? As you
         | have to label variables, why not include units? How does that
         | hinder you?
         | 
         | Do you label your variables a, b, c,...?
        
           | gpderetta wrote:
           | Variables? Point-free programming is the name of the game!
        
       | moelf wrote:
       | or just have multi-dispatch, Julia:                 julia> using
       | Dates            julia> Millisecond(10)       10 milliseconds
       | julia> sleep(Microsecond(100))            julia>
       | sleep(Millisecond(10))
        
       | zcombynator wrote:
       | Unconventional take: just take the SI base unit any time. For
       | time it's 1 second.
        
       | thom wrote:
       | If you're old you call this the Whole Value pattern.
       | 
       | http://fit.c2.com/wiki.cgi?WholeValue
        
       | pacifika wrote:
       | 300 * TIME_IN_SECONDS
        
       | hosembafer wrote:
       | Similar topic, instead of var names, in typed languages you can
       | use domain-specific types for primitives.
       | 
       | https://overcoddicted.com/domain-specific-types-for-primitiv...
        
       | tempodox wrote:
       | And, please, also attach units to numeric input fields in the UI
       | so users know what they're entering.
        
       | spixy wrote:
       | C#:                   Thread.Sleep(TimeSpan.FromSeconds(3));
       | 
       | or with its int overloaded method:
       | Thread.Sleep(millisecondsTimeout: 3000);
        
       | sclangdon wrote:
       | I have a similar nitpick with boolean arguments. How many times
       | have you seen something like: DoSomething(true, false, false)?
       | It's much more readable if you use enums (in a language that
       | doesn't let you specify the argument name at the call site). E.G.
       | DoSomething(ENABLE_REPORTING, USE_UTC, OUTPUT_VERBOSE).
        
       | drej wrote:
       | Clicking on the link I though "I wonder it it starts with
       | time.sleep"
       | 
       | It was a pretty safe guess, though, the number of bugs related to
       | this is pretty epic.
        
       | Jamie9912 wrote:
       | Discord API is guilty of one of these very examples, they send a
       | retry-after header on 429 responses, but the thing is.. is it in
       | Bananas? Apples? Elephants?
        
         | timando wrote:
         | The retry-after header is documented as being in seconds (or a
         | date). https://httpwg.org/specs/rfc7231.html#header.retry-after
        
           | [deleted]
        
           | Jamie9912 wrote:
           | Funny because Discord implements it as milliseconds
        
         | ruuda wrote:
         | Unfortunately it's part of http. One thing you can do is to
         | send both the standard Retry-After header for tools that rely
         | on it, and a nonstandard but unambiguous Retry-After-Seconds.
         | That makes responses self-documenting. (One downside is that
         | you now have two numbers, and if you introduce a bug that makes
         | them different, it will be more confusing.)
        
       | wackro wrote:
       | Somewhat unrelated, the typography and use of color on this
       | article are sublime. No cookie popup either. What a joy.
        
       | justinhj wrote:
       | Passing the time unit as a second parameter is used a lot in Java
       | APIs and seems to work well
        
         | qw wrote:
         | Java's Duration is also useful for time units
         | void foo(Duration duration);              var result =
         | foo(Duration.ofHours(2));
         | 
         | You can also do simple calculations easily
         | var bar = Duration.ofHours(2).plusMinutes(30);
        
       | [deleted]
        
       | yummybear wrote:
       | I can understand the reasoning, in this specific case. But having
       | every function designating their unit is a new hungarian
       | notation. Imagine working with:
       | 
       | setSpeedInKilometersPerSecond vs. setSpeed
       | 
       | I'd rather have it baked into the language ala CSS ("100ms").
        
         | [deleted]
        
         | berkes wrote:
         | First, I'd say that you probably want to invest in your IDE or
         | editor.
         | 
         | But more important: there's middleground. What about
         | setSpeedMmps() if setSpeedInMillimeterPerSecond is too noisy.
         | 
         | My ROT is that the unit or type designation schould not
         | overshout the most important info. Which, in case of
         | setSpeedInMillimeterPerSecond is arguably, indeed the case. But
         | the solution is almost never binary, but a more succint
         | version. Everyone understands km, mm, sec, hr (though the win
         | with such is silly) px and so on.
        
         | Mazzen wrote:
         | You are missing one crucial element here:
         | `setSpeed(meterPerSecond: float)`
        
         | kuu wrote:
         | Do they charge you by written bytes? I really don't see the
         | problem with larger function names...
        
           | OskarS wrote:
           | "It's annoying" is a pretty good reason. If you don't mind
           | function names like that, go become a Java Enterprise
           | programmer, see how you like it after a few years.
           | 
           | In addition: it's the wrong solution to the problem. The
           | units shouldn't be baked in to the function definition, just
           | the type of quantity. You should be able to do both:
           | setSpeed(10 m/s)
           | 
           | and                   setSpeed(45 km/h)
           | 
           | Which you can do in many languages. In fact, time functions
           | in C++ work exactly like this. If you want to suspend a
           | thread for 10 seconds you do
           | std::this_thread::sleep_for(10s);
           | 
           | but if you want to suspend it for 5 milliseconds, you do
           | std::this_thread::sleep_for(5ms);
           | 
           | And if you just supply a unitless number, it's a compiler
           | error.
        
         | tirpen wrote:
         | Are you coding without any form of auto completion?
        
           | qayxc wrote:
           | As silly as this may sound, you may run into issues with
           | certain linters or formatting tools in some languages.
           | 
           | A prominent example is PEP8 in Python, which suggests a line
           | length limit of 79 characters (though 80-100 chars are
           | considered to be "OK" as well). Long variable or function
           | names can lead to distracting "forced" line breaks in such
           | scenarios.
        
       | cute_boi wrote:
       | Rust got it correct imo.
        
       | foobarthrow2 wrote:
        
       | cynik_ wrote:
       | I wrote about this a long time ago too:
       | https://explog.in/notes/units.html. Units are critical,
       | particularly when crossing language/engineer boundaries.
        
       | btown wrote:
       | Along these lines: if you are designing an API for pricing data
       | or fintech and think "let's send things in integer cents of the
       | currency so there aren't any rounding errors" - setting aside
       | that there are many situations where this is not appropriate, if
       | you do still want to do this, for the love of Pete please name
       | your variables and attributes with `_cents` in the names. No
       | exceptions. It is the biggest unit-related footgun imaginable,
       | and since it's not a "unit" technically, it's easy to overlook.
        
         | Archelaos wrote:
         | As we all know, naming things is so difficult.
         | 
         | Most currencies do not have "Cent" as a base unit. And there
         | are currencies without a smaller base unit, most notably
         | japanese Yen.
         | 
         | The problem is, that there exists no established currency
         | neutral name to distinguish between the two possible units that
         | coincide in such cases as Yen.
         | 
         | I was thinking about the following:                 class
         | AmountOfMoney         property int FinerAmount         property
         | decimal CoarserAmount
         | 
         | In the case of Yen (FinerAmount == CoarserAmount) is always
         | true.
         | 
         | Any suggestions for better wordings?
        
           | gpderetta wrote:
           | Splitting the integer and the decimal part is always annoying
           | because now you have to deal with non-normalized quantities.
           | An option is to just use a custom float type:
           | class AmountOfMoney         int mantissa         int exponent
           | # base 10
        
             | Archelaos wrote:
             | This is a missunderstanding.
             | 
             | If we have for example USD 10.42, the values in my
             | implementation are:                 FinerAmount = 1042
             | CoarserAmount = 10.42
             | 
             | The profile of the class was abbreviated. Of course, we
             | also need a currency property for the general case:
             | Currency = USDollar
             | 
             | The definition of the class for the currency in pseudo-
             | code:                 class Iso4217CurrencyCode
             | int NumericCode         string AlphabeticCode          int
             | DecimalPlaces                   static USDollar = new
             | Iso4217CurrencyCode(840, "USD", 2);       static Yen = new
             | Iso4217CurrencyCode(392, "JPY", 0);
             | 
             | The constructor for the amount of money only uses
             | FinerAmount, and CoarserAmount is calculated:
             | CoarserAmount => Convert.ToDecimal(FinerAmount /
             | Math.Pow(10, Currency.DecimalPlaces));
             | 
             | So                 foo = AmountOfMoney(FinerAmount: 1042,
             | Currency: USDollar);
             | 
             | sets foo.CoarserAmount automatically to 10.42.
             | 
             | But                 bar = AmountOfMoney(FinerAmount: 1042,
             | Currency: Yen);
             | 
             | sets bar.CoarserAmount automatically to 1042.
        
         | arpa wrote:
         | Assuming all currencies have 2 decimal units and subunits have
         | 1:100 ratio is another major footgun:
         | https://en.m.wikipedia.org/wiki/ISO_4217
        
           | btown wrote:
           | Absolutely agreed! And a more nuanced approach is what Stripe
           | does, which is to take the "zero-decimal-currency" as the
           | unit of record, be that USD cents or the non-subdivisible
           | JPY. https://stripe.com/docs/currencies#zero-decimal
           | 
           | But in that case, and _especially_ in that case, in any
           | system that might interact with, say, a UI where a field is
           | in decimal USD, Stripe needs to be careful about which things
           | are price_decimal and price_zerodecimal. Unless you have a
           | near-religious fervor that all variables not annotated with
           | _decimal are assumed to be _zerodecimal, in such a situation
           | one might go so far as to auto-reject any PR that does not
           | suffix all variables explicitly. Because the alternative is
           | hard-to-detect 100x-off bugs that occur when battle-tested
           | systems /libraries are reused in different contexts.
        
       | lowbloodsugar wrote:
       | Naming the method sleepMillis or sleepSeconds would help too.
        
         | nerdwaller wrote:
         | In my opinion that's too specific as you'd need a dozen methods
         | just to accomplish the common needs. Why not use a type as the
         | argument that's explicit and meets even more use cases? Meaning
         | instead of accepting an int just accept a `timedelta` in python
         | or a `time.Duration` in go, or `2.seconds` (I don't recall the
         | type) in rails?
        
       | snicker7 wrote:
       | Julia supports zero-overhead units:
       | 
       | https://github.com/PainterQubits/Unitful.jl
        
       | nraynaud wrote:
       | I recently worked on some disk file formats (.vmdk, .vhd), and I
       | always put the units in the name, because I'm always switching
       | byte, sectors, blocks. Same for addresses, is it a LBA on the
       | virtual disk, or an offset in the disk image file.
        
       | dathinab wrote:
       | An often better solution is to have a type which is not an
       | integer/string as input and have various ways to convert from/to
       | integers in a unit showing way.
       | 
       | Types like e.g. Duration (for e.g. sleep), Instance (for
       | calculating time passed based on monotonic timestamps), Distance
       | etc.
       | 
       | Through at the same time in static typed languages being generic
       | over the unit is often unnecessarily and hinders productivity
       | (e.g. Duration<TimeUnit> with types Duration<Seconds>,
       | Duration<Hours>) similar having unit types (e.g. passing
       | instances of Seconds, Hours to sleep) is also often not necessary
       | and more harmful then good. (Exceptions exists, where you e.g.
       | need to have where high precision and range while at the same
       | time need to keep storage constraints as small as possible while
       | also juggling units, like some scientific or embedded
       | applications).
        
       | jillesvangurp wrote:
       | Java and Kotlin have a nice Duration class. So in Kotlin you can
       | do                 delay(duration = Duration.ofMinutes(minutes =
       | 1))
       | 
       | which is equivalent to                 delay(timeMillis = 60_000)
       | 
       | Using the optional argument names here for clarity; you don't
       | have to of course.
       | 
       | Sticking with the JVM, a frequent source of confusion is the
       | epoch. Is it in millis or in seconds? With 32 bit integers that
       | has to be seconds (which will set you up for the year 2038
       | problem). However, Java always used 64 bit longs for tracking the
       | epoch in milliseconds instead even before the year 2000 problem
       | was still a thing. Knowing which you are dealing with is kind of
       | relevant in a lot of places; especially when interfacing with
       | code or APIs written in other languages with more 32 bit legacy.
       | 
       | Things like network timeouts are usually in milliseconds. But how
       | do you know this for sure? Specifying, them in seconds means that
       | there's less risk of forgetting a 0 or something like that. So,
       | using seconds is pretty common too. You can't just blindly assume
       | one or the other. Even if you use the Duration class above, you'd
       | still want to put the magic number it takes as a parameter in
       | some configuration property or constant. Those need good names
       | too and they should include the unit.
        
         | neop1x wrote:
         | Go has time.Duration type as well and works like this:
         | 
         | time.Sleep(10 * time.Millisecond)
        
         | zzbzq wrote:
         | The Duration.ofMinutes thing doesn't address the exact same
         | problem. Anyone can put the units on the "right side". You
         | don't even need a fancy "Duration.ofMinutes" helper function.
         | Clarity-wise that's not different than just putting a comment
         | saying how long it is and what units. The problem in the
         | article is getting the units on the "left side," which, yes,
         | you have to put the units in the name of the function.
        
           | renewiltord wrote:
           | Ah no. The function accepts a `Duration` type which could be
           | precisely 1 m 23 s 14 ms 10 us 8 ns. And so you don't need
           | `delay_ms` vs. `delay_ns` or anything because the type
           | encodes the precise duration. If you passed a nanosecond
           | `Duration` into `delay` it will delay ns, if you pass a
           | millisecond `Duration` it will delay ms.
        
           | macintux wrote:
           | You have to enforce the units within the function, but that's
           | not the same as putting them in the name of the function.
           | 
           | For example, in Erlang, the sleep function could/should have
           | been written to take named tuples: `timer:sleep({seconds,
           | 3})`
        
       | cbsmith wrote:
       | ...and so the tradition of loading up variable names with meta
       | information that should really be in the type system is passed
       | down from Hungarian notation to present day...
       | 
       | It's funny how the article talks about using the type system, but
       | the title does not.
        
       | runald wrote:
       | This usually bites me when it see a function that takes a
       | parameter named angle. I usually have to read the docs or inline
       | comment to know if it's in radians or degrees. At worst case, I
       | have to go to read the implementation to figure it out.
        
       | SideburnsOfDoom wrote:
       | My strong recommendation at work is: _do not_ use configuration
       | values such as "int dataCacheTimeMins" as these are prone to
       | error, inflexible (cannot represent 2 mins 30 seconds) and not
       | used consistently (will be mixed in with "int
       | dataRequestTimeoutSeconds" and "int someOtherTimeMillis" and
       | values named _without_ explicit units).
       | 
       | Instead always use "TimeSpan dataCacheTime" as this is more
       | flexible: can hold values from sub-millisecond up to multiple
       | days, and is easier to use with framework methods that will also
       | expect this type.
       | 
       | In other words, use the appropriate type instead of putting the
       | duration unit name in the var.
        
       | mellowagain wrote:
        
       | stjohnswarts wrote:
       | Or just document it. And the programmer should read documentation
       | for the method. time.sleep() docs tells you exactly what units it
       | uses.
        
       | ad-astra wrote:
       | Agreed, always one of my peeves.
        
       | mannykannot wrote:
       | When dealing with vectors, it is also important to establish your
       | frame of reference. Sometimes, though by no means always, there
       | is a well-established convention. When it is not, however, it can
       | get verbose to encode into identifiers. It can also be tedious,
       | as no-one needs to be reminded of it every time they read an
       | expression. In these cases, documentation is the best choice.
        
       | shikoba wrote:
       | Or, except if you need absolute precision, you wrap all those
       | primitives in a function that uses SI. So seconds for your sleep
       | wrapper.
        
       | meadsteve wrote:
       | I ended up building a library for elixir a few years back for
       | this kind of thing: https://github.com/meadsteve/unit_fun.
        
       | WatchDog wrote:
       | Or use an IDE? Here[0] is a screenshot of the Java example in
       | idea, not only does it show an inlayed parameter name hint, but
       | simply mousing over the method will show you the documentation.
       | 
       | [0]: https://i.imgur.com/8UcEO5N.png
        
         | gregmac wrote:
         | This doesn't work looking at a PR.
         | 
         | It also doesn't make a unit error stick out, as you have to
         | take the time to specifically hover to check. What I mean by
         | this is consider you've opened a mature code base and are
         | browsing around, and scroll past:                   timeout =
         | 60000;
         | 
         | I'd assume this is milliseconds, and whether I check would
         | depend on what I'm doing and probably also my mood.
         | 
         | Whereas if I see:                   timeoutSeconds = 60000;
         | 
         | It'll draw my attention and no matter what I'm doing I'll
         | either open a bug or just fix it.
        
         | wyager wrote:
         | Programs should be comprehensible as text, without machine
         | assistance.
        
       | unnouinceput wrote:
       | Eh, it seems the author never worked for a big organization and
       | when it finally did, it has a pet peeve.
       | 
       | Lemme tell you, every single organization that respect itself, it
       | will tell you, during code review, that you do not use magic
       | numbers in code. It's a red flag, so his "Do this:
       | frobnicate(timeout_seconds=300)" will actually fail the code
       | review.
       | 
       | Here is what you would do instead. Declare a constant in some
       | constants only unit, with explanation what it does and then use
       | that constant, like this:
       | 
       | //constant unit
       | 
       | const TIMEOUT_SECONDS = 300;//bla bla why this is 300 seconds,
       | usually from client requirement
       | 
       | //code unit
       | 
       | frobnicate(TIMEOUT_SECONDS);
        
         | gpderetta wrote:
         | But that still using a magic number, so obviously you should do
         | something like this:                  const TIMEOUT_SECONDS =
         | ONE * HUNDREDS;
         | 
         | The definition of ONE and HUNDREDS is left as an exercise.
         | 
         | Snark aside, the rule zero of all coding conventions is that
         | they should not be applied if they do not make sense in a
         | specific case.
        
           | unnouinceput wrote:
           | The "bla bla" explanation will suffice. Usually will include
           | a link to documentation, no need to further split the hair
        
         | aembleton wrote:
         | In this case, the units are in the variable name. I think that
         | was what the author was arguing for.
        
       | amai wrote:
       | Is there a programming language that supports units (and
       | calculation with units) out of the box?
        
       | emmelaich wrote:
       | Worth mentioning Frink.
       | 
       | > _Frink is a practical calculating tool and programming language
       | designed to make physical calculations simple, to help ensure
       | that answers come out right, and to make a tool that 's really
       | useful in the real world. It tracks units of measure (feet,
       | meters, kilograms, watts, etc.) through all calculations.._
       | 
       | https://frinklang.org/
        
         | dkbrk wrote:
         | Frink's units definition file is a great read:
         | https://futureboy.us/frinkdata/units.txt
         | 
         | I use Frink very regularly as a calculator. I've got a
         | keybinding in emacs to bring it up in comint-mode, which works
         | very well.
         | 
         | It's also a general-purpose programming language, at least in
         | theory. I actually tried using it for that purpose once, with I
         | think a few thousand lines of Frink code in total. It was not a
         | pleasant experience. It's fine if you want to write a short
         | script that's dimensionally aware, but for modelling of a
         | complex physical system there are much better tools, such as
         | Modelica.
        
           | SkeuomorphicBee wrote:
           | A really great read. I found particularly interesting the
           | long comment about the Hertz inconsistency, I had no idea the
           | S.I. Hertz, when applied to circular motion, was not a full
           | circle per second.
        
       | asiachick wrote:
       | There's a good old article about this from Joel Spolsky
       | 
       | https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...
       | 
       | It also makes the distinction between "apps hungarian" (good,
       | unit-types, eg: meters, seconds) and "system hungarian" (bad,
       | storage-types: float, int)
       | 
       | Sadly I've never worked on a codebase that follows this.
        
       | charcircuit wrote:
       | Meanwhile in Java this is handled by the IDE. The IDE will insert
       | the variable name since you are passing in just a number.
       | Thread.sleep(millis: 300)
        
         | xigoi wrote:
         | I don't think a language should require an IDE to be usable.
        
       | sleepyfran wrote:
       | This is one of the reasons why I love F#, baked in support for
       | units of measures. So instead of having to rename the function to
       | include the unit I can just declare it to take the type
       | `int<second>` and the compiler will complain if you try to pass
       | an `int` or an `int<minute>` unless you declare an explicit
       | conversion between the units.
        
       | connicpu wrote:
       | Sometimes the verbosity annoys me a little while writing it, but
       | I do think Rust made the right decision making you write code
       | like the following to use the standard sleep function.
       | std::thread::sleep(Duration::from_millis(300));
        
         | onox wrote:
         | In Ada you can do something similar:                   delay
         | 0.3;
         | 
         | Or with package Ada.Real_Time:                   delay
         | To_Duration (Milliseconds (300));
         | 
         | Or use `delay until`:                   delay until Clock +
         | Milliseconds (300);
         | 
         | `delay until` is useful in loops because `delay` sleeps _at
         | least_ the given duration, so you get drift. (You call Clock
         | only once and store it in a variable before the loop and then
         | update it adding the time span each iteration)
        
           | gpderetta wrote:
           | In fact std::thread::sleep doesn't exist. There's sleep_for
           | and sleep_until. Time deltas and time points are incompatible
           | at the type level, so you have to do:                  std::t
           | his_thread::sleep_until(std::chrono::system_clock::now() +
           | 300ms)
           | 
           | That's true for all functions that take timeouts (At least
           | since C++11).
           | 
           | edit: s/thread/this_thread/
        
             | eMSF wrote:
             | GP's snippet was in Rust (not that I know if it's valid
             | Rust code).
             | 
             | However, in C++ std::thread is a class and it does not have
             | a static member function sleep_until. (However,
             | std::this_thread, which is a namespace, does have such a
             | function).
        
               | gpderetta wrote:
               | D'oh! Thanks for the correction! Rust using std:: for its
               | standard library does make some code snippets ambiguous!
        
               | eMSF wrote:
               | Yeah, I agree. :-)
        
       | Ensorceled wrote:
       | I regularly program in Go and Python.
       | 
       | When I hover over time.sleep(delay) in my Python IDE the detailed
       | pop up shows me that this sleeps for delay seconds and that delay
       | is an int.
       | 
       | When I hover over time.Sleep(wait) in my Go IDE, the popup shows
       | me that time.Sleep takes a time.Duration.
       | 
       | Please get better tools and stay the heck away from both my
       | languages and coding style guidelines.
        
         | Lochleg wrote:
         | In Golang, I've seen time.Sleep(2 * time.Second). That's pretty
         | explicit, so, it seems someone carried the whole concept
         | forward.
        
       | sleepydog wrote:
       | This is not exactly the same thing, but for the love of god, if
       | you have a monitoring or logging product, make the date and time
       | zone visible wherever time is displayed. I cannot tell you how
       | many times I've been sent screenshots of graphs, showing some
       | catastrophic scenario at, say, 08:43, with no idea of what time
       | zone the graphs are using, or what day the graph is showing.
        
         | twistedpair wrote:
         | If it was a Google product, it's implicitly Pacific Standard
         | Time.
        
         | 10000truths wrote:
         | I prefer the use of Unix timestamps. Easier to filter with
         | standard Unix tools, and if I really need formatted date+time
         | in my output, I can always use awk.
        
           | simion314 wrote:
           | I don like it, say I open a database table and search for
           | some events , then look at the created_at column and see a
           | timestamp, so now I need to copy paste timestamps into a
           | webpage and convert it to human readable time to then notice
           | is 5 years old and not what i am looking for.
           | 
           | What are you doing in this case?(in case you worked with
           | database logs), export to csv and then do it with unix tools?
        
             | 8n4vidtmkvmk wrote:
             | depending on the sql dialect, you can convert it in sql. or
             | even add a virtual column with the conversion for your
             | convenience
        
           | berkes wrote:
           | I used to prefer unix timestamps too. But I Saw The Light.
           | 
           | For one: those standard Unix tools can convert from date/time
           | values to timestamps just as easy. Arguably easier.
           | 
           | And a timestamp is merely an Int, so many languages,
           | databases, APIs and so on, lack ergonomic methods to convert
           | timestamps to datetimes. But have easy ways to do the
           | reverse. It's almost always easier to convert dates, times or
           | datetimes to timestamp ints (or floats) than to convert an
           | int or float to a date, datetime or time.
           | 
           | A timestamp.toString() is unfamiliar to humans, a
           | datetime.toString() is not. The list of small benefits in
           | favor of actual date or time types just goes on.
        
         | ruuda wrote:
         | Yeah, this is also happens in code. The solutions are the same,
         | either use a type that is unambiguous (`timestamptz` in
         | Postgres, `datetime` in Python with `.tzinfo is not None`,
         | `DateTimeOffset` in .NET, `UTCTime` in Haskell etc.), or if you
         | _have_ to use naive datetimes, put the time zone in the name
         | and call it `datetime_utc`.
        
         | kristopolous wrote:
         | make everything UTC, people. It'll make your life way easier.
         | Try it out.
        
           | Too wrote:
           | Internally yes, this is a no brainer. However in log files
           | that are often read directly by humans, who want to see
           | things in local time, it can become a balance and you might
           | need to fight some admins for it. A proper structural logging
           | system solves this, but log files on disk and other ad-hoc
           | diy logs is still extremely common to see.
        
             | gpderetta wrote:
             | Especially in log files I want to see UTC. When you have
             | servers all around the world, I do not want to figure out
             | what timezone was the specific server running in nor I want
             | to convert between timezones when comparing logs of
             | different servers.
        
             | guipsp wrote:
             | Just live in GMT+0. Easy!
        
               | alephnil wrote:
               | I have sometimes put my computer in the Iceland time zone
               | for that reason when using dual boot with Linux, since
               | Linux prefer to run UTC on the clock, and the Iceland
               | time zone is UTC+0 with no daylight saving time. Making
               | windows believe it is in Iceland make sure it does not
               | mess up the clock. Though it is possible to set windows
               | to UTC too with the same effect.
        
             | barrkel wrote:
             | On-disk logs should use ISO-8601 in UTC, ideally first
             | thing on the line.
             | 
             | That way you can merge them from different sources and sort
             | them to help figure out interactions and causality. There
             | might be clock drift from different sources but that's a
             | much smaller problem than trying to eyeball multiple
             | different logs concurrently, or write ad-hoc scripts to
             | enable merging.
        
               | Too wrote:
               | For pure servers, what you say is easy and yes, almost
               | exclusively, the preferred option. The tricky situations
               | usually occur in CI, where you script together a lot of
               | weird tools, most of them originally designed to be run
               | by hands on developers workstation, where they want to
               | see local timestamps and never had time to implement log
               | config. Some days you can consider yourself lucky if the
               | log files have any timestamps at all.
        
           | EsotericAlgo wrote:
           | One especially frustrating version of this is a log or the
           | like reporting a time as UTC but it's not. So close.
        
           | BurningFrog wrote:
           | This is good advice, but ONLY for timestamps.
           | 
           | When people try to apply this to other time related info,
           | it's always a disaster.
        
           | AYBABTME wrote:
           | Still need the timezone in the timestamp, UTC or not.
        
           | makeitdouble wrote:
           | Only if literally _everything_ is UTC.
           | 
           | If you can't go that far and still need local time zones in
           | some specific part, just embrace your fate and keep and
           | display timezones everywhere, even when it's UTC.
           | 
           | TBH, I've never seen an organization that could 100% move
           | everything to UTC. Especially with countries following DST
           | and other shenanigans, and you want to quickly be able to
           | compare events at the same local time.
        
             | kristopolous wrote:
             | Use timezones as an interface accommodation and not a
             | storage format.
             | 
             | If you're going to do it in storage, keep it outside the
             | ISO/8601 string. Chronology is the most important thing to
             | get right. Locality comes after
        
       | josephg wrote:
       | One more tip: If you're ever designing an API like this, instead
       | of:
       | 
       | time.sleep(300)
       | 
       | Put your units in the method name:
       | 
       | time.sleep_seconds(300)
       | 
       | Likewise, if you're making a .length() method where the units are
       | at all ambiguous (like the length of a string), name your units.
       | Bad: str.len(). Good: str.len_chars() / str.len_utf8_bytes().
       | (I'm looking at you, Rust!)
        
         | rahimiali wrote:
         | time.sleep_seconds is appealing, but this approach doesn't work
         | when a function takes additional arguments. for example, if
         | your function is
         | poll_file_descriptors(read_descriptors, write_desciptors,
         | timeout_in_seconds)
         | 
         | it would be awkward to change the name of the function just
         | because on of the arguments happens to refer to time.
        
           | agloeregrets wrote:
           | This is where Objective C brings subtle magic with mid-
           | function name arguments. Sure it's crazy verbose but insanely
           | readable: printFile(file:
           | File)withDelayInSeconds(delaySeconds:
           | int)andPrintColor(PrintColor: UIColor)
        
             | joshuamorton wrote:
             | This is just the builder pattern but worse?
        
               | josephg wrote:
               | It's actually just an obj-c method call. There's no
               | temporary builder object (or associated class) that needs
               | to be implemented and instantiated like you'd need for a
               | builder.
        
           | joshvm wrote:
           | I would always make a local variable for things like this, to
           | avoid magic numbers (especially if a function signature has
           | several numeric arguments). Then you can explicitly put the
           | units in the variable name, e.g. _duration_s = 300_ and pass
           | that. It 's fine if the signature tells you the units, but it
           | doesn't help anyone reading the code if you have
           | _poll_file_descriptors(read_descriptors, write_desciptors,
           | 300)_.
        
             | [deleted]
        
             | mulmen wrote:
             | But how do you know the unit to use in the variable?
        
               | Karellen wrote:
               | You have to read the documentation. But you need to do
               | that in order to be able to use the API properly anyway.
               | 
               | The point the article is making is not about making it
               | easier to write a line of code, but about making it
               | easier to _read_ a line of code. Given that most lines of
               | code are read many more times than they are written, this
               | is a good thing to focus on.
               | 
               | "Programs must be written for people to read, and only
               | incidentally for machines to execute."
               | 
               | -- Abel and Sussman, _Structure and Interpretation of
               | Computer Programs_ , 1984
        
               | josephg wrote:
               | Being forced to read the documentation carefully every
               | time you call the method is really bad UX though. And the
               | approach in the article (let ms = 5; sleep(ms);) can be
               | _wrong_. Maybe the method is actually taking microseconds
               | not milliseconds and this causes a bug. I can also
               | imagine linters (or other humans) fighting this style,
               | since it's longer, and something you have to actively do
               | every time you call the method.
               | 
               | Putting the units in the method name (when you can) fixes
               | all of this. Sleep_milliseconds(5) is impossible to
               | misuse or leave undocumented.
        
         | xyzzy_plugh wrote:
         | The solution to this is as old as salt:                 typedef
         | int seconds;
         | 
         | and                 time.sleep(seconds duration);
        
           | ameliaquining wrote:
           | That doesn't really seem better, because the fact that the
           | unit is seconds is only obvious if you happen to be looking
           | at the function signature in the header or somesuch. This is
           | because C typedefs are type aliases, not newtypes. If seconds
           | were instead a struct with a single int field, or something
           | like that, then that would help a little. To really solve
           | this problem, you need information hiding, which C doesn't
           | have except through questionable hacks.
        
         | adtac wrote:
         | I'm sorry, but if a language forced me to write
         | str.len_utf8_bytes() every time I wanted the length of a
         | string, I'd just stop using that language.
        
           | mgdlbp wrote:
           | Though it might encourage some to consider
           | str.len_extended_grapheme_clusters()
        
           | jeffparsons wrote:
           | Out of interest, which length did you want?
        
             | [deleted]
        
             | jhasse wrote:
             | Number of characters
        
               | int_19h wrote:
               | What's a "character"? A codepoint? A glyph? Is "fi" a
               | single character? How about "ss"? "OU"? "IJ"?
               | 
               | When programmers get answers to these questions wrong,
               | the code that they write ends up being broken for someone
               | out there. And they do get it wrong if their native
               | culture instills a wrong kind of "common sense" about
               | scripts. Which is precisely why we need _more_ stuff like
               | str.len_utf8_bytes() - because it forces the person
               | writing it to consider their assumptions.
        
               | josephg wrote:
               | Yep. I think about this stuff a lot and I still mess this
               | up all the time. I've come to realise that string.length
               | in javascript is a footgun. Basically every time I use
               | it, my code is wrong when I test with non-ascii
               | characters.
               | 
               | I've spent the last decade writing javascript and I've
               | never once actually cared to know what half the UTF16
               | byte length of a string is.
               | 
               | The only legitimate uses are internal in javascript
               | (since other parts of JS make that quantity meaningful).
               | Like using it in slice() or iterating - though for the
               | latter we now have Unicode string iteration anyway.
        
       | egberts1 wrote:
       | Haven't had a mistype or a case of confusion with using Ada
       | language to date.
        
       | james2doyle wrote:
       | If you're using Javascript or Typescript, there is an Eslint rule
       | called "no-magic-numbers" which enforces a rule where numbers are
       | required to be assigned to a variable:
       | https://eslint.org/docs/rules/no-magic-numbers
       | 
       | You can set ones to ignore, a minimum value for the rule to
       | apply, or require the variable to be a const.
        
         | pojzon wrote:
         | This is more about units.
         | 
         | int length = 5
         | 
         | Is quite different than:
         | 
         | int lenght_in_meters = 5
        
         | hinkley wrote:
         | I'm a fan of the middle ground here where you limit magic
         | numbers to known constants and arithmetic. This means some
         | constants don't have magic numbers, but also some inline uses
         | don't necessarily have constants.
         | 
         | For instance 7, 24, 60, 1000 allowed in defining units of time,
         | and any other intervals are defined as 5 minutes = 5 x 60 x
         | 1000.
         | 
         | Still, I've had plenty of experiences with 'is this unit in
         | seconds or milliseconds'. As I recall, Gilad Bracha at one
         | point looked at attaching units to numbers but I think he got
         | wrapped around the axle on automatic conversions - if you
         | divide meters by seconds, this is a meters/second unit. But do
         | you convert to newtons or joules automatically too?
        
           | ttymck wrote:
           | 60 minutes or 60 seconds?
        
       | dragonwriter wrote:
       | Units in values > units in names.
        
       | bmitc wrote:
       | Forever and always. :) If I see a numerical value that has units
       | but doesn't in the name, I add it.
       | 
       | Also, I love F#'s units of measure.
        
       | eyelidlessness wrote:
       | I prefer to do this with types versus variable/parameter names
       | _where possible_ , but yep runtime names otherwise. It annoys
       | some people but the thing is almost always either autosuggested
       | or showing up in your editor as you type as docs, so... to quote
       | Mitch Hedberg, "we apologize for the convenience".
        
       | throwaway81523 wrote:
       | I've heard of some Ada coding standards that require this in all
       | variable names. It must have made the code awfully clumsy, but as
       | the examples in OP show, it can be made nice. So the general
       | advice is good. I'm slightly disappointed that the Haskell
       | library didn't use a newtype, e.g. threadDelay (Microseconds
       | 300).
        
         | p_l wrote:
         | "Native" Ada way would be to declare units in types and require
         | explicit casts (also, you can prevent casting to unsupported
         | types, so no retrieving Int64 from hypothetical
         | Duration_Nanoseconds
        
         | wyager wrote:
         | Haskell has a couple libraries that would be great here; either
         | the excellent time library, or the very powerful dimensional
         | library with full statically typed SI units. Of course for
         | something as core as threadDelay, a newtype is more appropriate
         | as you say.
        
           | throwaway81523 wrote:
           | Another approach (used somewhat by Python, at least for time
           | units) is use SI units or some other standard or convention,
           | and be willing to use floating point numbers for
           | measurements. That was considered bloat in the old days, but
           | reasonable general purpose computers these days almost always
           | have FPU hardware.
        
       | animsriv wrote:
       | I remember as a kid, my Physics teacher used to penalize us for
       | not writing the unit in the calculations. It seemed absurdly
       | archaic at that time, but it makes so much sense now.
        
       | logbiscuitswave wrote:
       | Fully agree with everything in this article. This is definitely a
       | code smell to me to see unitless sizes and intervals specified. I
       | know that whenever I'm doing a code review and I see some
       | property or variable name like "timeout" or "size" I will ask the
       | developer to change the name to make it clear what the unit is
       | trying to portray.
       | 
       | When possible, I also encourage the use of better types than
       | simple integer values, (like TimeSpan if .NET) as these further
       | reduce ambiguity and the potential for mistakes.
       | 
       | This is such a simple thing to find and fix but it definitely
       | helps in the long term.
        
         | bentcorner wrote:
         | I also agree but would offer a third suggestion - add the type
         | to the function name as well, so you see this line in code:
         | `timeoutSec(timeout)`. You can't enforce people to name the
         | parameter correctly, this means that anyone reading doesn't
         | have to go digging to know the parameter type. Also stuff like
         | `timeoutSec(timeoutMs)` stands out like a sore thumb.
        
       | ahelwer wrote:
       | I prefer using timedelta (or TimeSpan for the .NET crowd) but
       | I've run into a somewhat funny resulting problem: often these
       | time values are read in from a config file, so now people need to
       | know/remember the serialized time span format. Like what is
       | "00:50"? Is it fifty minutes? Seconds?
        
         | marcosdumay wrote:
         | That's why you use a constructor with the unity names, not the
         | conversion from a unityless string.
        
         | ruuda wrote:
         | You don't have to use the default serialization format. You can
         | have `timeout_seconds = <<int>>` or `timeout = <<int>>s` in
         | your config file, store it internally as timedelta, and convert
         | when you read the file.
        
           | ahelwer wrote:
           | Seems to negate the motivation for using a timespan datatype
           | in the first place.
        
         | SideburnsOfDoom wrote:
         | Sure, we got used to the format. I have a gist that among other
         | things lists all of the cases, including the harder ones such
         | as "10ms", or "3 days".
         | 
         | FWIW, in "TimeSpan for the .NET crowd", you would write
         | "00:00:50" for (zero hours, zero minutes and) fifty seconds.
         | Hours, minutes and seconds cases are easy now that we know the
         | format.
         | 
         | Yes, you can omit some of the zeros, but your comment above
         | makes the case that for clarity, you should not.
        
       | rolobio wrote:
       | In Python you can force the use of a parameter's name with *
       | def my_sleep(*, seconds: int):          pass
       | my_sleep(seconds=3)
       | 
       | This will force those who use your function to use the parameter
       | name. A sort of documentation I suppose.
        
         | Biganon wrote:
         | That's in the article...?
        
       | Closi wrote:
       | I used to work at a company with two database fields, speed_kmph.
       | 
       | The documentation read "speed_kmph - This field contains the
       | travelling speed in MILES PER HOUR - please do not be confused by
       | the name".
       | 
       | Woo, great job guys.
        
         | gpderetta wrote:
         | recently I was looking at some pcap parsing code which was
         | storing the timestamp field into a timeval structure (that
         | nominally has usec precision), but then treating it as
         | nanoseconds (as pcap supports both resolution). It made for
         | some very confusing reads!
        
         | bombcar wrote:
         | This is why it's dangerous to encode the unit in the variable,
         | because it will eventually change (we had code that was
         | measured in seconds and had to be changed to measure in 20/ths
         | of a second for more granularity, if the timer variable had
         | been named "timer_seconds" it would have had to be changed
         | everywhere.
        
           | andrewzah wrote:
           | Someone doing a half-assed refactor doesn't mean it's
           | "dangerous" to encode a unit in a variable or function.
           | 
           | I do agree that generally it's better to use something like a
           | struct that's more flexible, but doing that for every
           | function is also quite verbose. For some functions the time
           | requirement may never change as well.
        
           | hallway_monitor wrote:
           | In this specific case, it seems like creating a new property
           | with the new data in a new name would be the safest path
           | forward. Ensuring the unit are in both property names will
           | prevent confusion.
        
           | llbeansandrice wrote:
           | This sounds like a feature to me and modern IDEs make this
           | type of simple refactoring quite straight forward for most
           | languages.
        
           | RandallBrown wrote:
           | If you change the unit, I think the variable _should_ be
           | changed everywhere.
           | 
           | It's hard to know what assumptions code is making and by
           | forcing you to change the code everywhere (which should be
           | pretty easy in any modern IDE) you at least have a chance to
           | evaluate any issues that unit change could cause.
        
         | quickthrower2 wrote:
         | DB field names can be really hard to change. All those crystal
         | reports to update, and the sales managers pet access DB that
         | the hero set up for him that you don't know about.
        
           | tonyedgecombe wrote:
           | >DB field names can be really hard to change.
           | 
           | I find it really hard to accept any excuse for something like
           | that. It's why enterprise code is so sloppy, people doing the
           | most expedient thing rather than what is correct.
        
             | Closi wrote:
             | How do you write code so that it can accommodate DB field
             | name changes without breaking SQL reports / BI?
             | 
             | Might be easy if you own the whole codebase and all
             | reporting, but you are also going to break all those linked
             | BI reports that the analysis team has written.
        
               | Too wrote:
               | Breaking the report is a feature.
               | 
               | If you don't, it will assume kmph instead of mph and just
               | present the wrong data! But sure...those graphs still
               | look pretty...
        
               | im3w1l wrote:
               | Create a new column speed_mph. Create a trigger that
               | makes writes to either column gets written to both (make
               | sure to write it to avoid infinite recursion). Copy all
               | data from speed_kmph to speed_mph. Deprecate speed_kmph.
               | Change existing usages at your leisure. Delete
               | speed_kmph.
        
               | pojzon wrote:
               | Most often those reports are built on top of table views
               | and not direct table contents. If you have an abstraction
               | layer between its not hard to change whats under.
               | 
               | But that makes an assumption you didnt make any
               | shortcuts.
        
             | cle wrote:
             | What is "correct" is up for debate, and often depends on
             | cost tradeoffs. Sometimes this is the "correct" thing to
             | do, no matter how gross we think it is.
        
               | tonyedgecombe wrote:
               | Not often, what has always surprised me is how regularly
               | these sort of problems are self inflicted. A lot of
               | people will just do what is expedient regardless of what
               | the management position is.
        
         | jrodthree24 wrote:
         | It's even better when the documentation gets stale too. And now
         | this is in meters/second but the name implies km and docs
         | specify miles.
        
       | jakuboboza wrote:
       | This is a very valid argument. Go has this time.Second duration
       | type that is used often and it helps a lot understand things. But
       | things like Js/Pure Ruby have just raw numbers where you have to
       | either check docs or just remember that sleep takes miliseconds
       | or seconds etc.
       | 
       | It seems types are useful piece of information. Who would expect?
        
       | wiz21c wrote:
       | Julia seems to have some unit support (via package):
       | 
       | http://painterqubits.github.io/Unitful.jl/stable/
        
       | zeristor wrote:
       | I thought this was in reference to the HNews post from
       | WashingtonPost about the Eastern Antarctic being "70 degrees"
       | warmer.
       | 
       | https://news.ycombinator.com/item?id=30733387
        
       | timando wrote:
       | > And don't design your CLI accounting app like this: > show-
       | transactions --minimum-amount 32
       | 
       | I'd argue that it's fine if the accounting app is never going to
       | handle multiple currencies.
        
       | JaggerJo wrote:
       | F# has units of measure built into the language.
       | 
       | let time: float<s> = 0.1<s>
       | 
       | let length: float<m> = 10.0<m>
       | 
       | let speed: float<m/s> = length / time
        
       | AtNightWeCode wrote:
       | This is good scouting. In Java there is a naming convention.
       | In<metric>, like TTLInMillis. In C# you often use TimeSpans, like
       | TimeSpan.FromSeconds(123). However, I see this problem more and
       | more often for some reason.
        
       | sexy_panda wrote:
       | imho it's bad practise to not use SI units [0] by default.
       | 
       | Why would you want to enter a percentage of a minute?
       | 
       | [0] https://en.wikipedia.org/wiki/International_System_of_Units
        
       | fastball wrote:
       | Though you don't actually need to enforce keyword arguments, any
       | good IDE will give you the (positional) arg names if you
       | mouseover or w/e, so as long as the positional arg is named
       | `timeout_ms` instead of `timeout` it should still be fine.
        
         | anko wrote:
         | I think the problem is a bit more nuanced, but i don't have a
         | perfect answer.
         | 
         | This is fine but relying on an IDE for code reviews really
         | sucks. I'd much prefer to be able to do it on github. And it
         | sucks for any language which infers types :( Scala is in
         | particular awful for reviewing on github
        
         | rahimiali wrote:
         | IDE hints like this are useful when you're writing the code,
         | but not so useful when you're reviewing it in online code
         | review tools.
         | 
         | I wish code review tool could provide this hover functionality
         | too.
        
       | james2doyle wrote:
       | PHP mess detector has a rule for this called "Magic Number
       | Detector" (https://github.com/povils/phpmnd) which will cause an
       | error when it encounters numbers that violate the parameters you
       | set.
        
       | deanCommie wrote:
       | If you're passing around parameters, use a Duration class. Most
       | languages have one:
       | 
       | * https://docs.oracle.com/javase/8/docs/api/java/time/Duration...
       | * https://docs.microsoft.com/en-us/dotnet/api/system.timespan?...
       | * https://en.cppreference.com/w/cpp/chrono/duration
       | 
       | If you're putting something in a config file, as the blog says -
       | always put the unit in the key name.
        
       | FpUser wrote:
       | Ha. I've learned it decades ago. It is handled on a level of my
       | spinal chord.
       | 
       | Same thing with explicit memory allocation. If for whatever weird
       | reason I need to explicitly allocate RAM I first write
       | deallocation.
        
       | alexwennerberg wrote:
       | I think Go has a reasonable approach:
       | time.Sleep(1 * time.Second)
        
         | oatmeal_croc wrote:
         | Big fan of this.
        
         | Gwypaas wrote:
         | Go'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
         | 
         | > 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-affe...
         | 
         | > time: use monotonic clock to measure elapsed time
         | 
         | https://github.com/golang/go/issues/12914
        
         | jeroenhd wrote:
         | Rust 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 wrote:
           | Yeah, 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 wrote:
         | Or Ruby on Rails:                 sleep(5.seconds)
         | sleep(1.minute)       sleep(2.hours)
         | 
         | etc etc
        
         | 33degrees wrote:
         | In Ruby that would be                   sleep 3.seconds
         | 
         | Hard to to be more concise than that
        
           | inopinatus wrote:
           | Are we golfing? Because that's identical to
           | sleep 3
        
             | wyattpeak wrote:
             | Are we golfing? This whole discussion is about clarifying
             | units.
        
               | inopinatus wrote:
               | I must clarify, that was intended rhetorically, and in
               | the most self-serving fashion; I try never to miss a
               | golfing prompt
        
           | mfkp wrote:
           | Technically Ruby only accepts seconds. You're thinking of
           | ActiveSupport from Rails.
        
             | inopinatus wrote:
             | Here'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 wrote:
               | Not 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!?
        
               | inopinatus wrote:
               | Actually taken almost verbatim from the report
               | summarizing a real and subtle bug (distributed across
               | multiple files) in code written by definitely-not-
               | novices.
        
               | lloeki wrote:
               | > 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.
        
               | neurostimulant wrote:
               | I'm not really familiar to RoR. Is is due to Time.now
               | getting called twice and each returns slightly different
               | value?
        
               | inopinatus wrote:
               | Alas, no. It's because ActiveSupport's duration
               | arithmetic is not distributive under conversion.
               | 
               | The expression on the left hand side advances time (as a
               | domain object) by exactly a month, then converts the
               | result to integer unix time. The expression on the right
               | adds 26297461 to the current unix time.
               | 
               | The conversion becomes dangerously magical in the
               | presence of shared code that accepts both object and
               | integer representations of time & duration. A consumer
               | from one part of a system can inadvertently obtain
               | different results to another unless they use identical
               | calling conventions.
               | 
               | [1] this is 1/12 of the mean length of a gregorian year2
               | 
               | [2] 365.2425 days i.e. 31,556,952 seconds
        
               | neurostimulant wrote:
               | Oh wow. This is totally make sense when you think about
               | it, but something that'll never cross my mind when
               | casually checking the code. I guess this is why python's
               | timedelta doesn't have month unit as the length of a
               | month is highly context dependent.
        
               | [deleted]
        
               | ativzzz wrote:
               | I would just use `1.month.from_now` instead of the
               | additions anyway
        
               | inopinatus wrote:
               | That won't save you; 1.month.from_now is implemented by
               | addition.
        
         | 29athrowaway wrote:
         | I hope late millenials and generation Z rediscover types soon.
        
           | LAC-Tech wrote:
           | huh? 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.
        
             | p_l wrote:
             | Except Common Lisp is typed language (with more expressive
             | type system than most)
        
             | djbusby wrote:
             | Imma get my cane and hit you with Perl and PHP ;)
        
             | int_19h wrote:
             | And now millennials seem to be doing the same with JS.
             | _sigh_
        
         | chrismorgan wrote:
         | I'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.
        
           | crdrost wrote:
           | I mean in their defense I see almost nobody doing this
           | right... Like to do full SI you really need 7 rational
           | numbers, maybe a sort of inline "NaN" equivalent for when you
           | add things with incommensurate units... you might also want
           | display hints for preferred SI prefixes (might just be a
           | dedicated format type), and while you're at it you might as
           | well use a Decimal type instead of doubles, oh and probably
           | these numbers should have an uncertainty in them, so probably
           | you want a modular system where you can mixin units or mixin
           | uncertainty and you can start from a base of doubles or
           | decimals or, hell, you start experimenting with continued
           | fractions...Sigh. The real world is complicated.
           | 
           | Every implementation of units is secretly trying to be
           | Moment.js, basically.
        
             | account42 wrote:
             | C++11's std::duration manages just fine without that much
             | scope bloat. operator* for two durations is simpley not
             | defined so will lead to a compile error.
        
             | int_19h wrote:
             | All you need is a language that actually incorporates units
             | of measure into the type system - i.e. you can define units
             | orthogonal to types (including relationships between
             | units), and then you can specify both the unit and the
             | underlying numeric type in a declaration.
             | 
             | https://docs.microsoft.com/en-us/dotnet/fsharp/language-
             | refe...
             | 
             | This can also be pulled off with somewhat less pleasant
             | syntax on top of a sufficiently flexible parametrized type
             | system - e.g. C++ templates.
        
             | wnoise wrote:
             | And yet people actually do manage meaningful unit systems
             | that don't allow this.
        
             | tfigment wrote:
             | Company i worked for 20 years ago had commercial
             | engineering modelling program that did all physical types
             | correctly and did scaling for user but it was fairly unique
             | in scope and like you say almost all programming languages
             | fall short here and it had its own quirks.
        
           | maerF0x0 wrote:
           | my 2c, I think the issue is simply in the name collision of
           | units and the constants. (ie, "seconds" and time.Seconds) .
           | 
           | In reality most programming languages do not have units what
           | so ever (built into the language, maybe tacked on as a
           | library after the fact). They have int64s, a unitless value
           | that just keeps track of whole numbers of whatever it
           | semantically means to the developer. If we want to truly have
           | units in values then we either need 1st class language
           | support (including syntactical support) or a rich library
           | that doesnt just "put units in [symbols]". One could probably
           | make it happen with a type that keeps track of units
           | ```         type unitedVal struct {              denomerator
           | int64              numerator int64               denomUnits
           | string              numerUnits string         }
           | func (united *unitedVal) Multiply(by unitedVal) *unitedVal {
           | return &unitedVal{                numerator:
           | united.numerator*by.numerator,                denominator:
           | united.denominator*by.denominator,                denomUnits:
           | united.denomUnits + " * " + by.denomUnits,
           | numerUnits: united.numerUnits + " * " + by.numerUnits,
           | }         }         ```
           | 
           | and then filling out for all the other operations you want to
           | support.
        
           | svnpenn wrote:
           | All 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 wrote:
             | Just contrived examples, like gravity * t^2 to get distance
             | to fall and such, probably
        
             | bobbylarrybobby wrote:
             | What is correct is that duration +- duration = duration,
             | duration * scalar = duration, timestamp +- duration =
             | timestamp, timestamp - timestamp = duration, and anything
             | else doesn't compile.
        
               | Groxx wrote:
               | To 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)
        
               | chrismorgan wrote:
               | And it's not just that Go _allows_ that, but that that's
               | actually the _only_ general way of doing it, as Go only
               | allows duration * scalar in constant context (which is
               | admittedly all most people do with durations, which is
               | why I say it's still probably better than Go did it this
               | way, given their deliberately limited type system).
        
               | svnpenn wrote:
               | If you exponent time.Duration, that's a user error.
               | 
               | What you're suggesting would be like a compiler error for
               | multiplying two int64s
        
               | linkdd wrote:
               | What they're suggesting is that `time.Duration` should
               | not be an int64.                 1 second * 1 second = 1
               | second2       1 meter * 1 meter = 1 meter2       1 meter
               | / 1 second = 1 m/s
               | 
               | Those are not user errors, those are physical values. A
               | physical value is two things:                 - a scalar
               | (int64, float, ...)       - a unit (meter, second,
               | inches, ...)
               | 
               | If the type system of your programming language does not
               | allow you to define units, this should at least be a
               | structure with a scalar and an enum, and functions to
               | cast from one unit to another (if possible).
               | 
               | Working with units is a common thing in science.
        
               | skissane wrote:
               | > A physical value is two things:
               | 
               | I would argue it is actually three things: a scalar, a
               | unit, and an indication of error - which is at least
               | another scalar, but there are multiple ways of expressing
               | error, so it might require more than just a single scalar
               | (such as an interval and the probability the actual value
               | lies within that interval.)
               | 
               | > If the type system of your programming language does
               | not allow you to define units, this should at least be a
               | structure with a scalar and an enum
               | 
               | Ideally more than just an enum - Newton = kg*m*s^-2
               | (equivalently kg^1*m^1*s^-2) - which suggests a set of
               | pairs (unit and exponent).
        
               | linkdd wrote:
               | Yes, thank you for the precisions, this just make my
               | point stronger: int64/float are very ill-suited to
               | represent such values.
               | 
               | And it's especially true for time units.
               | 
               | For example, "how many seconds is one month?" does not
               | make sense, but "how many seconds is
               | january/february/march?" does make sense. The unit
               | "month" does not really exist, each calendar month is its
               | own unit.
               | 
               | And "february" is not even a "stable" unit because
               | sometimes it's 28 days, sometimes it's 29 days. Even a
               | minute can some rare times be 61 seconds.
               | 
               | This is why in physics, we use seconds multiplied by
               | powers of 10 and nothing else.
               | 
               | To my knowledge, there is not a single programming
               | language that differentiate a "scalar" and a "quantity"
               | (scalar, unit, error).
        
               | conradludgate wrote:
               | It should be fine to multiply two durations, but it
               | should not return the same time.Duration type
        
               | afiori wrote:
               | not being able to sum timestamps is a bit beyond the
               | scope of units, it is more of a vector vs point
               | distinction
        
             | int_19h wrote:
             | > All that, and yet I don't see a single example of what
             | would be "correct", or an example language that does it
             | better.
             | 
             | F#, Rust, C++?..
             | 
             | > First of all, who is multiplying time.Duration against
             | itself
             | 
             | Physicists do, every time they have to deal with
             | acceleration - m/s^2.
        
               | WinterMount223 wrote:
               | You are right however physicists do not multiply duration
               | x duration but time x time. Duration is discrete and time
               | is infinitesimal.
        
             | chrismorgan wrote:
             | Once you go beyond constants (which in practice means
             | literals, I think, but I'm not conversant enough in Go to
             | be confident), Go _requires_ that you multiply Duration by
             | Duration--you _can't_ multiply it with a scalar outside of
             | constants. In other words, as soon as a scalar multiple
             | becomes a parameter rather than a constant, you can't just
             | do `n * duration`, but have to do something more like
             | `Duration(n) * duration`, which is obviously physically
             | wrong for a system of units, because the unit should be
             | time _squared_ , not time.
             | 
             | As for languages doing it better, approximately every
             | single language that has strong static typing and uses
             | dedicated types for times does it better. Rust is the one
             | I'm most familiar with and comfortable with.
        
               | svnpenn wrote:
               | You seem to be confusing the Duration type with Duration
               | values. Yes, if you insist on using a typed value,
               | instead of an untyped constant, then that value needs to
               | be type Duration.
               | 
               | But Duration(1) is way different than time.Second.
               | honestly it just sounds like you don't know the language,
               | and aren't willing to learn it. Go is not Rust. Things
               | are different, that doesn't mean Go sucks.
        
             | thwarted wrote:
             | The provided example is pretty rough, and I'm sure it's
             | occurred in the wild. Sure, put the units in the variable
             | name, and it _encourages_ this kind of mistake, because
             | time.Duration is not  "seconds", it is a duration. The
             | variable name should match the API of time.Sleep, which
             | takes a duration. The variable should be named delay. A
             | variable named delaySecs is the same kind of maintenance
             | headache as a variable named "two_days_ago = 2.days.ago" in
             | ruby.
             | 
             | The variables used for accepting and parsing input are the
             | ones that should have units in them in this example.
             | Although if you need a delay specified, it's valuable to be
             | explicit and robust in the input and accept a string
             | time.ParseDuration understands. Then you don't have this
             | units problem in your variable naming at all, allows easier
             | input of wider ranges of values by the operator, and makes
             | input validation (if only a subset of durations are
             | allowed) more concise and consistent.
        
               | conradludgate wrote:
               | I've seen a lot of code at my last job in Go where all
               | duration variables included their units. It was amazingly
               | bad Go code (it was built in part of the projects PoC by
               | new Go devs) but it doesn't help that for the most part
               | it did work.
               | 
               | Time was honestly our biggest source of bugs by far.
               | Although adding time.Time ended up being more problematic
               | than durations which were mostly only constructed like
               | that in tests
        
             | tedunangst wrote:
             | One alternative is rust Duration, which makes you spell out
             | all your arithmetic operations. But this is exactly the
             | approach taken by go time.Time, so the part about the type
             | system being incapable or whatever is kinda misguided.
             | https://doc.rust-lang.org/std/time/struct.Duration.html
             | 
             | C++ chrono::duration allows arithmetic operations with more
             | sensible overloading.
             | https://en.cppreference.com/w/cpp/chrono/duration
        
             | xigoi wrote:
             | Nim does it correctly: https://nim-
             | lang.org/docs/times.html#%2A%2CDuration%2Cint64
        
         | qurm wrote:
         | Or Dart                   Future.delayed(const
         | Duration(seconds: 2)         Future.delayed(const
         | Duration(milliseconds: 2000)
        
         | devmunchies wrote:
         | That'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
        
         | cytzol wrote:
         | Like 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). 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]
        
           | eyelidlessness wrote:
           | This looks to me like the semantics are good but the
           | implementation details are broken. 1 * time.Second *
           | time.Second semantically reads to me as 1 second. If
           | time.Second is some numeric value, that's obviously wrong
           | _everwhere_ unless the type system reflects and enforces the
           | unit conversion.
        
             | linkdd wrote:
             | > 1 * time.Second * time.Second semantically reads to me as
             | 1 second.
             | 
             | Which is wrong, 1s * 1s = 1s2.
             | 
             | For example, the force of gravity is expressed in m/s2 and
             | describe an acceleration (m/s / s, aka a change of velocity
             | per time units, where velocity is a change of distance per
             | time units).
        
               | [deleted]
        
               | eyelidlessness wrote:
               | Okay so do I need to consult Relativity to program 1sec +
               | 2min?
        
               | mminer237 wrote:
               | You can just do `1 * time.Second + 2 * time.Minute` to do
               | that. Adding times works intuitively. It's multiplying
               | durations that gives you accelerations.
        
               | linkdd wrote:
               | Since 1min could be 61 seconds[1], yes?
               | 
               | But assuming your comment is not a joke. You probably
               | want to convert minutes to seconds in order to work with
               | the same units, then add the scalar parts together.
               | 
               | That's how you deal with different quantities: convert to
               | same unit, add values.
               | 
               | This is analog to fractions: 1/2 + 1/4 = 2/4 + 1/4 =
               | (2+1)/4 = 3/4.                 [1] -
               | https://en.wikipedia.org/wiki/Leap_second
        
               | eyelidlessness wrote:
               | In basic middle school math it's common to multiply
               | different units as a basic conversion mechanism.
               | Multiplying by the same unit is semantically equivalent
               | to "x times 1 is identity(x)", and other cross-unit
               | arithmetic implies conversion to ensure like units before
               | processing. A typed unit numeric system would imply that
               | to me. It would not imply I'm multiplying the units, but
               | rather the scalar value of the unit.
        
               | int_19h wrote:
               | What is the "scalar value of the unit"?
               | 
               | Units can be expressed in terms of other units, and you
               | can arbitrarily pick one unit as a base and then express
               | the rest in it. But the key word here is "arbitrarily".
               | 
               | If multiplying by the same unit yield the same unit, then
               | how did you compute area or volume in school?
        
               | linkdd wrote:
               | > In basic middle school math it's common to multiply
               | different units as a basic conversion mechanism
               | 
               | EDIT: Yes, you multiply the units `2m * 2s` : you first
               | multiply the units to get: `m.s`. This is what I say: you
               | convert everything to the same units before doing the
               | calculations.
               | 
               | > Multiplying by the same unit is semantically equivalent
               | to "x times 1 is identity(x)"
               | 
               | This is wrong.
               | 
               | 1kg * 1kg = 1kg2 period.
               | 
               | What you're saying is `2kg * 1 = 2kg`, which is right,
               | because `1` is a scalar while `2kg` is a quantity. This
               | is completely different than multiplying 2 quantities.
               | 
               | > It would not imply I'm multiplying the units, but
               | rather the scalar value of the unit.
               | 
               | That's where you're wrong. When doing arithmetic on
               | quantities, you have 2 equations:                 x = 2kg
               | * 4s       unit(x) = kg * s = kg.s       scalar(x) = 2 *
               | 4 = 8       x = 8 kg.s
               | 
               | Or                 x = 5m / 2s       x = (5/2) m/s
               | x = 2.5 m/s
               | 
               | There is a meaning to units and the operation you do with
               | them. `5m / 2s` is 5 meters in 2 seconds, which is the
               | speed `2.5 m/s`.
               | 
               | `2m + 1s` has no meaning, therefore you can't do anything
               | with the scalar values, and the result remains `2m + 1s`,
               | not `3 (m+s)`.
        
               | Armavica wrote:
               | All unit conversions are actually multiplications by the
               | dimensionless constant 1, i.e., no-ops.
               | 
               | Let's say that you want to convert `2 min` into seconds.
               | You know that `1 min = 60 s` is true. Dividing this
               | equation by `1 min` on both sides is allowed and brings
               | `1 = (60 s) / (1 min)`. This shows that if we multiply
               | any value in minutes by `(60 s) / (1 min)`, we are not
               | actually changing the value, because this is equivalent
               | to multiplying it by 1. Therefore, `2 min = 2 min * 1 = 2
               | min * (60 s) / (1 min) = 2 * 60 s * (1 min) / (1 min) =
               | 120 s`. We didn't change the value because we multiplied
               | it by 1, and we didn't change its dimensionality ("type")
               | because we multiplied it by a dimensionless number. We
               | just moved around a dimensionless factor of 60, from the
               | unit to the numerical value.
               | 
               | I think that you misremember, or didn't realize that to
               | convert minutes into seconds, you were not multiplying by
               | `60 s` but by `(60 s) / (1 min)` which is nothing else
               | than 1.
        
               | gpderetta wrote:
               | Wait, would you really expect 1m * 1m to be anything
               | other than 1m2? When does it ever happens that you want
               | to multiply to non-unitless[1] measurements and not
               | multiply the units???
               | 
               | [1] would that be unitful?
        
           | [deleted]
        
           | aasasd wrote:
           | Perhaps the function shouldn't accept the unit of sec2. Not
           | least because I have no idea what a delay in that unit could
           | signify.
        
             | rsa25519 wrote:
             | Note that the wonderful Go type system interprets
             | time.Second * time.Second as 277777h46m40s with the type
             | time.Second (not sec^2)
        
               | frozenice wrote:
               | time.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
        
             | ironmagma wrote:
             | It 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       )
        
             | nine_k wrote:
             | Certainly, but for that the type system should be rich
             | enough to support unit designators.
             | 
             | I know how to implement that in Haskell, and that it can be
             | implemented in C++ and Rust. I know how to logically
             | implement that in Java or Typescript, but usability will
             | suck (no infix operators).
        
               | int_19h wrote:
               | Go tends to cover such things by incorporating them
               | directly in the language. But then it tends to not cover
               | them at all because it would "overcomplicate" the
               | language...
               | 
               | For a good example of what it looks like when somebody
               | does bother to do it, see F# units of measure.
        
         | jamestimmins wrote:
         | I'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.
        
           | syntaxfree wrote:
           | Overloading the asterisk is always weird because
           | multiplication is expected to be associative etc etc.
        
             | thaumasiotes wrote:
             | But 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?
        
             | ts4z wrote:
             | time.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 wrote:
               | (As noted elsewhere it's nanoseconds.)
        
             | xyzzy_plugh wrote:
             | It'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 wrote:
             | It's not really overloading. it is associative:
             | 2*time.Hour+1*time.second == time.Second+time.Hour*2
        
               | wtallis wrote:
               | I believe that's illustrating commutativity, not
               | associativity.
        
               | thaumasiotes wrote:
               | The 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 wrote:
             | There is no operator overloading here. The type Duration is
             | effectively an int64: https://pkg.go.dev/time#Duration
        
             | vitus wrote:
             | I'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.)
        
           | cwojno wrote:
           | Having used it extensively, it's actually quite nice.
        
           | sk0g wrote:
           | Is 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.
        
       | ketzo wrote:
       | Tangentially related:
       | 
       | Would love HN's recommendations for blogs/writing on how to do
       | better programming.
       | 
       | A lot of writing that I am exposed to is about the business of
       | software, or engineering leadership, or architecture/tech stacks
       | -- which, to be clear, I really like reading, and find value in!
       | 
       | But I would love to read more thoughts on how to actually write
       | good code on a regular basis.
        
       | moralestapia wrote:
       | Agree with the post.
       | 
       | On JSON, I always do { unit:XXXX, value:XXXX }, it is quite
       | verbose but it does help a lot when you least expect it.
       | 
       | I also wrote a small utility that transforms between values like
       | { unit:'m', value:5 } to { unit:'km', value:0.005 } so that makes
       | it super easy for me to pipe stuff from one context to another
       | when is needed.
        
         | linkdd wrote:
         | Do you have a link to this utility?
        
           | moralestapia wrote:
           | Oh sorry, I haven't open sourced it, I never thought of it
           | actually until now.
           | 
           | As I now realize, it could be quite useful for others.
        
       | didip wrote:
       | Preach! This is a big issue across all projects written in any
       | programming languages.
       | 
       | Without this small info, you have to grep the docs or worse, grep
       | the source code itself. There's nothing wrong with looking at the
       | source code but you shouldn't have to if you just want to use the
       | public interface.
        
       | rzwitserloot wrote:
       | Thread.sleep (the java example) is ancient, but java is at least
       | consistent and uses millis for everything. Almost all other
       | timing functions in java have a 2-arg setup: `.foo(5,
       | TimeUnit.HOURS)`. Where TimeUnit is an enum that has the usual
       | options (HOURS, MILLIS, SECONDS, etc). It doesn't go beyond
       | 'days' (once you get to months in particular, is that 28 days, 30
       | days, 31 days, 30.437 days (which is the actual average)....).
        
       | einpoklum wrote:
       | C++ has, in recent years, improved support for this. The best
       | state of affairs is with time units:                   using
       | namespace std::chrono_literals;         auto lesson = 45min;
       | auto day = 24h;         std::cout << "one lesson is " <<
       | lesson.count() << " minutes\n"                   << "one day is "
       | << day.count() << " hours\n";
       | 
       | and you can compare durations specified with different units etc.
       | There mpusz/units library, which may go into the standard at some
       | point, lets you do this:                   using namespace
       | units::isq::si::references;              // simple numeric
       | operations         static_assert(10 * km / 2 == 5 * km);
       | // unit conversions         static_assert(1 * h == 3600 * s);
       | static_assert(1 * km + 1 * m == 1001 * m);
       | 
       | and also write conceptified functions which "do the right thing",
       | e.g.:                   constexpr Speed auto avg_speed(Length
       | auto d, Time auto t)         {             return d / t;
       | }
       | 
       | this will normalize appropriately. But - the specific units used
       | will need to be known at compile-time. Choosing units at run-time
       | is a different kettle of fish.
        
       | rpaddock wrote:
       | I once went in to clean up a project that was designed by a
       | committee of people spread all over the world. The unit was large
       | moving equipment that if something went wrong, people might die.
       | The unit was composed of several different CPU modules
       | communicating on a property bus. Each module's software was
       | written by a different group in a different part of the world.
       | 
       | The operator's requested speed was input in Feet Per Minute. The
       | output to a Variable Frequency Drive was in tenths of Hertz. The
       | tachometer feedback was in RPM, and to top it off all the
       | internal calculations were done in Radians-Per-Second.
       | 
       | The first thing I did to get the project back on track was to
       | adopt a standardized variable naming convention that included the
       | units. For example the Operator Request became
       | operator_request_fpm_u16. You then knew immediately you were
       | dealing with Feet Per Minutes, and that it was a 16 bit unsigned
       | variable.
       | 
       | After the variable name cleanup many of the bugs became self
       | documented, when you saw something like "operator_request_fpm_u16
       | / vfd_hz_s32" in the code, you knew there was a problem that
       | needed to be fixed...
        
         | gugagore wrote:
         | This is Hungarian notation. A combination of both flavors into
         | one. https://en.wikipedia.org/wiki/Hungarian_notation.
         | 
         | My take is that Hungarian notation exists to work around a
         | deficiency in tooling. I think this is clearer when encoding
         | e.g. u16 into the identifier, since that information is
         | redundant (the declaration or schema already encodes that it is
         | u16).
        
       | ChrisMarshallNY wrote:
       | This is something that I've done forever.
       | 
       | For example, when I create a static value to hold a constant, I
       | usually do it like so:                   static private let
       | _maximumButtonHeightInDisplayUnits = CGFloat(30)
        
       | skyde wrote:
       | what about having measure class instead. Ex:
       | 
       | Length object = Length.Parse(string);
       | 
       | or
       | 
       | Temperature object = Temperature.Parse(string);
       | 
       | this would but much simpler!
        
       | phkahler wrote:
       | It would be much better to (also) put the units int the function
       | name. Don't just have sleep() but sleepSeconds(). This prevents
       | the person writing code from having to look up or guess what
       | units the parameter has, as well as a person reading it later.
       | This is more an API design issue than an API user issue, although
       | both approaches can be used together.
        
         | hutzlibu wrote:
         | But I this is not really necessary, if you use a IDE with
         | integrated docs, where you see the parameters of a function on
         | a mouseover.
        
       | wodenokoto wrote:
       | timeout = timedelta(seconds=300)         frobnicate(timeout)
       | 
       | Working with GCP or Azure's Python SDK is like navigating a
       | jungle of types. Some calls return a `compute_engine_list_item`
       | while others return a `compute_engine` type and these are
       | difficult to inspect and reason about, because Python classes
       | default to printing something along the lines of
       | `<__main__.myclass at 0x7fa8864a1040>`, making heavily typed
       | Python code quite difficult to work with.
       | 
       | No paradigm is going to save you from spaghetti-code, but being
       | able to pass a list and get an integer in return, makes it very
       | easy to reason about what you can do with these values, whereas
       | it can be quite difficult to reason about custom types/objects.
       | 
       | My point is, that knowing if `frobnicate(timeout=300)` is in
       | seconds or minutes can be just as difficult (or even more
       | difficult) as knowing what specific object I need to instantiate
       | and pass to `frobnicate` (in the above case a `timedelta`)
        
         | Aeolun wrote:
         | I do not think the fact that Google API's have terrible types
         | is a good argument against typing in general.
        
         | dharmab wrote:
         | When I dealt with the Azure SDk for Python I frequently wrote
         | small scripts that created the types in question and then
         | called breakpoint() so that I could examine the types
         | interactively.
        
         | necovek wrote:
         | Badly designed type systems should not be the measuring stick.
         | 
         | But in your example above, typed Python would instruct your
         | editor and tools like mypy to flag any improper use of
         | frobnicate. You can set up your editor to offer you a tip on
         | what type to use as soon as you type in `frobnicate(`.
         | 
         | In cases where typing is not really available, I prefer to put
         | types into APIs instead of variable names (and Python makes
         | that great: `frobnicate(duration_as_timedelta=timeout)`).
        
         | akdor1154 wrote:
         | In general you're right.. strong typing needs good tooling and
         | thourough language support to be fun. Python is a bit lacking
         | in both of these.
         | 
         | In this specific example i disagree, timedelta is part of the
         | standard library and should be widely known and familiar.
        
         | chriswarbo wrote:
         | > being able to pass a list and get an integer in return, makes
         | it very easy to reason about what you can do with these values
         | 
         | I disagree; to paraphrase Ian Malcolm: what you _can_ do with
         | these values is less important than what you _should_ do with
         | these values. For example, we _can_ add a distance to a
         | currency, if they 're both int or float; that doesn't mean we
         | _should_.
         | 
         | The most obvious example of this is "stringly-typed
         | programming", where pretty much everything is "string". Can I
         | append a user-input string to an SQL statement string? Sure;
         | but I shouldn't. Can I append a UserInput to an SQLStatement?
         | Not without conversion (i.e. escaping)!
        
       | swyx wrote:
       | in the genre of naming things, some related things to explore:
       | 
       | - avoiding naming things if you can help it
       | 
       | - using tooling to autogenerate names
       | 
       | - avoiding too short, likely overloaded names like `id`, `name`,
       | and `url`
       | 
       | - don't choose lazy pluralization - eg instead of `names/name`,
       | use `nameList/nameItem`
       | 
       | - encoding types to make Wrong Code Look Wrong, a famous Spolsky
       | opinion (lite hungarian notation)
       | 
       | - coming up with grammars for naming, eg React had an exercise to
       | name its lifecycles combinations of THING-VERB-ACTION, like
       | `componentDidMount`, before open sourcing, which helped
       | learnability
       | 
       | pulled from my collection of Naming Opinions here:
       | https://www.swyx.io/how-to-name-things
        
         | tcbasche wrote:
         | >- don't choose lazy pluralization - eg instead of
         | `names/name`, use `nameList/nameItem`
         | 
         | Isn't this just extra noise? If the type of the variable is an
         | Array wouldn't `nameArray` be superfluous? Worse still is if
         | the type changes but the name stays the same.
         | 
         | I get the advice is probably Javascript specific, but even in a
         | Typescript world it doesn't make much sense to me to do this
         | kind of type-in-name encoding.
        
           | lifthrasiir wrote:
           | Even in typed languages `names` and `name` are too similar to
           | slow code reading down.
        
             | berkes wrote:
             | Exactly this. In many languages the compiler will help you.
             | 
             | But this has bitten me in Ruby, JavaScript and PHP several
             | times. Runtime errors and downtime. Most recent:
             | autocompled some updatedCartsItems when it had to be
             | UpdatedCartItems. Both were used in the same class. Had
             | they be named sensible, like CartListWithUpdatedItems and
             | UpdatedItemList or something better, I'd have saved myself
             | hours of WTFing through CI logs.
        
       | hwc wrote:
       | Also, when using Go, use the time.Duration type in your API. It
       | makes things unambiguous but adds no overhead.
        
       | windpower wrote:
       | Swift is pretty good at this. e.g.:
       | Task.sleep(nanoseconds: 3e11)
        
         | gh123man wrote:
         | In swift I quite like DispatchTimeInterval's approach [1] (see
         | Enumeration Cases). In most of my projects I end up adding a
         | simple extension to TimeInterval to get the same behavior.
         | Which makes reasoning about time very simple eg:
         | Date().advanced(by: .hours(2) + .seconds(10))
         | 
         | I'm honestly not sure why TimeInterval doesn't include this
         | representation by default.
         | 
         | 1.
         | https://developer.apple.com/documentation/dispatch/dispatcht...
        
       | amingilani wrote:
       | My preferred way in Python is:
       | 
       | ```
       | 
       | time.sleep(timedelta(minutes=5).total_seconds)
       | 
       | ```
       | 
       | Or
       | 
       | ```
       | 
       | time_to_sleep = timedelta(minutes=5)
       | time.sleep(time_to_sleep.total_seconds())
       | 
       | ```
        
         | jeffparsons wrote:
         | Unless I'm confident that I remember `time.sleep` wants a
         | number of seconds, then I could miss an obvious error there.
         | 
         | For example...
         | time.sleep(timedelta(minutes=5).total_milliseconds)
         | 
         | ...looks just as plausible. So what does this solve?
        
           | amingilani wrote:
           | It communicates my intent to the reviewer and future readers
           | of the code that: 1) I mean to set the duration to 5 minutes,
           | which is easier parsed by humans than 300 seconds. 2) I'm
           | passing seconds into time.sleep, which makes any mistakes I
           | make more obvious.
           | 
           | I'm not saying time.sleep can't be improved but my method
           | makes it easier to find any mistakes I've made in the future.
           | 
           | As a demonstration, reading your code makes it more obvious
           | that you've passed the wrong unit into time.sleep.
        
             | jeffparsons wrote:
             | Got it -- so it's more about mitigating the badness when
             | it's somebody else's API.
             | 
             | Seems reasonable! :)
             | 
             | When I encounter these sorts of methods (which is
             | surprisingly rare these days) I tend to double-check what
             | units the method takes and additionally add a comment above
             | my call saying "`sleep` takes duration in seconds", just to
             | give future readers more ways to check whether I screwed
             | up.
        
       | jonnycomputer wrote:
       | Ok, I'll bite. Why does time.sleep(secs) not accept keyword
       | arguments, but                   def foo(x):             print(x)
       | 
       | accept `foo(x='I accept keyword arguments!')`
        
         | falcolas wrote:
         | time.sleep is implemented in C. For Python, adding keyword
         | arguments to functions implemented in C takes a not-
         | insignificant amount of additional boilerplate, so its often
         | not done.
        
           | jonnycomputer wrote:
           | Ah, of course. Posting before my morning coffee. (:
        
       | jeffreygoesto wrote:
       | Good C++ library for that topic is [0]. You can even go further
       | and combine with something like [1] which is super helpful for
       | kalman filters and other stuff where you have heterogeneous units
       | in one vector.
       | 
       | [0] https://github.com/mpusz/units
       | 
       | [1] "Daniel Withopf - Physical Units for Matrices. How hard can
       | it be? - Meeting C++ 2021"
       | https://m.youtube.com/watch?v=4LmMwhM8ODI
        
       | rbanffy wrote:
       | Ruby has a very neat syntax that can solve that. For instance,
       | you'd just:                   sleep 5.seconds
       | 
       | or                   temperature = 0.17.kelvin
       | 
       | Not sure that last abuse actually works, but one may try. :-P
        
       | nailer wrote:
       | In JS/TS I'd do:
       | 
       | await sleep(5 * MINUTES)
       | 
       | Where MINUTE and MINUTES is a constant for 60 * SECOND.
        
       | gjvc wrote:
       | in the same vein, please name associative structures (hashes,
       | maps, dictionaries, etc) as _value-type-by-key-type_ (for example
       | "username_by_id", rather than "username_lookup" or such.
       | Conventions like these don't have an impact one-by-one, but
       | rather when applied to a body of code as a whole. In this case
       | when one has to do one lookup by the result of another the
       | explicit "x-by-y" naming really helps reassure me the right
       | values are being looked up!
        
       | oatmeal_croc wrote:
       | Is there a standard for Durations, like we have for Time? (Like
       | RFC3339)
        
         | rotifer wrote:
         | ISO 8601 specifies durations [1]. For example, Java's Duration
         | type [2] is based upon it.
         | 
         | Depending on your language, and how much type safety you want,
         | you could use something Haskell's units library [3].
         | 
         | I believe F# also has units [4], possibly built in to the
         | language? (I've never used F#.)
         | 
         | [1] https://en.wikipedia.org/wiki/ISO_8601#Durations
         | 
         | [2]
         | https://docs.oracle.com/en/java/javase/11/docs/api/java.base...
         | 
         | [3] https://hackage.haskell.org/package/units
         | 
         | [4] https://docs.microsoft.com/en-us/dotnet/fsharp/language-
         | refe...
        
       | friendzis wrote:
       | Please do not, unless you are actually implementing unit
       | conversion logic.
       | 
       | Pass around _types_ encoding certain quantities. You do not want
       | a Thread to  "sleep for x units", but rather "sleep for this
       | specific Duration", therefore pass around Durations and implement
       | appropriate utilities `.toSeconds(Duration d)`, `.fromTime(Time
       | t1, Time t2)`. The very moment your `.frobnicate(int
       | time_in_seconds)` gets wrapped in `foobar(int duration)` all
       | meaning is lost and _you have no control over it_.
       | 
       | Type systems are there to encode meaning (sometimes including
       | possible values) behind a value - use it. And if you use highly
       | dynamic prototyping language in production... Well, inability to
       | encode and _enforce_ meaning behind a value is part of the
       | compromise.
        
         | gwright wrote:
         | From the article:
         | 
         | > Option 2: use strong types, An alternative to putting the
         | unit in the name, is to use stronger types than integers or
         | floats. For example, we might use a duration type
        
       ___________________________________________________________________
       (page generated 2022-03-21 23:01 UTC)