> On Oct 11, 2016, at 8:51 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
> On Tue, Oct 11, 2016 at 8:21 PM, Charles Srstka via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> On Oct 11, 2016, at 4:42 PM, Braeden Profile via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> enum RectSize
>> {
>>    let height:Int
>>    let width:Int
>>    case small(width: 30, height: 30)
>>    case medium(width: 60, height: 60)
>>    case large(width: 120, height: 120)
>> }
> 
> I like the concept, but this doesn’t seem as flexible as it could be, and 
> could get ugly when mixing these defaults with enum associated values. How 
> about dynamic properties instead? Something like:
> 
> enum RectSize {
>       var height: Int { get }
>       var width: Int { get }
> 
>       case small {
>               height { return 30 }
>               width { return 30 }
>       }
> 
>       case medium {
>               height { return 60 }
>               width { return 60 }
>       }
> 
>       case large {
>               height { return 120 }
>               width { return 120 }
>       }
> 
>       case custom(width: Int, height: Int) {
>               height { return height }
>               width { return width }
>       }
> }
> 
> I'd be interested in expanding raw values to accommodate other types, but 
> computed properties are already possible:
> 
> ```
> enum RectSize {
>     case small, medium, large
> 
>     var height: Int {
>         switch self {
>         case .small:
>             return 30
>         case .medium:
>             return 60
>         case .large:
>             return 120
>         }
>     }
>     
>     var width: Int {
>         return height
>     }
> } 
> ```
> 
> There have been off-and-on proposals to change the syntax from what it is 
> currently, but none have been deemed a significant enough advantage to merit 
> a change--even before source-breaking changes in Swift 3 were over. Keeping 
> in mind that sugar is the lowest priority for Swift 4 (and not in scope for 
> the current phase), what's the advantage of your proposed syntax for computed 
> properties over the existing one?

It’s *possible*, but the syntax is incredibly verbose, unwieldy, and ugly. 
Imagine an enum with lots of cases and lots of properties—and before you say 
this is contrived, this already currently happens quite a lot with error enums 
(pardon the badly written error messages; this is only for example):

enum FileError: Error, LocalizedError {
    case notFound(url: URL)
    case accessDenied(url: URL)
    case incorrectFormat(url: URL)
    case ioError(url: URL)
    // ... imagine there are another 20 or so of these ...
    
    // Now, implement LocalizedError:
    
    var errorDescription: String? {
        switch self {
        case let .notFound(url: url):
            return "Could not access the file \(url.lastPathComponent) because 
it could not be found."
        case let .accessDenied(url: url):
            return "Could not access the file \(url.lastPathComponent) because 
access was denied."
        case let .incorrectFormat(url: url):
            return "Could not access the file \(url.lastPathComponent) because 
it was not in the expected format."
        case let .ioError(url: url):
            return "Could not access the file \(url.lastPathComponent) because 
an I/O error occurred."
        // ... etc ...
        }
    }
    
    var failureReason: String? {
        switch self {
        case let .notFound(url: url):
            return "The file \(url.lastPathComponent) could not be found."
        case let .accessDenied(url: url):
            return "We do not have permission to view the file 
\(url.lastPathComponent)"
        case let .incorrectFormat(url: url):
            return "The file \(url.lastPathComponent) was not in the expected 
format."
        case let .ioError(url: url):
            return "An I/O error occurred while accessing the file 
\(url.lastPathComponent)."
        // ... etc ...
        }
    }
    
    var recoverySuggestion: String? {
        switch self {
        case .notFound:
            return "Please locate the correct file and try again."
        case .accessDenied:
            return "You can change the file's permissions using the Finder's 
Get Info window."
        case .incorrectFormat:
            return "The file may have become corrupt."
        case .ioError:
            return "Dear Lord, the hard drive may be failing."
        // ... etc ...
        }
    }
    
    var helpAnchor: String? {
        switch self {
        case .notFound:
            return "notFound"
        case .accessDenied:
            return "accessDenied"
        case .incorrectFormat:
            return "incorrectFormat"
        case .ioError:
            return "ioError"
        // ... etc ...
        }
    }
    
    // Each of these errors references a file URL, so I may want a property for 
that too
    
    var url: URL {
        switch self {
        case let .notFound(url: url):
            return url
        case let .accessDenied(url: url):
            return url
        case let .incorrectFormat(url: url):
            return url
        case let .ioError(url: url):
            return url
        // ... etc ...
        }
    }
}

Look how ugly this is. Switch statements everywhere, related values separated 
by really large amounts of space (and even more so if this error had more 
cases, or if I’d implemented other error protocols like RecoverableError, 
CustomNSError, etc.).

With the improved syntax, this could look something like this instead:

enum FileError: Error, LocalizedError {
    var url: URL { get }
    
    case notFound(url: URL) {
        errorDescription = "Could not access the file \(url.lastPathComponent) 
because it could not be found."
        failureReason = "The file \(url.lastPathComponent) could not be found."
        recoverySuggestion = "Please locate the correct file and try again."
        helpAnchor = "notFound"
        url = url
    }
    
    case accessDenied(url: URL) {
        errorDescription = "Could not access the file \(url.lastPathComponent) 
because access was denied."
        failureReason = "We do not have permission to view the file 
\(url.lastPathComponent)"
        recoverySuggestion = "You can change the file's permissions using the 
Finder's Get Info window."
        helpAnchor = "accessDenied"
        url = url
    }
    
    case incorrectFormat(url: URL) {
        errorDescription = "Could not access the file \(url.lastPathComponent) 
because it was not in the expected format."
        failureReason = "The file \(url.lastPathComponent) was not in the 
expected format."
        recoverySuggestion = "The file may have become corrupt."
        helpAnchor = "incorrectFormat"
        url = url
    }
    
    case ioError(url: URL) {
        errorDescription = "Could not access the file \(url.lastPathComponent) 
because an I/O error occurred."
        failureReason = "An I/O error occurred while accessing the file 
\(url.lastPathComponent)."
        recoverySuggestion = "Dear Lord, the hard drive may be failing."
        helpAnchor = "ioError"
        url = url
    }
    
    // ... etc ...
}

I don’t think it can be denied that the second is orders of magnitude easier to 
read and comprehend.

Charles

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

Reply via email to