Option types and pattern matching.

Edmund Smith via Digitalmars-d digitalmars-d at puremagic.com
Mon Oct 26 08:58:36 PDT 2015


On Monday, 26 October 2015 at 14:13:20 UTC, TheFlyingFiddle wrote:
> On Monday, 26 October 2015 at 11:40:09 UTC, Edmund Smith wrote:
>> Scala's Option is really nice on the other hand since you 
>> can/should pattern match).
> Don't really see a point in an optional type if can access the 
> underlying
> value without first checking if it's there.

The key difference with (exhaustive) pattern matching is that it 
*is* the check that the value is there. Pattern matching enforces 
the existence of an on-nothing clause for Optional, on-error for 
Error, on-Leaf and on-Branch for Bintrees, etc.
And even with nice higher-order functions, plain pattern matching 
is quite valuable for finely controlled error/resource handling, 
and I often see it in Rust code as well as Scala (and I've seen 
it used in Haskell occasionally too). A brief, contrived example 
use-case:

//External code that disallows monadic int[]
void processThatMustOccur(int[] data);
...
Option!File findFile(string fname);
Result!(int[]) parseInts(File file);

//verbose for clarity
void parseMatches(string path) {
     Option!File ofile = path.findFile();

     //Static guarantee of handling value not present
     ofile match {
         None() => {
             //Handle error for no file found, retry with new path
         }
         //The existence of file is effectively proof that ofile 
is present
         Some(file) => {
             Option!(int[]) odata = file.parseInts();
             odata match {
                 Success(data) => 
processThatMustOccur(preProcess(data));
                 Error(error) =>
                     //Handle error for bad parse, backtrack 
depends on error
             }
         }
     }

     //Continue after processing data
}

void parseMonadic(string path) {
     path.findFile()
         .bind!parseInts()
         .bind!(map!preProcess)
         .bind!processThatMustOccur()
         .onFailure!backTrack
         //How can we backtrack a variable amount easily?

     //Continue after processing data
}

The error control loss can be mostly avoided by using an 
appropriate error monad or API design, but there's still the 
issue of interfacing with non-monadic code.
It essentially provides a guarantee that the equivalent of 'T 
get();' will handle errors, like having a checked exception 
version 'T get() throws OnNotPresent;' instead. It also scales up 
much better than having these checked exceptions on not-present 
ADT accesses.


More information about the Digitalmars-d mailing list