On Thu, May 23, 2024, at 1:35 AM, Robert Landers wrote:

> For what it's worth, the biggest downside to this decision is in
> upgrading old/legacy projects to use enums. Most of the time, you want
> to convert a const to an enum, and that also usually means it will be
> a backed enum. Since there's no way to cast a backed enum to a
> string/int, you have to instead add ->value (I really don't understand
> the difference; casting would have been much more elegant); this
> almost always results in lots of hidden runtime errors. At the last
> couple of places, after seeing the damage the conversion could do,
> doing this conversion was simply off-limits. Maybe by now, there is
> some reliable tooling to handle this automatically... I haven't
> looked. The point remains that it is a strange decision to use
> `->value` but not allow `(string)` or `(int)` or allow even
> implementing it yourself.

Union types are the correct solution here:

function move(string $direction, Player $player) { ... }

becomes

function move (Direction|string $direction, Player $player) {
    if (is_string($direction)) {
        $direction = Direction::from($direction);
    }
    // We now have a normalized enum to work with.
}

The only catch there is inheritance, where it works fine if you jut expand the 
implementers/children first, then the interface/parent.  Then you can remove 
the string option at some point in the future, going the other way 
(interface/parent, then implementer/child).

--Larry Garfield

Reply via email to