> On Jun 29, 2017, at 1:05 AM, David Hart via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> I’ve taken time to digest all the messages on this discussion and would like 
> to summarise my point of view concerning several topics:
> 
> Usefulness of messages
> 
> Xiaodi seems to question the usefulness of attaching more information to the 
> failure case of an optional's unwrapping. To his credit, the original example 
> ("Array guaranteed non-empty") don’t add much. Instead, I think we should see 
> those strings as a great opportunity to add application-specific business 
> logic context that help debugging when the unwrapping fails. For example, 
> let’s imagine that I am handling the log out operation for a user I know 
> exists, I could write this:
> 
> let user = database.users[userId] !! “User to logout does not exist”

To expand on the usefulness of these messages, here’re some scattered examples 
of how I’ve been using this operator in an app I work on, pulled from various 
parts of the code:

// in a right-click gesture recognizer action handler
let event = NSApp.currentEvent !! "Trying to get current event for right click, 
but there's no event”

// in a custom view controller subclass that only accepts children of a certain 
kind:
let existing = childViewControllers as? Array<TableRowViewController> !! 
"TableViewController must only have TableRowViewControllers as children"

// providing a value based on an initializer that returns an optional:
lazy var emptyURL: URL = { return URL(string: “myapp://section/\(identifier)") 
!! "can't create basic empty url” }()

// retrieving an image from an embedded framework:
    private static let addImage: NSImage = {
        let bundle = Bundle(for: FlagViewController.self)
        let image = bundle.image(forResource: "add") !! "Missing 'add' image"
        image.isTemplate = true
        return image
    }()

// asserting consistency of an internal model
let flag = command.flag(with: flagID) !! "Unable to retrieve non-custom flag 
for id \(flagID.string)"

My usage of “!!” generally falls in to two big buckets:

1. Asserting system framework correctness

        For example, the “NSApp.currentEvent” property returns an 
Optional<NSEvent>, because there’s not always a current event going on. That’s 
fine. But when I’m in the action handler of a right-click gesture recognizer it 
is safe to assert that I do have an event. If this ever fails, I have an 
immediately clear description of where the system framework has not worked 
according to my expectations.

2. Asserting app logic correctness

        For example, I use this to assert that my outlets are properly hooked 
up (and the message tells me explicitly which outlet I’ve forgotten), or that 
my internal data model is in a consistent state.

Both areas of usage have been extremely helpful in building my app. They help 
me identify when I forget to put resources in the right target, or when I make 
changes to the internal model but forget all the places I’m supposed to insert 
things. They help me catch when I fat-finger a URL.

Yes, I could absolutely have done all of this with just a bare unwrap operator, 
but by putting the diagnostic message in there, I get immediate feedback as to 
why my code is failing. I don’t have to go digging around in the code in order 
to re-teach myself of what invariants are supposed to be held, because the 
error message gives me the succinct and immediately-actionable thing to do.

> Never and new operator
> 
> If we introduce the new operator !! solely with the String override, I still 
> have some doubts about it pulling its own weight. Of course, we could add a 
> () -> Never override to increase its usefulness:
> 
> let user = database.users[userId] !! “User to logout does not exist”
> let user = database.users[userId] !! logFatalError(“User to logout does not 
> exist”)

As I demonstrate above even just the string version can be extremely helpful.

> But Jaden Geller makes a very good point: if and once Never becomes a true 
> bottom type, that syntax will be redundant because Never will be usable with 
> the ?? operator, creating a lot of confusion:
> 
> let user = database.users[userId] !! logFatalError(“User to logout does not 
> exist”)
> let user = database.users[userId] ?? logFatalError(“User to logout does not 
> exist”)

Maybe the answer then is to add !! for strings, and then use ?? If you have a 
custom Never function.

> Those two lines will have exactly the same effect.
> 
> Cognitive Dissonance of Never and ??
> 
> Ben Cohen originally mentioned that if we introduce a () -> Never overload of 
> the ?? operator, there will be cognitive dissonance because the question mark 
> operator is never used in Swift to signal a trap. But if we make Never a true 
> bottom type, which has a lot of advantages, this dissonance will be 
> unavoidable. Shouldn’t we embrace it then?
> 
> Potential for confusion with multiple per line
> 
> This might not be a real concern, but are we introducing a syntax that will 
> make it possible/encourage people to write less than readable code?
> 
> let user = (database !! “Database is not operational”).users[userId !! “User 
> was not set in time”] !! “User to logout does not exist"

IMO, this is a bit of a red herring, because you can already write similarly 
atrocious code in Swift today. The addition of “!!” wouldn’t really change that.

Cheers,

Dave

> David.
> 
>> On 28 Jun 2017, at 22:30, Erica Sadun via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> Based on the feedback on this thread, I'm coming to the following 
>> conclusions:
>> 
>> `!!` sends the right semantic message. "Unwrap or die" is an unsafe 
>> operation. It is based on `!`, the unsafe forced unwrap operator, and not on 
>> `??`, the safe fallback nil-coalescing operator. Its symbology should 
>> therefore follow `!` and not `?`. 
>> 
>> The `!!` operator should follow the same semantics as 
>> `Optional.unsafelyUnwrapped`, which establishes a precedent for this 
>> approach:
>> 
>> > "The unsafelyUnwrapped property provides the same value as the forced 
>> > unwrap operator (postfix !). However, in optimized builds (-O), no check 
>> > is performed to ensure that the current instance actually has a value. 
>> > Accessing this property in the case of a nil value is a serious 
>> > programming error and could lead to undefined behavior or a runtime error."
>> 
>> By following `Optional.unsafelyUnwrapped`, this approach is consistent with 
>> https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst#logic-failures
>>  
>> <https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst#logic-failures>
>> 
>> > "Logic failures are intended to be handled by fixing the code. It means 
>> > checks of logic failures can be removed if the code is tested enough.
>> Actually checks of logic failures for various operations, `!`, `array[i]`, 
>> `&+` and so on, are designed and implemented to be removed
>> when we use `-Ounchecked`. It is useful for heavy computation like image 
>> processing and machine learning in which overhead of those checks is not 
>> permissible."
>> 
>> The right hand side should use a string (or more properly a string 
>> autoclosure) in preference to using a `Never` bottom type or a `() -> Never` 
>> closure. A string provides the cleanest user experience, and allows the 
>> greatest degree of self-documentation. 
>> 
>> - A string is cleaner and more readable to type. It respects DRY, and avoids 
>> using *both* the operator and the call to `fatalError` or 
>> `preconditionFailure` to signal an unsafe condition:
>> `let last = array.last !! “Array guaranteed non-empty" // readable`
>> than: 
>> `let last = array.last !! fatalError(“Array guaranteed non-empty”) // 
>> redundant, violates DRY`
>> 
>> - A string allows the operator *itself* to unsafely fail, just as the unary 
>> version of `!` does now. It does this with additional feedback to the 
>> developer during testing, code reading, and code maintenance. The string 
>> provides a self-auditing in-line annotation of the reason why the forced 
>> unwrap has been well considered, using a language construct to support this.
>> 
>> - A string disallows a potentially unsafe `Never` call that does not reflect 
>> a serious programming error, for example:
>> let last = array.last !! f() // where func f() -> Never { while true {} }
>> 
>> - Although as several list members mention, a `Never` closure solution is 
>> available today in Swift, so is the `!!` operator solution. Neither one 
>> requires a fundamental change to the language.
>> 
>> - Pushing forward on this proposal does not in any way reflect on adopting 
>> the still-desirable `Never` bottom type.
>> 
>>> On Jun 28, 2017, at 12:42 PM, Tony Allevato via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> 
>>> 
>>> On Wed, Jun 28, 2017 at 11:15 AM Dave DeLong <del...@apple.com 
>>> <mailto:del...@apple.com>> wrote:
>>>> On Jun 28, 2017, at 10:44 AM, Adrian Zubarev via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> Well the main debate is that, we all want early access to a feature that 
>>>> will be part of Swift as soon as `Never` becomes the bottom type. When 
>>>> this happens the `??` will automatically support the pitched behavior. 
>>>> Until then if we all agree that we should add it now in a way that will 
>>>> not break anything we can simply add an overload to `??` as I previously 
>>>> showed.
>>>> 
>>> 
>>> I believe we should add it now, but I like the recent observation that 
>>> making ?? suddenly become a potentially crashing operator violates the 
>>> expectation that ? is an indication of safety.
>>> 
>>> ?? does *not* become a potentially crashing operator. The *fatalError* (or 
>>> whatever else the user chooses to put there) on the right-hand side is the 
>>> crashing operation.
>>> 
>>> 
>>> On the other hand, the existing semantics of Swift are that ! is always 
>>> dangerous, so making !! be the a potentially crashing operator is much more 
>>> consistent with the language.
>>> 
>>>> There is no need for `!!` because it will fade in the future. If you think 
>>>> of `Never` as a bottom type now then `??` will already make total sense. 
>>>> The default value for T from rhs might be T or Never. 
>>> 
>>> I respectfully disagree with your absolute position on this topic. Even 
>>> with Never as a bottom type in the future, it would still be more 
>>> convenient for me to type:
>>> 
>>> let last = array.last !! “Array must be non-empty"
>>> 
>>> … than it ever would be to type:
>>> 
>>> let last = array.last ?? fatalError(“Array must be non-empty”)
>>> 
>>> 
>>> There is a very high bar for additions to the standard library—a new 
>>> operator added to the language is going to be around (1) forever, or (2) 
>>> indefinitely with some migration cost to users if it's ever removed. 
>>> Shaving off a few keystrokes doesn't quite meet that bar—especially when an 
>>> alternative has been shown to work already that provides the same 
>>> functionality, is more general (not coupled to fatalError or String 
>>> messages), and that fits better into Swift's design.
>>> 
>>> 
>>> To make sure I'm not being too much of a downer, I would completely support 
>>> this broader feature being implemented by that alternative: the ?? + 
>>> autoclosure () -> Never combo. Then once Never does become a true bottom 
>>> type, I believe it could be removed and the calling code would still *just 
>>> work*.
>>> 
>>>  
>>> Dave
>>> 
>>>> 
>>>> @erica: the rhs argument should be called something like `noreturnOrError` 
>>>> and not `defaultValue`. And we should keep in mind that when Never becomes 
>>>> the bottom type we have to remove that overload from stdlib, because 
>>>> otherwise it will be ambiguous. 
>>>> 
>>>> ---
>>>> 
>>>> On the other hand if we tackle a different operator then we should rething 
>>>> the 'default value operator' because the second ? signals an optional but 
>>>> not a non-optional or an inplicit unwrapped operator. In that case I 
>>>> personally thing ?! would make more sense. Unwrap or (non-optional | IUO | 
>>>> trap/die)
>>>> 
>>>> -- 
>>>> Adrian Zubarev
>>>> Sent with Airmail
>>>> Am 28. Juni 2017 um 18:13:18, Tony Allevato via swift-evolution 
>>>> (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) schrieb:
>>>> 
>>>>> It's hard for me to articulate, but "foo !! message" feels a little too 
>>>>> much like a Perl-ism for my taste. Objectively that's not a great 
>>>>> criticism on its own, but I just don't like the "smell" of an operator 
>>>>> that takes a value on one side and a string for error reporting purposes 
>>>>> on the other. It doesn't feel like it fits the style of Swift. I prefer a 
>>>>> version that makes the call to fatalError (and thus, any other 
>>>>> non-returning handler) explicitly written out in code.
>>>>> 
>>>>> So, if the language can already support this with ?? and 
>>>>> autoclosure/Never as was shown above, I'd rather see that added to the 
>>>>> language instead of a new operator that does the same thing (and is 
>>>>> actually less general).
>>>>> 
>>>>> On Wed, Jun 28, 2017 at 8:52 AM Jacob Williams via swift-evolution 
>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>> I feel that the !! operator would be necessary for indicating that if 
>>>>> this fails then something went horribly wrong somewhere and we should 
>>>>> throw the fatalError. This allows the inclusion of optimizations using 
>>>>> -Ounchecked and is clear that this is an operation that could result in a 
>>>>> runtime error just like force unwrapping.
>>>>> 
>>>>> If we want code clarity and uniformity, then I think !! Is much better 
>>>>> than ?? because it goes right along with the single ! Used for force 
>>>>> unwrapping. However, this does depend on if the operator would be 
>>>>> returning some kind of error that would cause the program to exit.
>>>>> 
>>>>> I think the ?? operator should not cause a program to exit early. It goes 
>>>>> against optional unwrapping principles. I think code could get very 
>>>>> confusing if some ? would return nil/a default value, and others would be 
>>>>> causing your program to crash and exit. The ? operators should always be 
>>>>> classified as safe operations.
>>>>> 
>>>>>> On Jun 28, 2017, at 9:41 AM, Ben Cohen via swift-evolution 
>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>>> 
>>>>>> 
>>>>>>> On Jun 28, 2017, at 8:27 AM, David Hart via swift-evolution 
>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>>>> 
>>>>>>> Count me in as a strong proponent of ?? () -> Never. We don't need to 
>>>>>>> burden the language with an extra operator just for that.
>>>>>> 
>>>>>> You could say the same about ??
>>>>>> 
>>>>>> The concern that an additional operator (and one that, IMO, fits well 
>>>>>> into existing patterns) is so burdensome seems way overweighted in this 
>>>>>> discussion IMO. 
>>>>>> 
>>>>>> Adding the operator, and encouraging its use, will help foster better 
>>>>>> understanding of optionals and legitimate use of force-unwrapping in a 
>>>>>> way that I don’t think `?? fatalError` could.
>>>>>> 
>>>>>> 
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>>> <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 
>>>>> <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 
>>>>> <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 
>>>> <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 
>>> <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
> 
> _______________________________________________
> 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

Reply via email to