[swift-evolution] [Idea] Use optionals for non-optional parameters

Xiaodi Wu xiaodi.wu at gmail.com
Mon Aug 15 14:39:50 CDT 2016


On Mon, Aug 15, 2016 at 2:29 PM, Tim Vermeulen <tvermeulen at me.com> wrote:

>
> On 15 Aug 2016, at 21:27, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Mon, Aug 15, 2016 at 1:57 PM, Haravikk via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>>
>> On 15 Aug 2016, at 13:44, Tim Vermeulen <tvermeulen at me.com> wrote:
>>
>> On 15 Aug 2016, at 08:02, Justin Jia via swift-evolution<swift-evolutio
>> n at swift.org(mailto:swift-evolution at swift.org <swift-evolution at swift.org>
>> )>wrote:
>> Hi!
>>
>> I don’t know if this has came up before. I tried to search though the
>> mailing list but didn’t find any related threads.
>>
>> This is purely a syntactic thing (which I know it’s the lowest priority
>> for Swift 4), but I think it’s an important one.
>>
>> Let’s say we have a struct with a function:
>>
>> ```
>> struct Foo {
>> func bar(x: Int)
>> }
>> ```
>>
>> We can use optionals:
>>
>> ```
>> let foo: Foo? = nil
>> let x = 1
>> foo!.bar(x: x) // Able to compile, but will cause runtime error
>> foo?.bar(x: x) // Able to compile, and won't cause runtime error
>> ```
>>
>> However:
>>
>> ```
>> let foo = Foo()
>> let x: Int? = nil
>> foo.bar(x: x!) // Able to compile, but will cause runtime error
>> foo.bar(x: x?) // Won't compile
>> ```
>>
>> I propose that we should allow `foo.bar(x: x?)`, which should be
>> equivalent to:
>>
>> ```
>> if let x = x {
>> foo.bar(x: x)
>> }
>> ```
>>
>> What do you think?
>>
>> I like the intent behind this, but personally I think it's not clear
>> enough. For me, putting the statement in a conditional as you've shown is
>> the better solution, as it's a lot clearer exactly what's going on. Putting
>> a question mark on a variable makes it look like something specific to that
>> variable, rather than preventing the entire statement from executing.
>>
>>
>> I get where you’re coming from, but how would people react if optional
>> chaining wasn’t in the language yet and someone proposed it now? I know
>> it’s not strictly the same thing, but it’s still a single question mark
>> that prevents the whole statement from being executed. I think it would be
>> met with a lot of resistance from people saying that being more explicit
>> with `if let` is the way to go.
>>
>>
>> True, but with optional chaining the position of the question mark makes
>> it a lot more clear where it stops, whereas in this proposal the question
>> mark seems a bit less intuitive since it's within the parenthesis yet
>> affecting the statement outside of it.
>>
>> There may be some alternatives though, for example, what about a
>> shorthand for the conditional like so:
>>
>> if let x? { foo.bar(x: x) }
>> if x? { foo.bar(x: x) } // even shorter?
>>
>>
>> The alternatives you’ve come up with would only work if foo.bar doesn’t
>> return anything. If it does return something, and you want to assign it to
>> a variable, you have to declare the variable beforehand and it just becomes
>> ugly. It’s then probably a better idea to use map/flatmap:
>>
>>
>> Hmm, what about something involving the where keyword? Something like:
>>
>> let value = foo.bar(x: x) where x?
>>
>>
>> Some people have queried the ability to use where in assignments before,
>> as another way to have a statement be nil if a condition isn't met, but in
>> this case the condition is that x is unwrapped (thus valid for the call).
>> This basically lets you use it like a "retroactive" conditional, it'd be
>> nice to get the same x? behaviour on for loops anyway (letting you unwrap
>> values that way, and maybe test them too).
>>
>
> `let value = (x == nil) ? nil : foo.bar(x: x)` isn't so bad, is it?
>
>
> In my opinion, it is.
>

It certainly isn't much longer, and its meaning is clear to anyone with a
basic grasp of Swift. What makes it bad, in your opinion?


> And you’d even need to write `foo.bar(x: x!)`, right?
>

You would. That's my bad.

> You could even write a custom operator to sugar it.
>
>
```
infix operator ??? : NilCoalescingPrecedence
func ??? <T>(lhs: [Any?], rhs: @autoclosure () -> T) -> T? {
    for l in lhs {
        if l == nil { return nil }
    }
    return rhs()
}

var x: Int?
var y: Int?

(x, y) = (nil, nil)

[x, y] ??? x! * y!
// nil

(x, y) = (1, 2)

[x, y] ??? x! * y!
// Optional(2)
```


>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160815/43ba9834/attachment.html>


More information about the swift-evolution mailing list