mozilla/rust — Issue #1945: RFC: handling partial functions in Rust libraries
Author: catamorphism
Created: 2012-03-08 23:41:48+00:00
State: open
Labels: A-typesystem, B-RFC

I don't have a specific proposal, but I do want to discuss principles for how to handle partial functions in the standard libraries. Examples of partial functions are ```option::get``` (undefined on ```none```), ```vec::last``` (undefined on empty vectors), and ```map::get``` (undefined for keys not bound in the map).

One approach is to "totalize" these functions by lifting their results into the ```option``` type: for example, ```vec::last``` would return ```none``` if invoked on an empty vector and ```some(x)``` on a non-empty vector, for some ```x```. (That was the behavior until today.)

Another approach is to use typestate to specify preconditions so that we write total functions on a smaller domain, rather than partial functions on a bigger domain.

Finally, perhaps the simplest approach is for library functions to ```fail``` with an uncaught exception when error conditions arise.

I prefer either the first or second approach over the third (ideally I would prefer the second, but clearly there has been some hesitance to use typestate in anger). My preference is informed by my experience with Haskell where the use of functions like ```fromJust``` or ```head``` in cases where the invariants don't really hold (and the compiler doesn't help by checking those invariants) is a major pain. If you know an invariant, you should be able to write it down and express it either through types or typestate (whether it's types or typestate is more of an implementation detail to me).

However, I just changed ```vec::last``` to fail on an empty vector, for consistency with some of the existing ```vec``` code. I'd like to arrive at some guiding principles here.