## Notes for November 7th, 2022

As a reminder, we use [this syntax](DU-2022-10-31.md#pseudo-syntax) for describing unions forms.

### Conversions

Pickup up from last week, we talked about equivalency again. This time, we started by focusing on the differences between `union (A | B)` (an anonymous union of types) and
`union NamedAOrB (A | B)` (a named union of types). We do generally think that `union (A | B)` and `union (B | A)` should at least be implicitly convertible, if not identical,
and that has implications on the grow up story. Much like with tuples, we don't think anonymous union types belong in public APIs, except in cases like `Zip` where the
implementation detail of the tuple is the _purpose_ of the API (in other words, when the likelihood of adding or removing a new element is nonexistent). Tuples that need to
be in public API generally want to grow up to be positional records, and we might need something similar here for untagged named unions. In thinking about it more, though,
we're not certain of the need for exporting this type of union. It would have limitations, such as the inability to have two different cases with the same type (a string result
or string error, for example, couldn't be represented without a separate tag), so it's possible that the roles proposal is enough for us here. Something like
`role NamedAOrB : (A | B);` would give a name to the case, give us equivalency with the underlying type, and maintain discouragement of putting untagged unions in public
type hierarchies.

### Switching on unions

We considered a few different ways that users might want to pattern match against anonymous unions of types:

```cs
void M((int|string) x) 
{
    object o = x;
    _ = o switch
    {
        (int|string) => 0,
        _ => 0
    };
    _ = o switch
    {
        int or string => 1,
        _ => 1
    };
    _ = o switch
    {
        int => 2,
        string => 2,
        _ => 2,
    };

    // Switch on x
    _ = x switch
    {
        int => 2, // Could use x.IsTypeOf<int>
        string => 2,
        _ => 2,
    };
}
```

There are a few ways this could work:

1. Erase the union, and have it be object. Type tests are emitted as today.
2. Check for an IsOneOf marker interface. Would have to always check, behavior change on recompile.
3. When switching on the union itself, call an `IsType<T>` method.
4. Have the runtime participate in boxing, throwing away a wrapper type.

We don't have any decisions yet, we're still exploring the space. We'll keep exploring further.
