I'm biased as the pitcher, but I find that an "inheritance" model would be more
straightforward than an inclusive model.
If I understand you correctly, with this model:
> enum NetworkException {
> case NoInternetError, SecurityError
> }
>
> enum ChangePictureError {
> case NetworkException(NetworkException)
> case ParseException(ParseException)
> case PictureTooLarge
> }
you're saying that we should be able to write:
> let x: ChangePictureError = NetworkException.NoInternetError
The implicit conversion from NetworkException to ChangePictureError reminds me
of C++ implicit constructors, which are generally frowned upon, so I'm not sure
that this is the best way forward.
On the other hand, going back to my original example:
> enum MyLibError: ErrorType {
> case FileNotFound
> case UnexpectedEOF
> case PermissionDenied
> // ... 300 cases later
> case FluxCapacitorFailure
> case SplineReticulationError
> }
>
> enum FileSystemError: MyLibError {
> case FileNotFound = .FileNotFound
> case UnexpectedEOF = .UnexpectedEOF
> case PermissionDenied = .PermissionDenied
> }
I can easily rationalize that FileSystemError is implicitly convertible to
MyLibError because of the "inheritance" relationship.
Félix
> Le 19 déc. 2015 à 14:28:44, Matthew Johnson <[email protected]> a écrit :
>
>>
>> On Dec 18, 2015, at 11:34 AM, Dennis Lysenko via swift-evolution
>> <[email protected] <mailto:[email protected]>> wrote:
>>
>> Sorry, I got a bit too excited and skimmed over the most important part of
>> the idea. So this is a special type of enum declaration in which you cannot
>> declare any new enum members. I personally have not seen a use for this in
>> my code but I would love to hear others' response to it. It is a very
>> interesting idea though.
>>
>> I'm going to go out on a limb with an idea that is in the same vein as this
>> one: What if we favored composition over inheritance here, and made it so
>> that you could transparently refer to members of other enums *without*
>> having another enum as a backing type?
>>
>> e.g., you have:
>> enum NetworkException {
>> case NoInternetError, SecurityError
>> }
>>
>> enum ParseException {
>> case FailedResponse(statusCode: Int)
>> case EmptyResponse
>> case MissingField(fieldName: String)
>> }
>>
>> As two general classes of errors. But for a full API call wrapper, you might
>> want an error class that composes the two, so that when calling the API call
>> from your UI code, you can display a "please check your connection" message
>> for NoInternetError, a "Please log in" error for FailedResponse with
>> statusCode=401, or a "server error" message for any of the rest.
>>
>> I wonder how do you and others feel about that use-case? I have certainly
>> seen it come up a lot in real-world projects that require resilient UI
>> interactions with nontrivial networking operations.
>>
>> Here are some quick code samples off the top of my head for how we might go
>> about this (let's say the API operation is "change profile picture":
>>
>> enum ChangePictureError {
>> include NetworkException
>> include ParseException
>> case PictureTooLarge
>> }
>
> By including all of the cases you make it possible for ChangePictureError to
> be a supertype of NetworkException and ParseException. This is a pretty
> interesting idea. It might be worth exploring.
>
> One thing that would need to be considered is that ideally if the actual
> values was a NetworkException case you would want to be able to call any
> methods exposed by Network Exception. A good way to accomplish that might be
> to add implicit conversion as well as syntactic sugar for nested enums. So
> if we have this:
>
> enum ChangePictureError {
> case NetworkException(NetworkException)
> case ParseException(ParseException)
> case PictureTooLarge
> }
>
> I can do this:
>
> var error: ChangePictureError // set somewhere, can be set with a
> NetworkException or a PictureTooLarge
> switch error {
> case .NoNetworkError: // equivaluent to case
> .NetworkException(.NoNetworkError)
> case .NoInternetError: // equivaluent to case
> .NetworkException(. NoInternetError)
> case .FailedResponse(let statusCode): // equivaluent to case
> .ParseException(.FailedResponse(let statusCode))
> case .EmptyResponse: // equivaluent to case
> .ParseException(.EmptyResponse)
> case .MissingField(let fieldName): // equivaluent to case
> .ParseException(. MissingField(let fieldName))
> case .PictureTooLarge:
> }
>
> The syntactic sugar would only work for case names where there is no overlap.
> Case names that overlap would need to be explicitly disambiguated. The
> syntactic sugar and implicit conversions could allow for either single-level
> nesting or arbitrary nesting depth. An example of arbitrary depth might be
> ParseException also containing a ValidationError case:
>
> enum ValidationError {
> case OutOfRange
> case InvalidType
> }
>
> enum ParseException {
> case ValidationError(ValidationError)
> case FailedResponse(statusCode: Int)
> case EmptyResponse
> case MissingField(fieldName: String)
> }
>
> Mostly just thinking out loud here and exploring the idea. What do others
> think of this?
>
>>
>> or
>>
>> enum ChangePictureError {
>> compose NetworkException.NoInternetError
>> compose ParseException.EmptyResponse
>> compose ParseException.FailedResponse(statusCode: Int)
>> case PictureTooLarge
>> }
>>
>> Not a proposal by any stretch of the imagination, just a potential direction
>> inspired by your idea, Felix.
>>
>>
>> On Fri, Dec 18, 2015 at 12:21 PM Dennis Lysenko <[email protected]
>> <mailto:[email protected]>> wrote:
>> Felix,
>>
>> This seems to be very interestingly tied into your comments about
>> polymorphism in 'throws' type annotations. Would you not feel that allowing
>> enums to be built on top of other enums would promote the kind of egregious
>> proliferation of exception polymorphism that discourages so many from
>> following Java's checked exception model?
>>
>> On Fri, Dec 18, 2015 at 11:29 AM Félix Cloutier <[email protected]
>> <mailto:[email protected]>> wrote:
>> Hi all,
>>
>> Swift currently has more or less three conceptual types of enums:
>> discriminated unions, lists of unique tokens, and lists of value of a raw
>> type.
>>
>> > // Discriminated unions
>> > enum Foo {
>> > case Bar(Int)
>> > case Baz(String)
>> > }
>> >
>> > // Lists of unique tokens (mixable with discriminated unions)
>> > enum Foo {
>> > case Frob
>> > case Nicate
>> > }
>> >
>> > // Lists of raw values
>> > enum Foo: String {
>> > case Bar = "Bar"
>> > case Baz = "Baz"
>> > }
>>
>> I think that the last case could be made more interesting if you could use
>> more types as underlying types. For instance, it could probably be extended
>> to support another enum as the backing type. One possible use case would be
>> to have a big fat enum for all the possible errors that your program/library
>> can throw, but refine that list into a shorter enum for functions that don't
>> need it all.
>>
>> > enum MyLibError: ErrorType {
>> > case FileNotFound
>> > case UnexpectedEOF
>> > case PermissionDenied
>> > // ... 300 cases later
>> > case FluxCapacitorFailure
>> > case SplineReticulationError
>> > }
>> >
>> > enum FileSystemError: MyLibError {
>> > case FileNotFound = .FileNotFound
>> > case UnexpectedEOF = .UnexpectedEOF
>> > case PermissionDenied = .PermissionDenied
>> > }
>>
>> This example could be made simpler if the `= .Foo` part was inferred from
>> the name, but you get the idea.
>>
>> In this case, it would be helpful (but not required) that FileSystemError
>> was convertible into a MyLibError, so that it could be transparently
>> rethrown in a function that uses the larger enum. I personally don't see why
>> enums with a specified underlying type can't be implicitly converted to it,
>> but this is not currently the case and it probably deserves some discussion
>> as well.
>>
>> Is there any interest in that?
>>
>> Félix
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution