Make distinction between ?? -> T and ?? -> T?


(Sébastien Blondiau) #1

Currently, there is only one nil coalescing operator, which may return an optional value or not, depending on the second parameter. This variability can leads to unclear line of code:

var isItOptionalOrNot = value ?? otherValue

I think there should be two distinct operators:

var certainlyOptional = value ?? otherValue
var certainlyNotOptional = value ?! notOptionalValue

In my point of view, this differentiation brings more clarity about wether the result is an optional or not.

What's your opinion?

···

--
Sébastien Blondiau


(David Waite) #2

I would assume ?! has the possibility of having an assert kill my application.

Is there a particular reason you are proposing this, such as a hard-to-diagnose bug?

-DW

···

On Mar 7, 2016, at 2:29 PM, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Currently, there is only one nil coalescing operator, which may return an optional value or not, depending on the second parameter. This variability can leads to unclear line of code:

var isItOptionalOrNot = value ?? otherValue

I think there should be two distinct operators:

var certainlyOptional = value ?? otherValue
var certainlyNotOptional = value ?! notOptionalValue

In my point of view, this differentiation brings more clarity about wether the result is an optional or not.

What's your opinion?

--
Sébastien Blondiau
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Radek Pietruszewski) #3

-1, never seen a real world situation where this would be confusing/problematic.

Having one operator is nice for chaining:

var value = someArray ?? someFallback ?? secondaryFallback ?? []

— Radek

···

On 07 Mar 2016, at 22:29, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Currently, there is only one nil coalescing operator, which may return an optional value or not, depending on the second parameter. This variability can leads to unclear line of code:

var isItOptionalOrNot = value ?? otherValue

I think there should be two distinct operators:

var certainlyOptional = value ?? otherValue
var certainlyNotOptional = value ?! notOptionalValue

In my point of view, this differentiation brings more clarity about wether the result is an optional or not.

What's your opinion?

--
Sébastien Blondiau
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pyry Jahkola) #4

Consider a parallel Swiftverse where the standard library only defined the following single overload of `??`:

infix operator ?? { associativity right precedence 131 }

func ?? <T>(x: T?, @autoclosure y: () -> T) -> T {
    if let x = x { return x } else { return y() }
}

With that defined, life went on and things worked just fine:

let some: Int? = 1
let none: Int? = nil
let one = some ?? 2 // = 1: Int
let two = none ?? 2 // = 2: Int
let ein = none ?? some ?? 3 // = 1: Int

(That last line, by the way, is equivalent to `none ?? (some ?? 3)` because of the right associativity.)

However, because of implicit optional wrapping, the following lines compiled as well:

let un = some ?? none // = Optional(1): Int?
let deux = 2 ?? none // = Optional(2): Int?
let rien = none ?? some // = nil: Int?

The reason was the compiler would Optional-wrap the left-hand side of `??` over and over again, until the argument pair met the shape `(T?, T)` for a type `T`, which happened to be `Int?` in this case:

some ?? none → Optional(some) ?? none
2 ?? none → Optional(Optional(2)) ?? none
none ?? some → Optional(none) ?? some

Don't you think the last line was especially surprising? Just a couple of lines up, the definition of `ein` looked almost identical:

let ein = none ?? some ?? 3 // = 1: Int
let rien = none ?? some // = nil: Int?

…yet with an entirely different result! Of course that's just because of associativity rules, but who remembered! So I guess in our world, the intention with the second overload `(T?, T?) -> T?` is beginner friendliness, and I can't argue against.

— Pyry

Epilogue: The parallel Swiftverse, however, went their own way and protected fellow swiftizens against indecision with:

enum Nope {}

@available(*, deprecated,
    message="Your unwrappingness gets nowhere less Optional. See?")
func ** <T>(x: T?, y: T?) -> Nope { fatalError("How embarrassing!") }

Who knows, maybe one day they went on and invented a way to turn that thing into a compiler error? Who knows.

The End.

···

On 07 Mar 2016, at 23:29, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

I think there should be two distinct operators:

var certainlyOptional = value ?? otherValue
var certainlyNotOptional = value ?! notOptionalValue


(Joe Groff) #5

This case could be handled by making `??` right-associative. In fact, I had originally implemented it that way. I don't recall why we changed it and added the extra overload; Jordan, do you recall?

-Joe

···

On Mar 7, 2016, at 2:26 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

-1, never seen a real world situation where this would be confusing/problematic.

Having one operator is nice for chaining:

var value = someArray ?? someFallback ?? secondaryFallback ?? []


(Jordan Rose) #6

'??' doesn't have to fold all the optionals. I consider that a feature and am happy we have it; others may disagree.

When there is a non-optional case at the end, the two versions are equivalent; they just build different intermediate closures.

(((someArray ?? someFallback) ?? secondaryFallback) ?? []) // left-associative
(someArray ?? (someFallback ?? (secondaryFallback ?? []))) // right-associative

If 'someFallback' is the first non-nil argument, then in both cases 'someArray' and 'someFallback' will be evaluated and 'secondaryFallback' and '[]' will not. With the left-associative version, we have to do extra tests for nil, but those will be optimized away when ?? is inlined. We also create more closure instances, but again we can probably optimize that away. With the right-associative version, we end up with nested closures instead, which may be harder to optimize…or may not be.

Jordan

···

On Mar 7, 2016, at 15:17, Joe Groff <jgroff@apple.com> wrote:

On Mar 7, 2016, at 2:26 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

-1, never seen a real world situation where this would be confusing/problematic.

Having one operator is nice for chaining:

var value = someArray ?? someFallback ?? secondaryFallback ?? []

This case could be handled by making `??` right-associative. In fact, I had originally implemented it that way. I don't recall why we changed it and added the extra overload; Jordan, do you recall?


(Ross O'Brien) #7

During the review of the proposal for a '??=' operator, one of the given
disadvantages was the confusion over the meaning of '??'. Since one of its
two meanings is that it nil-coalesces a chained expression into a
non-optional result, it might be misinterpreted that given the expression
'lhs ??= rhs' and a non-optional 'rhs', 'lhs' would no longer be optional.
'??' is an overloaded operator; unloading one of its two responsibilities
to a second operator would improve code clarity.

Radoslaw's example is simplistic because '[]' is unambiguously
non-optional. So let's replace it:

var value = someArray ?? someFallback ?? secondaryFallback ??
tertiaryFallback

Is 'value' optional or non-optional?

var value = someArray ?? someFallback ?? secondaryFallback ?!
tertiaryFallback

Now we can see immediately that 'value' is optional in the first case, and
non-optional in the second. However, since '!' is associated with
assertions, I agree that perhaps there's a better choice of operator for
this meaning.

···

On Mon, Mar 7, 2016 at 10:26 PM, Radosław Pietruszewski < swift-evolution@swift.org> wrote:

-1, never seen a real world situation where this would be
confusing/problematic.

Having one operator is nice for chaining:

var value = someArray ?? someFallback ?? secondaryFallback ?? []

— Radek

On 07 Mar 2016, at 22:29, Sébastien Blondiau via swift-evolution < > swift-evolution@swift.org> wrote:

Currently, there is only one nil coalescing operator, which may return an
optional value or not, depending on the second parameter. This variability
can leads to unclear line of code:

var isItOptionalOrNot = value ?? otherValue

I think there should be two distinct operators:

var certainlyOptional = value ?? otherValue
var certainlyNotOptional = value ?! notOptionalValue

In my point of view, this differentiation brings more clarity about wether
the result is an optional or not.

What's your opinion?

--
Sébastien Blondiau
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pyry Jahkola) #8

@available(*, deprecated,
    message="Your unwrappingness gets nowhere less Optional. See?")
func ** <T>(x: T?, y: T?) -> Nope { fatalError("How embarrassing!") }

This should be `func ??` of course. Used `**` in the playground when writing this, and failed at copy-paste-and-edit.


(Pyry Jahkola) #9

With the left-associative version, we have to do extra tests for nil, but those will be optimized away when ?? is inlined. We also create more closure instances, but again we can probably optimize that away. With the right-associative version, we end up with nested closures instead, which may be harder to optimize…or may not be.

FWIW, the current implementation is right-associative: https://github.com/apple/swift/blob/12b793c87f160a0f18bb8762e425174205c5d80a/stdlib/public/core/Policy.swift#L399


(Sébastien Blondiau) #10

The situation in which I found a little confusing that that was the same operator, was something like that:

func someFunction() -> T {
    
    var someValue: T
    
    /* some code */
    
    var value = someOptionalValue ?? someValue
    
    /* some code */
    
    return value
}

For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {
    
    var someValue: T?
    
    /* some code */
    
    var value = someOptionalValue ?? someValue
    
    /* some code */
    
    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}

In my point of view, the error was not at the return line but rather at the declaration of value. The existence of two operators would have forced me in the first case to use ?! to have value as a non optional, and would make the localisation of the error obvious.

The operator ?! have to have a lower precedence to return the non optional value after that ?? returned the optional one.
Having two operators would not prevent programmers from chaining. The case:

var value = someArray ?? someFallback ?? secondaryFallback ?? []

would just be replaced by:

var value = someArray ?? someFallback ?? secondaryFallback ?! []

Same changes would occur everywhere value is non optional. With these changes, I don't see any situation where code would be broken.

···

--
Sébastien Blondiau

Le 7 mars 2016 à 23:53, Ross O'Brien <narrativium+swift@gmail.com> a écrit :

During the review of the proposal for a '??=' operator, one of the given disadvantages was the confusion over the meaning of '??'. Since one of its two meanings is that it nil-coalesces a chained expression into a non-optional result, it might be misinterpreted that given the expression 'lhs ??= rhs' and a non-optional 'rhs', 'lhs' would no longer be optional. '??' is an overloaded operator; unloading one of its two responsibilities to a second operator would improve code clarity.

Radoslaw's example is simplistic because '[]' is unambiguously non-optional. So let's replace it:

var value = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback

Is 'value' optional or non-optional?

var value = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback

Now we can see immediately that 'value' is optional in the first case, and non-optional in the second. However, since '!' is associated with assertions, I agree that perhaps there's a better choice of operator for this meaning.

On Mon, Mar 7, 2016 at 10:26 PM, Radosław Pietruszewski <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
-1, never seen a real world situation where this would be confusing/problematic.

Having one operator is nice for chaining:

var value = someArray ?? someFallback ?? secondaryFallback ?? []

— Radek

On 07 Mar 2016, at 22:29, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Currently, there is only one nil coalescing operator, which may return an optional value or not, depending on the second parameter. This variability can leads to unclear line of code:

var isItOptionalOrNot = value ?? otherValue

I think there should be two distinct operators:

var certainlyOptional = value ?? otherValue
var certainlyNotOptional = value ?! notOptionalValue

In my point of view, this differentiation brings more clarity about wether the result is an optional or not.

What's your opinion?

--
Sébastien Blondiau
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Sébastien Blondiau) #11

Here is my proposal:

Distinction between ?? -> T? and ?? -> T

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#introduction>Introduction

The current nil coalescing operator can return an optional or not, depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#motivation>Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#proposed-solution>Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#detailed-design>Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#impact-on-existing-code>Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#alternatives-considered>Alternatives considered

There are currently no alternatives considered.

Thoughts?

···

--
Sébastien Blondiau


(Jordan Rose) #12

I forgot to mention it but I'm (also?) very much against adding a new operator with "!" in the name that won't ever trap. The "not" operator got pulled in from C, but every other use of "!" means "I am asserting I know more than the compiler does" (or perhaps more accurately "there is a precondition here that the compiler doesn't know about"). That includes !-to-unwrap, ImplicitlyUnwrappedOptional, 'as!', and 'try!'.

Jordan

···

On Mar 10, 2016, at 4:49 , Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Here is my proposal:

Distinction between ?? -> T? and ?? -> T

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#introduction>Introduction

The current nil coalescing operator can return an optional or not, depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#motivation>Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#proposed-solution>Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#detailed-design>Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#impact-on-existing-code>Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#alternatives-considered>Alternatives considered

There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Patrick Gili) #13

I'm very much against having two operators that essential do the same thing. This proposal sounds like something that will become a source of confusion, which is a bad direction for Swift.

-Patrick

···

On Mar 10, 2016, at 7:49 AM, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Here is my proposal:

Distinction between ?? -> T? and ?? -> T

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#introduction>Introduction

The current nil coalescing operator can return an optional or not, depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#motivation>Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#proposed-solution>Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#detailed-design>Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#impact-on-existing-code>Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#alternatives-considered>Alternatives considered

There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Shawn Erickson) #14

-1 on ?! since it doesn't trap like others uses of !
-1 on the need for this, the compiler won't let you do the wrong thing
here, yeah I understand that at a glance a human can't quickly tell however
the same thing happens things that return an option when assigned into a
var/let

···

On Thu, Mar 10, 2016 at 9:23 AM Jordan Rose via swift-evolution < swift-evolution@swift.org> wrote:

I forgot to mention it but I'm (also?) very much against adding a new
operator with "!" in the name that won't ever trap. The "not" operator got
pulled in from C, but every other use of "!" means "I am asserting I know
more than the compiler does" (or perhaps more accurately "there is a
*precondition* here that the compiler doesn't know about"). That includes
!-to-unwrap, ImplicitlyUnwrappedOptional, 'as!', and 'try!'.

Jordan

On Mar 10, 2016, at 4:49 , Sébastien Blondiau via swift-evolution < > swift-evolution@swift.org> wrote:

Here is my proposal:

Distinction between ?? -> T? and ?? -> T
<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#introduction>
Introduction

The current nil coalescing operator can return an optional or not,
depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#motivation>
Motivation

Currently, the only nil coalescing operator may return an optional value
or not. This variability can leads to unclear line of code:

var result = value ?? otherValue

where result may be an optional, and cannot be determined without looking
for the definition of otherValue.

A real situation where I found the unique operator confusing was something
like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}

For some reasons, I had to consider a new case where someValue had to be
an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}

In my situation, the error was not at the return line but rather at the
declaration of value. value was non optional in the first code and
implicitly became optional in the second code.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#proposed-solution>Proposed
solution

A new operator ?! , which take a non optional second parameter and return
a non optional value. This new operator replaces the current ?? which
return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality
var value = someOptionalValue ?! someValue // value is not optional// but if someValue is optional then this produces an error

The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallbackvar nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#detailed-design>Detailed
design

Under this proposal, the ?! operator has a lower precedence than ?? to
have the described form of chaining: the operator ?! returns a non
optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }
+infix operator ?! { precedence 130 }

The ?! operator is non associative to avoid bad usages, which would lose
some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback

Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T

The internal implementation do not need to change.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#impact-on-existing-code>Impact
on existing code

This proposal will impact every code using the nil coalesing operator to
get a non optional value.

The migration can be done automatically by replacing all ?? which
currently return non optional value.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#alternatives-considered>Alternatives
considered
There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Sweeris) #15

-1, for the reasons mentioned by everyone else.

- Dave Sweeris

···

On Mar 10, 2016, at 6:49 AM, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Here is my proposal:

Distinction between ?? -> T? and ?? -> T

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#introduction>Introduction

The current nil coalescing operator can return an optional or not, depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#motivation>Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#proposed-solution>Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#detailed-design>Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#impact-on-existing-code>Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#alternatives-considered>Alternatives considered

There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Sébastien Blondiau) #16

Thank's for your feedbacks.

I have to agree with you that ! is associated with assertion, an other name is indeed required (maybe ?. or anything else).

In opposition to what Patrick said, the interest of the new operator was avoid the confusion which exists between the two functions of ?? (one which returns an optional, the other which returns a non optional). This confusion has been proofed during the review of the proposal about the ??= operator.

I understand that this proposal only offers some human readability and does not prevent from errors which are not caught by the compiler, so is not really important.


(Thorsten Seitz) #17

I agree with Shawn an Jordan.
-1 to the proposal.

-Thorsten

···

Am 10.03.2016 um 18:29 schrieb Shawn Erickson via swift-evolution <swift-evolution@swift.org>:

-1 on ?! since it doesn't trap like others uses of !
-1 on the need for this, the compiler won't let you do the wrong thing here, yeah I understand that at a glance a human can't quickly tell however the same thing happens things that return an option when assigned into a var/let

On Thu, Mar 10, 2016 at 9:23 AM Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:
I forgot to mention it but I'm (also?) very much against adding a new operator with "!" in the name that won't ever trap. The "not" operator got pulled in from C, but every other use of "!" means "I am asserting I know more than the compiler does" (or perhaps more accurately "there is a precondition here that the compiler doesn't know about"). That includes !-to-unwrap, ImplicitlyUnwrappedOptional, 'as!', and 'try!'.

Jordan

On Mar 10, 2016, at 4:49 , Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Here is my proposal:

Distinction between ?? -> T? and ?? -> T
Introduction

The current nil coalescing operator can return an optional or not, depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

Alternatives considered

There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Hooman Mehr) #18

Here is what I do:

I have this function:

  func nilCrash<T>(message: String = "") -> T { preconditionFailure(message) }

Sometimes I have a bunch of optionals, but I assert at least one of them is not `nil` using the above:

  let value = optional1 ?? optional2 ?? optional3 ?? nilCrash()

A beneficial side effect is that the type of `value` does not become optional.

An alternative would be:

  let value = optional1 ?? optional2 ?? optional3!

With the same effect: Non-optional `value` type. So:

-1. It is not worth it.

···

On Mar 11, 2016, at 11:27 AM, Dave via swift-evolution <swift-evolution@swift.org> wrote:

-1, for the reasons mentioned by everyone else.

- Dave Sweeris

On Mar 10, 2016, at 6:49 AM, Sébastien Blondiau via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Here is my proposal:

Distinction between ?? -> T? and ?? -> T

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#introduction>Introduction

The current nil coalescing operator can return an optional or not, depending on the second parameter.

The prosposed solution is the use of two distinct operators: ?? and ?!.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#motivation>Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#proposed-solution>Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#detailed-design>Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#impact-on-existing-code>Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

<https://github.com/HyperSeb/nil-coalescing-operator/tree/master#alternatives-considered>Alternatives considered

There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Step C) #19

-1.

Jordan explained the meaning of ! In Swift. For those reasons "?!" Does not work as an operator for non-optional.

But further, optionals work in Swift by providing just enough explicitness without too much friction. This operator makes a distinction that is not sufficiently valuable beyond what the type system already provides. Comments below on the example.

-1 on ?! since it doesn't trap like others uses of !
-1 on the need for this, the compiler won't let you do the wrong thing here, yeah I understand that at a glance a human can't quickly tell however the same thing happens things that return an option when assigned into a var/let

I forgot to mention it but I'm (also?) very much against adding a new operator with "!" in the name that won't ever trap. The "not" operator got pulled in from C, but every other use of "!" means "I am asserting I know more than the compiler does" (or perhaps more accurately "there is a precondition here that the compiler doesn't know about"). That includes !-to-unwrap, ImplicitlyUnwrappedOptional, 'as!', and 'try!'.

Jordan

Here is my proposal:

Distinction between ?? -> T? and ?? -> T

Snip

Motivation

Currently, the only nil coalescing operator may return an optional value or not. This variability can leads to unclear line of code:

var result = value ?? otherValue
where result may be an optional, and cannot be determined without looking for the definition of otherValue.

A real situation where I found the unique operator confusing was something like that:

func someFunction() -> T {

    var someValue: T

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value
}
For some reasons, I had to consider a new case where someValue had to be an optional

func someFunction() -> T {

    var someValue: T?

    /* some code */

    var value = someOptionalValue ?? someValue

    /* some code */

    return value // error: value of optional type 'T?' not unwrapped; did you mean to use '!'
}
In my situation, the error was not at the return line but rather at the declaration of value. value was non optional in the first code and implicitly became optional in the second code.

But the type system gave you an error. Easy enough to find where the optional is coming from, and not unreasonable that the compiler can't tell which bit of this logic was the incorrect part. I think this is essential complexity, the price we pay (of having optionals and having to reason about them) is worth it and unavoidable for the benefit of having this method as it was originally - with no optional values.

(End of my reply)

···

Am 10.03.2016 um 18:29 schrieb Shawn Erickson via swift-evolution <swift-evolution@swift.org>:

On Thu, Mar 10, 2016 at 9:23 AM Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 10, 2016, at 4:49 , Sébastien Blondiau via swift-evolution <swift-evolution@swift.org> wrote:

Proposed solution

A new operator ?! , which take a non optional second parameter and return a non optional value. This new operator replaces the current ?? which return a non optional.

This ensures the programmer knows if whether the value is optional or not:

var value = someOptionalValue ?? someValue // value is optional, without depending on someValue optionality

var value = someOptionalValue ?! someValue // value is not optional
// but if someValue is optional then this produces an error
The nil coalescing chaining benefits the same clarity:

var optionalValue = someArray ?? someFallback ?? secondaryFallback ?? tertiaryFallback
var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Detailed design

Under this proposal, the ?! operator has a lower precedence than ?? to have the described form of chaining: the operator ?! returns a non optional after that ?? has returned an optional.

infix operator ?? { associativity right precedence 131 }

+infix operator ?! { precedence 130 }
The ?! operator is non associative to avoid bad usages, which would lose some interest of the new operator:

-var nonOptionalValue = someArray ?! someFallback ?! secondaryFallback ?! tertiaryFallback
+var nonOptionalValue = someArray ?? someFallback ?? secondaryFallback ?! tertiaryFallback
Only the function ?? which returns a non optional is replaced:

-public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
+public func ?!<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T
The internal implementation do not need to change.

Impact on existing code

This proposal will impact every code using the nil coalesing operator to get a non optional value.

The migration can be done automatically by replacing all ?? which currently return non optional value.

Alternatives considered

There are currently no alternatives considered.

Thoughts?

--
Sébastien Blondiau

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution