Hacker News new | past | comments | ask | show | jobs | submit login

Awesome, the ability to unwrap multiple optionals on one line should be bolded, underlined and all caps at the top of this article. Seriously though, this is an everyday pain point that happens all the time when writing Swift. Glad Apple is listening to developer feedback on this stuff.

Translation for those unfamiliar with Swift: Swift has a relatively strong type system. If a variable in Swift can be null at any point, it must be explicitly declared so as part of its type (e.g. an integer that can be null has the type "Int?", an integer that cannot be null has the type "Int").

Swift has a way to 'unwrap' these optional values and do things with them if they exist. Prior to this release, unwrapping multiple optional things required a bunch of nested if statements. With this release, unwrapping multiple optional values can be done in one if statement.




> Awesome, the ability to unwrap multiple optionals on one line should be bolded, underlined and all caps at the top of this article

This is why it's lame that Swift's optionals are a language feature and not an in-language implementation.

In Haskell, optionals are Monads, which means there is a function

    join :: m (m a) -> m a
"Maybe" (Haskell's standard library Optional) is a monad, so you can unwrap/collapse them using Join.

You can also daisy-chain them together using >>=, a la

    fail1 :: Maybe a
    fail2 :: a -> Maybe b
    result = fail1 >>= fail2
If either fail1 or fail2 fails, the entire "result" function fails (i.e. returns "Nothing").


If let (and optionals in general) is my favorite Swift feature and has immediately made my code 10x more stable from the get-go. Glad to see it get expanded like this.


I'd like to see them expand it the way Rust did: Rust lifted `if let` from Swift (I believe) but made it a more general-purpose refutable pattern matcher, it's just one step below match and works with any enum type not just Option. So you can write:

    enum Foo {
        Bar,
        Baz(i32),
        Qux(f64)
    }

    if let Bar = item {
        // do something
    } else if let Baz(val) = other {
        // do something with val
    }
which is oft shorter than a full-blown `match`, and more convenient when alternating on different "source" items.


Swift borrowed "if let" from Rust, not the other way around.


"The if let construct is based on the precedent set by Swift,"

https://github.com/rust-lang/rfcs/blob/master/text/0160-if-l...


That's putting it a bit mildly. Speaking as the author of that RFC, Rust's "if let" would never have existed if it were not for Swift. When I saw Swift's "if let" I immediately knew I wanted it in Rust. I also generalized it to arbitrary patterns at that time, since Rust doesn't fetishize Option the way Swift fetishizes Optional.

I am glad to see Swift 1.2 expanding "if let" to multiple clauses. But I do wish it supported arbitrary values instead of just Optional.


Wow. Such a rapid feedback loop here. Thanks for sharing.


if-let is great. I don't know where it started (apparently upthread they say Rust and swift have been swapping the idea) but Clojure has had it since 2008.[0]

    (if-let [name name-whose-value-is-possibly-null]
      (something-to-do name))
[0] https://clojuredocs.org/clojure.core/if-let


C++98 (maybe earlier) has a similar feature:

    if (mytype* p = find_or_null(blah))
        foo(*p);
Still have to dereference p, but at least it's only in scope when doing so is safe. Also goes well with auto and std::optional:

    if (auto opt = find_or_none(blah))
        foo(*opt);


I imagine everything in Swift has been borrowed from another language. OCaml, Go, etc. I'd be more interested in other great language features that are missing from Swift that are in other "classic" languages like OCaml, for instance.


Why is "if let" preferable to generalized pattern matching?


It's not "preferable" in the sense that you should have if let and not pattern matching. In Rust (and probably in Swift) it builds upon (and maybe desugars to, not sure) pattern matching. `if let` tends to be shorter and more readable than a full-blown match with a single match branch or just match/fail. Chainable `if let` is also significantly more convenient when trying multiple alternatives (on different source variables) one after the other.

See the Rust RFC on the subject for motivations and comparisons: https://github.com/rust-lang/rfcs/blob/master/text/0160-if-l...


I'm not a language guy so I don't know anything about generalized pattern matching. Maybe it is better. But for my own use, "if let" ensures that I always take care of any possible nulls in my code, while also keeping the conditional code in the same scope as the verified variable. There's no easy way to leave pointers dangling or uninitialized. The language design forces me to organize and think about my code in a much better way.


With generalized pattern matching, your code could (among other things) take the form of

    case result of
        Just x -> <do something with x>
        Nothing -> <do something without x>
This works with optionals as well as any other algebraic data type.


I'm not sure if this is the case in your example, but at least in Swift, the "if let" block or chaining for optionals is mandatory. This should mean that it's impossible to have a dangling/null pointer unless you use the force dereference operator. (And that's something that should almost never appear in your code!) You don't get the choice of being lazy or forgetting about checking your pointers: it's a conscious decision either way.

Personally, I appreciate that the language naturally makes me organize my code better and more safely.


It is, and you can pattern-match Optional in Swift, something along the lines of

    switch optional {
    case .Some(let numeral):
        println("Caught a \(numeral)")
    default:
        println("Nothing to catch")
    }


The nested if-let statements of doom have been one of my major annoyances -- so glad to hear unwrapping multiple optionals in a single line landed in 1.2.

The "wrapping the optionals in a tuple and using switch to pattern match" hack always seemed dirty, and this is a huge step in the right direction for code readability.




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

Search: