Option types and pattern matching.

TheFlyingFiddle via Digitalmars-d digitalmars-d at puremagic.com
Tue Oct 27 08:06:05 PDT 2015


On Tuesday, 27 October 2015 at 07:55:46 UTC, Kagamin wrote:
> On Monday, 26 October 2015 at 16:42:27 UTC, TheFlyingFiddle 
> wrote:
>> If you instead use pattern matching as in your example you 
>> have much better context information that can actually help 
>> you do something in the case a value is not there.
>
> Probably possible:
>
> Some!T get(T)(Option!T item) {
>     Some!T r;
>     //Static guarantee of handling value not present
>     item match {
>         None() => {
>             throw new Exception("empty!");
>         }
>         Some(t) => {
>             r=t;
>         }
>     }
>
>     return r;
> }
>
> Then:
> Option!File file;
> Some!File s = file.get();

Sure that would work but i don't see that it's different then an 
enfore since you don't have access the context where get is 
invoked so you can't really do anything with it.

Contrived Example:

void foo()
{
    Option!File worldFile = getAFile("world.json");
    auto world  = parseJSON(worldFile.get());
    Option!File mapFile = getAFile(world["map"]);
    auto map    = parseJSON(mapFile.get());
    //Other stuff.
}

Let's say we get an NoObjectException, this tells us that either 
the world.json file did not exist or the map file does not exist. 
get does not have access to that context so we wouldn't be able 
to tell. This next example would fix this.

void foo()
{
    Option!File worldFile = getAFile("world.json");
    enforce(worldFile.hasValue, "Error while loading file: 
world.json");
    auto world = parseJSON(worldFile.get());
    Option!File mapFile = getAFile(world["map"]);
    enforce(mapFile.hasValue, "Error while loading file: " ~ 
world["map"]);
    auto map = parseJSON(mapFile.get());
    //Other stuff
}

Now we know which file failed to load. But we bypassed the 
NoObjectException to do it.

I would prefer this style instead.
void foo()
{
   Option!File worldFile = getAFile("world.json");
   match worldFile {
      Some(value) => {
          auto world          = parseJSON(value);
          Option!File mapFile = getAFile(world["map"]);
          match mapFile {
             Some(mapf) => {
                auto map = parseJSON(mapf);
                //Do something here.
             },
             None => enforce(false, "Failed to load: " ~ 
world["map"]);
          }
      },
      None => enforce(false, "Failed to load: world.json");
    }
}

The reason that I prefer that is not that I like the syntax 
really. It's just that if the only way to get a value is to 
pattern match on it then you are forced to consider the case 
where the value was not there.


Guess a D version without language support would look something 
like:
void foo()
{
   auto worldFile = getAFile("world.json");
   worldFile.match!(
      (File worldf) {
         auto world = parseJSON(value);
         auto mapFile = getAFile(world["map"]);
         mapFile.match!(
            (File mapf)
            {
               auto map = parseJSON(mapf);
               //Do stuff;
            },
            (None) => enforce(false, "Failed to load: " ~ 
world["map"]);
      },
      (None) => enforce(false, "Failed to load: world.json")
   );
}

The example here is very contrived. Here we just throw exceptions 
if the file could not load and if that is all we do we should 
just wrap getAFile instead but i hope you get my point.






More information about the Digitalmars-d mailing list