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 <matt...@anandabits.com> a écrit : > >> >> On Dec 18, 2015, at 11:34 AM, Dennis Lysenko via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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 <dennis.s.lyse...@gmail.com >> <mailto:dennis.s.lyse...@gmail.com>> 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 <swift-evolution@swift.org >> <mailto:swift-evolution@swift.org>> 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 >> 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 https://lists.swift.org/mailman/listinfo/swift-evolution