[swift-evolution] [Pre-Proposal-Discussion] Union Type - Swift 4

Matthew Johnson matthew at anandabits.com
Sat Aug 20 13:09:31 CDT 2016

> On Aug 20, 2016, at 12:27 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> Maybe I'm not getting something. But if you only want T | U | V to expose members required by common protocols P, Q, and R, since you know the types at compile time, you also know the common protocols. Why wouldn't you just write P & Q & R, and if necessary precondition(x is T || x is U || x is V)?

This isn’t something I personally was advocating for (in fact I specifically suggested *not* proposing this would be a better strategy for receiving serious consideration of something union-ish).

However, if we *did* do something like this it would provide a static verification that the precondition is met while still exposing the members of the common protocol(s) directly.  That is substantially better than runtime verification of the precondition or the boilerplate necessary to expose provide forwarding members.

My personal interest in something union-ish is really along the lines of syntactic sugar for enums.

Rather than writing this:

enum StringOrIntOrBool {
    case .string(String)
    case .int(Int)
    case .bool(Bool)

func foo(values: [StringOrIntOrBool]) {}

foo([.string(“hello”), .int(42)])

I would prefer to just write:

func foo(values: String | Int | Bool) {}

foo([“hello”, 42])

The use case for this I found is in designing DSLs of various kinds where you need to accept a heterogenous collection of a specific fixed list of concrete types.  The primary concern is to have static verification of the possible values provided by the caller without requiring callers to manually instantiate cases and without polluting the member types with unwanted conformance to a single-use protocol (which would be an alternative if we get sealed protocols).

If we add automatic lifting as Brent suggested that solves the primary concern I have.  If we do add that, introducing the union-like notation would make sense as convenient syntactic sugar for use in these scenarios where the sugar states the intent more clearly and concisely than something a contrived name like `StringOrIntOrBool`.  But as I have already stated, that is as secondary concern and automatic lifting alone would solve the primary (call site / library user) concern.


> On Sat, Aug 20, 2016 at 12:35 Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>> wrote:
> > On Aug 20, 2016, at 10:36 AM, Haravikk <swift-evolution at haravikk.me <mailto:swift-evolution at haravikk.me>> wrote:
> >
> >
> >> On 19 Aug 2016, at 15:38, Xiaodi Wu via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> >>
> >> Ad-hoc enums have been discussed already, at length, and all the weaknesses touched on then still apply now. For instance, since they're ad-hoc, can you pass an instance of type "Int | String" as an argument if the function expects a "String | Int | Float"? Enums don't have duck typing behavior like that; if your ad-hoc type does, then it's not very much like an enum; if it doesn't, it won't feel much like a union type.
> >
> > While ad-hoc enums are certainly similar I don't think that this problem applies to unions; the problem with ad-hoc enums is that while cases may have the same name, the meaning of a case may not be identical, so compatibility is uncertain. For type unions I'd say this isn't an issue; I'd say that yes, String | Int is compatible with String | Int | Float as every possible value can be carried over (whereas the reverse is not true), they're just values of one of several types, so as long as the conversion is possible, it should be fine to pass it on (or rather, repackage it behind the scenes).
> >
> >> Moreover, an ad-hoc "String | Int" may look like a union type, but until switching over an instance to cast it, you can't invoke any methods common to String and Int. So it really doesn't feel like a union type at all.
> >
> > Could it not do that though? I'd say that a union type should conform to any common protocols that its members conform to; if this can be done in the initial release then great, otherwise it can come later.
> Conforming to common protocols would be much better than an implicit ad-hoc / duck-typed protocol that simply exposes all common members.  But there is strong opposition to unions, much of which is related to implementation complexity.  It seems to me that the path to having unions or a union-ish feature receiving serious consideration is to demonstrate the value they can offer even with relatively restricted functionality (such as syntactic sugar for enums with implicit lifting).  If that is successful we will have an opportunity to work with them and make a case for enhancements in the future.
> Also, it won't always possible for a union to conform to a protocol conformed to by all member types.  If the protocol has `Self` requirements in argument position it would not be able to conform and if it has associated type requirements which are bound to different concrete types in the types making up the union it would also not be able to conform.
> Matthew

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160820/96267255/attachment.html>

More information about the swift-evolution mailing list