Tagged unions [Was: What's wrong with std.variant.Variant?]
Paul Backus
snarwin at gmail.com
Tue Jun 16 16:26:14 UTC 2020
On Tuesday, 16 June 2020 at 12:44:54 UTC, Simen Kjærås wrote:
>
> I'm not Dukc, but here's an example I came up with:
>
[...]
>
> Essentially, there's shortcut returns for a few cases, but the
> others have some common behavior, even better if this is
> slightly different in one single place for one single held
> type, so you can't really factor it out as a separate function.
>
> --
> Simen
I think this is an instructive example, because it illustrates
one of the key
differences between functional-style code and imperative-style
code: explicit
coupling via funcion parameters and return values vs. implicit
coupling via
shared state.
Here's how I would write it:
float common1(float value)
{
// Lots of code that manipulates 'value'
}
float common2(float value)
{
// More code that manupulates 'value'
}
float special(string s, float value)
{
// Do something special for only one of the types,
// but after doing lots of common things
}
float myFun(SumType!(float, int, string, int[]) a)
{
import std.functional: pipe;
return a.match!(
number => cast(float) number,
(string s) =>
s.process
.common1
.pipe!(value => special(s, value))
.common2
(int[] ia) =>
ia.process
.common1
.common2
);
}
You'll notice that I've taken the liberty of extracting each
arbitrary "chunk"
of code indicated by a comment into its own function. In doing
so, I've had to
make the inputs and outputs of those chunks explicit (and make
some assumptions
about what they are). While this is a bit of extra work up front,
I think it
makes the end result easier to understand--not to mention easier
to unit test.
Exercise for the reader: how can this code be further refactored
to eliminate
the duplication between the string and int[] cases?
(Solution:
https://gist.github.com/pbackus/deda874eeddf587d938cb5d6213a0b84)
More information about the Digitalmars-d
mailing list