Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Adding on, its also a bit much to say that Swift has a good level of sugar and reference an enum of all things. Swift's union type story is so poor that, instead of properly modeling state, people to this day still use masses of optional types in their views rather than an enum because actually using swift enums and protocols is so painful.


I don’t which Swift developers you are talking to, but let the record know I don’t and use enum quite a lot. And I don’t find it particularly painful though a bit verbose at times.


I think Swift enums are really well designed, but SwiftData doesn't really support them unfortunately and Observable has problems with reactivity and enums (works on iOS not macOS I've found).

So lots of optionals might well be the better path here.


I don't think it's horrible, but I really do wish they would copy TypeScript here.

Let me do this:

    const x: String | Int
Instead of

    enum MyEnum {
        case string(String)
        case int(Int)
    }
There's an existing proposal for this here:

https://forums.swift.org/t/re-proposal-type-only-unions/7270...


It's worth pointing out that the two examples that you're writing are actually strictly different, and not just "better syntax for the same thing". (This is assuming `String | Int` works as in Python, and the second example works as in Rust.)

To understand the difference, `String | String` is just `String`. It's a union, not a sum type. There's no tag or identifier, so you cannot distinguish whether it's the first or the second string.

If this sounds pedantic, this has pretty important ramifications, especially once generics get involved.


To provide a concrete example, this bit me in a typescript codebase:

    type Option<T> = T | undefined

    function f<T>(value: T): Option<T> { ... }

    let thing: string | undefined = undefined;
    let result = f(thing);
Now imagine the definition of Option is in some library or other file and you don't realize how it works. You are thinking of the Option as its own structure and expect f to return Option<string | undefined>. But Option<string | undefined> = string | undefined | undefined = string | undefined = Option<string>.

The mistake here is in how Option is defined, but it's a footgun you need to be aware of.


The mistake here is that you assume that Option is a struct. For TypeScript, this is an idiomatic definition of something that is optional though.


I guess I just want to be able to do something like this in Swift:

    let x: String | Int
    
    switch x {
        case let value as String:
            // handle String value here
        case let value as Int:
            // handle Int value here
    }
There's one more thing about TypeScript-style union types: string literals. I think it's great to be able to do

    type Options = "option_1" | "option_2" ... "option_n"
And subsequently I could use

    let t: Options
    switch t {
        case "option_1":
            // handle `"option_1"` case here
        ...
        case "option_n":
            // handle `"option_n"` case here
    }
I think this is more programmer friendly than requiring an out-of-line definition of a new `enum`. Sometimes you just want to write some code, you know?


Hijacking your comment because this is a common point that's made on the superiority of Swift syntax against the union syntax.

At least with |, you're attempting to model the state space. You're saying "this is one of these things." You might get the exhaustiveness wrong, but you're in the right ballpark. As it's normally done right now, the Swift developer with five optional properties is modeling state as "maybe this, maybe that, maybe both, who knows, good luck." which is just worse than a bar. If you need to discriminate explicitly, add a `__kind` field!


So long as you have structurally typed structs (as TypeScript does), you can do stuff like {foo: string} | {bar: string} to the same effect as type constructors if and when you actually need it.

At the same time, how often do you really need (Just (Just (Just ...)))?


Note that union types are not the same thing as sum types, even if they're somewhat similar. https://viralinstruction.com/posts/uniontypes/


> actually using swift enums and protocols is so painful.

In what way? My understanding is they're widely used and encouraged.


If you look at most swiftui views, there will be a mass of optionals, rather than enum cases for every possible state that the view can occupy and a state machine transitioning between each state.

If you actually try and write it all out (like go full-on and use TCA to model all the states and actions such that all and only valid states can be represented in the state types) the compiler is going to have a hard time, you're going to write masses of boilerplate, and just in general it's much rougher than zustand and expo.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: