[HN Gopher] Multiplicity Choices Are Hard to Model and Change
       ___________________________________________________________________
        
       Multiplicity Choices Are Hard to Model and Change
        
       Author : ltratt
       Score  : 11 points
       Date   : 2022-05-27 07:08 UTC (1 days ago)
        
 (HTM) web link (tratt.net)
 (TXT) w3m dump (tratt.net)
        
       | dataangel wrote:
       | I broadly agree with multiplicity problems being the worst, but
       | have some nits.
       | 
       | > because my language's static type system probably won't give me
       | any leads on what needs fixing
       | 
       | This is because moving to Vec<Address> introduced 0 addresses as
       | a possibility into the type already and you didn't deal with it
       | then. If the author had moved to NonEmptyVec<Address> first, then
       | you could have transitioned to Option<NonEmptyVec<Address>>.
       | 
       | > Ironically, I often find that the hardest places to work out
       | what to do are those where the static type system forces me to
       | deal with the possibility of there not being a T but my analysis
       | of the code shows (or, at least, suggests) that at run-time there
       | always will be a T. This leads to a counter-intuitive situation:
       | although the static type system has helpfully told me all the
       | places where changing the multiplicity needs to be considered, I
       | can introduce more run-time errors than I could ever have
       | encountered in a non-option-types language!
       | 
       | This doesn't quite make sense. Either the errors could also
       | happen in the dynamic type setting in which case you were missing
       | checking you needed, or they can't happen in either setting in
       | which case you may have unnecessary code _checking_ for a missing
       | T, but those runtime errors never actually occur in practice. I
       | think maybe the author means those unnecessary checks are  "more
       | runtime errors", but it's not that you actually get more errors
       | in practice, it's just that someone reading the code might think
       | there is the possibility of errors in more places than there
       | actually are. There is an easy solution to this though: find the
       | earliest point where it's guaranteed that there is actually a T,
       | put one assert there with a comment indicating that if this
       | assert is ever false it's a bug, then stuff the the unwrapped T
       | in a new variable and use it from then on. If you need to pass it
       | to a function that requires an option just call it with
       | f(Some(foo)).
       | 
       | > (e.g. do I dynamically check the property each time I create
       | one of my new wrapper types? what is the performance cost?)
       | 
       | No you only have a constructor that requires you to pass in at
       | least one initial element which will statically enforce that it's
       | at least size one, and then only have the container assert that
       | it's still at least size one when methods that remove elements
       | are called (which in most use cases you probably won't ever call
       | or will call rarely). The cost is one branch when erasing, it's
       | very cheap. And since erasing from anywhere in the vector except
       | the end involves shifting comparatively speaking the branch is
       | cheap.
        
       ___________________________________________________________________
       (page generated 2022-05-28 23:01 UTC)