On Tue, Apr 27, 2021, at 2:07 PM, Chase Peeler wrote:

> > Sometimes it's helpful to apply a risk perspective the shed some light
> > under hidden assumptions of different arguments. For example, what's
> > the probability and impact of an event that would limit a coder when a
> > library is using a sealed class? And the other way around, what's the
> > probability and impact of an event that would decrease code quality
> > when a sealed class is *not* used (like being able to subclass
> > Maybe/Option even when it "shouldn't" be possible)?
> >
> >
> As someone mentioned above, maybe they want to just add some logging
> capabilities to maybe.
> class MyMaybe extends Maybe {
>   protected $logger;
>   public function setLogger($logger){ $this->logger = $logger; }
>   public function value(){
>      if(null !== $this->logger){ $this->logger->log("getting value"); }
>      return parent::value();
>   }
>  }

That's subtly different than what is being discussed here.  Consider:

class Maybe { ... }

class Some extends Maybe { ... }

class None extends Maybe { ... }

And now assume we have pattern matching in the match expression (just to make 
the following example simpler; it could also be done with instanceof directives 
just as well but it's more verbose):

function operateOnValue(Maybe $m) {
  $val = match($m) is (
    Some($v) => $v,
    None => $some_default,
  };
  ...
}

This code works on Maybe as defined, with two branches, Some and None.

If you extend Some with your own custom Some, it still works.  This code is 
fine.  Such extension could be prevented by making Some final, but *you can 
already do that today*.

If you want to add another subclass of Maybe, called Perhaps... that function 
will now break, because the nominal contract of Maybe (that it has only two 
variants) has been broken.  As soon as you pass a Perhaps to operateOnValue(), 
the function will fail with an exception.  And there is no way to prevent that 
today.

The two options to prevent such errors are:

1. Sealed classes.
2. Extend Enums into ADTs.

They're different in a few key ways, but both address the same problem space 
and would render operateOnValue() safer against errors, because its developer 
can know, by definition, that it can handle all possible variants of Maybe.  
(That is, it's a total function over Maybe.)

A comment (by whatever syntax) saying "pretty please don't extend Maybe" is 
worth the executable code it generates (which is to say, None).

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to