[swift-evolution] Proposal: Allow Type Annotations on Throws

David Owens II david at owensd.io
Mon Dec 21 15:00:48 CST 2015


> I understand that Rust is not doing implicit conversions, but the effect for the user is pretty much the same.  The try macro is converting the underlying error to the type that can be propagated.  As I stated, Swift is not Rust and deserves a different solution.  
> 
> Nevertheless, that does not minimize the need to solve the problem.  I maintain that the problem solved by the try macro is a significant one that is not addressed by the current proposal.  I would really like to see it addressed one way or another.
> 
>> 
>> You could make it “nicer” by doing something like this:
>> 
>> try MyError.convertFrom(try funcThatThrowsAnErrorThatMustBeTranslatedItoMyPublishedError())
> 
> Can you elaborate on how you think this would work?  If funcThatThrowsAnErrorThatMustBeTranslatedItoMyPublishedError actually throws it will be propagated to the next enclosing catch clause.  MyError.convertFrom will not have a chance to do anything with it.

Here’s a full playground example (I’ve annotated in comments where the type of error could be described):

enum InternalError: ErrorType {
    case Internal(value: Int)
}

enum PublishedError: ErrorType {
    static func from<T>(@autoclosure fn: () throws -> T) throws -> T {
        do {
            return try fn()
        }
        catch InternalError.Internal(let value) {
            throw PublishedError.Converted(value: value)
        }
        catch {
            fatalError("unsupported conversion")
        }
    }
    
    case Converted(value: Int)
}


func example() {

    func bad(value: Int) throws /* InternalError */ -> Int {
        if value % 2 == 0 { throw InternalError.Internal(value: value) }
        return value
    }

    func verbose(value: Int) throws /* PublishedError */ -> Int {
        do {
            return try bad(value)
        }
        catch InternalError.Internal(let value) {
            throw PublishedError.Converted(value: value)
        }
        catch {
            fatalError("unsupported conversion")
        }
    }
    
    func convert(value: Int) throws /* PublishedError */ -> Int {
        return try PublishedError.from(try bad(value))
    }
    
    do {
        let r1 = try verbose(11)
        print("verbose: \(r1)")
        
        let r2 = try convert(9)
        print("converted: \(r2)")
    }
    catch {
        print("error: \(error)")
    }

}

example()


As you can see, the “verbose()” and the “from()” conversion are basically the same implementation. What I’m saying is that I believe you can simply do the explicit conversion yourself without much fanfare (compare the verbose() and convert() implementations).

In the implementation of PublishedError.from() you can use Swift’s pattern matching to do all of your conversions in a single place. Note that where the implementation of “from” is at doesn’t matter, it could be on another type or a free function, whatever.

> Are you willing to explore adding *explicit* syntax to convert thrown errors to your proposal?  That seems like it might be a reasonable compromise between implicit conversions and manual boilerplate.  

The only boiler plate I’m seeing is the explicit conversion call: PublishedError.from(try bad(value))

Am I misunderstanding something? 

To me, this would be much more confusing:

    func convert(value: Int) throws /* PublishedError */ -> Int {
        return try bad(value)     /* implicit conversion from InternalError -> PublishedError */
    }

If there were implicit type conversions, this would have to be something that Swift supported all up. I’d be very hesitant to make this work for only errors. For example, how does implicit conversion work if we can later extend this to async behaviors? Do we have special conversions that can take an async error make it a synchronous error? How about vice-versa?

I guess I wouldn’t want to go further than having explicit conversions until we better understood all of those answers and how implicit type conversion would work in Swift generally. If I recall, Swift had implicit type conversion in the early versions, and it has been removed in most places. 

-David

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151221/5f4b8346/attachment.html>


More information about the swift-evolution mailing list