> On Apr 30, 2017, at 9:29 PM, Robert Widmann <[email protected]> wrote:
> 
> 
>> On Apr 30, 2017, at 1:43 PM, Gor Gyolchanyan <[email protected]> wrote:
>> 
>> It doesn’t have to be a massive source-break, since this pitch is supposed 
>> to be a strict superset of what Optional and throwing is currently.
>> The only thing that I can think of at this moment that would break is this 
>> syntax:
>> 
>> let foo: Int? = .none // Error: Can’t convert (Error) -> Int? to Int?
>> 
> 
> Except it’s not a strict superset if you break every use of this case as an 
> RValue.  Especially when so much of Swift’s syntax and major patterns revolve 
> around the manipulation of optionals.
> 
>> The ExpressibleByNilLiteral, the try/throw syntax, all of those things would 
>> work as they are right now.
>> Error handling as it is currently, is essentially a hidden `error` out 
>> parameter and a whole bunch of codegen.
>> Even the semantical changes described earlier would be purely additive.
> 
> Don’t get me wrong, I think you’ve identified the problem space well, I just 
> disagree with the solution.

Yeah, you’re right. It would take some next-level fixits to deal with the 
consequences of changing the most fundamental data type of Swift I can think of.
I’d really appreciate it if you’d offer an alternative solution to this problem.
The problem, as I understand it, is as follows:

A lot of Swift’s logic revolves around the notion that some values might be 
missing for whatever reason and some functions might fail for whatever reason.
Any function’s effect can be summed up as the union of its return value and the 
global state that it changes (that includes captured closure scopes).
This could be boiled down to the statement that “Values that a function sets 
and returns completely express the purpose of the function”.
The optional gives an extremely convenient way of representing values that 
might not exist (which, when returned from a function often means “failed for 
an unknown reason”).
The fact that Optional is a type, rather then a function attribute allows us to 
store and imperatively manipulate the outcome of logically failable functions, 
but unfortunately, it doesn’t allow us to reason about the cause of the failure.
On the other hand, throwing functions captures the logic of dealing with 
specific failures very well, but does not allow us to store and manipulate them 
easily, leaving us with workarounds like wrapping errors in enums with values 
and re-throwing the errors on their way out of the generic pipeline.
I’d like to come up with a solution that would unify the optionals and the 
throwing functions into a single mechanism for dealing with the concept of 
failure, taking the best of both worlds and getting the benefits of the new 
synergies.
This pitch was a first rough idea about the direction in which we could go in 
trying to find a solution.
I chose to enhance Optional instead of introducing a new type like Failable, so 
that we could make do with minimal language changes and migration procedures.

This problem is kinda similar to the variadic parameter problem, which makes it 
impossible to forward calls to variadic functions simply because that feature 
is too magical and does not provide a way to store and propagate its logic.

Another way I could think of solving it would be to allow overloading the 
postfix `!` and `?` operators (which would currently only be defined for 
Optionals), which would allow us to define the Failable enum type with some 
error handling syntax integration and make it feel more at home in the midst of 
Optionals.

Or better yet, make an OptionalProtocol and move the current magical logic to 
it, leaving the existing Optional perfectly intact and allowing userspace 
implementations.
This would also greatly benefit numerous use cases of “invalidatable” types 
(like file handlers that can be closed) that would no longer have to either 
fatalError or use unwieldy wrappers that operate on Optionals.

> ~Robert Widmann
> 
>> 
>>> On Apr 30, 2017, at 8:35 PM, Robert Widmann <[email protected]> 
>>> wrote:
>>> 
>>> This "revamp" is isomorphic to adding a Sum type to stdlib and plumbing 
>>> error handling syntax through.  I'd much rather see that than the massive 
>>> source-break this would entail.
>>> 
>>> ~Robert Widmann
>>> 
>>> 2017/04/30 13:11、Gor Gyolchanyan via swift-evolution 
>>> <[email protected]> のメッセージ:
>>> 
>>>> I’d like to suggest a bit of redesigning the Optional type and throwing 
>>>> functions to provide a single powerful and flexible mechanism for dealing 
>>>> with unexpected situations.
>>>> 
>>>> In short, The Optional would have an associated value of type Error added 
>>>> to its `none` case, which would describe the reason why the wrapped value 
>>>> is missing.
>>>> 
>>>> public enum Optional<Wrapped> {
>>>> 
>>>> case .some(Wrapped)
>>>> 
>>>> case .none(Error)
>>>> 
>>>> }
>>>> 
>>>> The Optional's ExpressibleByNilLiteral would initialize it with an error 
>>>> that corresponds to what is currently fatalError-ed as "unexpectedly found 
>>>> nil while unwrapping an Optional value".
>>>> 
>>>> The forced unwrapping operator (postfix `!`) would behave the same way as 
>>>> it does now, except in case of a fatal error it would print out the 
>>>> underlying error, instead of the aforementioned hard-coded string.
>>>> 
>>>> The optional chaining operator (postfix `?`) would behave the same way as 
>>>> it does now, except when it stops evaluating and returns the Optional, it 
>>>> would contain the error, returned by the sub-expression that failed to 
>>>> evaluate.
>>>> 
>>>> Any throwing function would be equivalent to a function that returns an 
>>>> Optional. If the function is declared as throwing and returning an 
>>>> Optional at the same time, it would be equivalent to a function returning 
>>>> an Optional Optional.
>>>> 
>>>> The if-let statement would bind the `let` variable to the wrapped value 
>>>> inside the "then" block and would bind it to the error in the "else" 
>>>> block. Chained else-if blocks would all be considered part of the 
>>>> overarching "else" block, so all of them would be able to access the error 
>>>> bound to the if-let name.
>>>> 
>>>> The guard-let and case-let statements are essentially just rewrites of 
>>>> if-let with some added logic.
>>>> 
>>>> The `try` keyword, applied to an optional would behave like this:
>>>> 
>>>> public func try<T>(_ optional: T?) throws -> T {
>>>> guard let wrapped = optional else {
>>>>     throw wrapped // Remember, if-let, guard-let and case-let statements 
>>>> bind the let name to the error in case of a failure.
>>>> }
>>>> return wrapped
>>>> }
>>>> 
>>>> Multiple let bindings in a single if-let statement are essentially 
>>>> rewrites of a nested chain of if-let statements.
>>>> 
>>>> The `try` keyword applied to an optional would unwrap the value or throw 
>>>> the error.
>>>> The `try?` keyword applied to a throwing function call would cause any 
>>>> thrown errors to be caught and put into the returned Optional, instead of 
>>>> simply ignored.
>>>> The `try!` keyword applied to a throwing function call would behave as 
>>>> you'd expect: just like `try?` except immediately force-unwrapped.
>>>> 
>>>> A throwing function would be convertible to a non-throwing 
>>>> optional-returning function and vice versa.
>>>> This would allow making use of throwing functions when dealing with 
>>>> generics or protocols that allow arbitrary return types, without having to 
>>>> sacrifice the convenience of error-handling logic. Conversely, it would 
>>>> allow to write generic code that deals with any type of function without 
>>>> having to implement special cases for throwing functions. This means that 
>>>> the two function types would be interchangeable and one would be able to 
>>>> satisfy protocol requirements of the other. The `rethrows` idiom would 
>>>> then become a natural consequence of writing generic functions that may 
>>>> return optional and non-optional results just as well.
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> [email protected]
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to