On Thu, Aug 25, 2016 at 10:07 AM, Matthew Johnson <[email protected]> wrote:
> > On Aug 25, 2016, at 9:37 AM, Xiaodi Wu <[email protected]> wrote: > > Charles clarified that indeed he was pitching casting operators that match > subclasses. > > > Ok, I missed that. > > > If the compiler knows that a class is sealed, why do you think there's a > new keyword needed for the compiler to prove exhaustiveness? > > > I said I wasn’t sure if there was a different / better way to do it. Just > that this *would* do it. > > > First, you can already match exact types by writing `type(of: instance) == > Base.self` (which doesn't evaluate to true if instance is of a subclass of > Base). > > > This might be an alternative if the compiler adds special knowledge of > this syntax to prove exhaustiveness. > I might be in favor of that. As it is, I can write this: ``` func ~= <T, U>(lhs: T.Type, rhs: U.Type) -> Bool { return lhs == rhs } class Base { init() { } } class A1 : Base { } class A2 : Base { } let a = A1() switch type(of: a) { case A1.self: print(1) case A2.self: print(2) case Base.self: print(0) default: fatalError() } ``` It'd be nice if the compiler would know about exhaustiveness (and if I didn't have to define my own `~=`). This is, afaict, doable without any additional syntax in the language. Second, if your class hierarchy is Base > A > B > C, then _even if_ there > existed no way to match exact types (which there is), you have the option > of switching over the type of an instance, providing cases that match in > the order C, B, A, Base in order to perform a different action for each. > This requires no additional knowledge at compile time beyond what you > already stipulated for your use case, namely that the entire class > hierarchy must be known at compile time. > > > This order requirement is fragile. If you put Base first it will always > match, which probably isn’t the intent. I would like to see a solution > that requires you to match each type in the hierarchy without being subject > to bugs related to ordering of the cases. > Given that the hierarchy is known at compile-time, a solution that would meet your criteria (not being subject to bugs related to ordering) would be diagnostics for unreachable cases (i.e., if Base is matched before A, `case is A` should be flagged as unreachable). > Third, your motivating example in the previous thread already works. > Slightly renamed to match the examples above, the following compiles: > > > ``` > class Base { init() { } } class A1 : Base { } class A2 : Base { } func > foo(_ b: Base) -> Int { switch b { case is A1: return 1 case is A2: return > 2 case is Base: return 0 } } > > let a = A1() let b = A2() foo(a) // 1 foo(b) // 2 > ``` > > There is a warning that `case is Base` is always true. Perhaps something > could be done about that diagnostic, since that is after all what you want > in a switch statement without a default case. > > I'm sure you were aware of all of these points, so I guess I'm asking, > what exactly are you pitching? > > > See above. I am looking for a solution that avoids this warning precisely > because it will *not* always be true. The compiler gaining special > knowledge of the `type(of: instance) == Base.self` pattern could be > *part* of a solution but it still doesn’t bind a name the correct type. For > example, with the Base > A > B > C hierarchy when I match `type(of: > instance) == B.self` I also want a variable bound with a type of `B`. This > gets pretty verbose and requires the compiler to have special knowledge of > pretty specific pattern: > > func foo(_ b: Base) -> Int { > switch b { > case let base as Base where type(of: instance) == Base.self: return 1 > case let a as A where type(of: instance) == A.self: return 2 > case let b as B where type(of: instance) == B.self: return 3 > case let c as C where type(of: instance) == C.self: return 4 > } > } > > If the compiler could prove exhaustiveness here I would accept that > solution. But it seems like an exact match cast operator would be much > more elegant. > > In any case, anything that requires matching every type in a hierarchy > without being subject to case ordering bugs and doesn’t require a default > clause would be acceptable to me. That is the problem I would like to see > solved. > Looking back, it seems like diagnostics for unreachable cases would meet your criteria exactly and would be the most straightforward. I don't think it would even require an evolution proposal. I would love to see type(of:) work with switch statements out-of-the-box, but that seems more esoteric. None of this requires additional syntax, IMHO. > > On Thu, Aug 25, 2016 at 08:40 Matthew Johnson <[email protected]> > wrote: > >> On Aug 24, 2016, at 9:33 PM, Xiaodi Wu <[email protected]> wrote: >> >> On Wed, Aug 24, 2016 at 9:25 PM, Matthew Johnson via swift-evolution < >> [email protected]> wrote: >> >>> >>> On Aug 24, 2016, at 9:09 PM, Robert Widmann via swift-evolution < >>> [email protected]> wrote: >>> >>> I have 3 qualms with this proposal as it stands: >>> >>> - type(of:) will never lie to you. >>> >>> The only question it won’t answer to your satisfaction is the dynamic >>> type of the NSString you boxed up as an Any. >>> >>> - No more keywords without significant justification. >>> >>> I don’t buy the performance use case at all - if you were properly >>> concerned about performance you would try to use as many of Swift’s static >>> features as possible. >>> >>> - Especially no more keywords that look like they belong in Rust or PHP! >>> >>> There is no precedent for the spelling of these operations other than >>> the suffixed punctuation. Given that they’re domain-specific, will >>> definitely be hard to use (given that NSString(string: "Bar”) may not >>> “really” given you an NSString yet that’s what you asked us to check for “ >>> *really*"), and will be obviated by the implementation of SE-0083, I >>> can’t see a reason why we need any of this in the language proper. >>> >>> >>> One related topic to consider is exhaustive pattern matching for >>> classes. Now that SE-0117 has been accepted it will be possible to do this >>> for many classes (I would say most if it weren’t for Objective-C classes >>> being so common in Swift and are imported as `open`). Supporting >>> exhaustive pattern matching well would require some kind of syntax for >>> matching the runtime type exactly. I have imagined this as being “exact >>> match” cast operators, which is what the `really_*` operators are. >>> >> >> I don't understand. As pitched, these operators remove bridging magic, >> but `Subclass really_is Superclass == true`. How would you use this for >> classes? >> >> >> Bridging is the use case motivating the pitch. I am bringing up a >> related use case. >> >> The pitch does not specify `Subclass really_is Superclass == true` and I >> would argue that this is not the semantics we would want. My >> interpretation of the proposed solution is: >> >> "I propose the following operators: really_is, really_as, really_as?, and >> really_as!. These operators would only return a positive result if the type >> actually was what was being asked for, instead of something that might be >> able to bridge to that type *or a superclass of that type*." >> >> We discussed the exhaustive pattern matching previously in this thread: >> https://lists.swift.org/pipermail/swift-evolution/We >> ek-of-Mon-20160523/018799.html where the “exact match” cast operators >> were called `isExactly` and `asExactly`. >> >> I think the exhaustive pattern matching use case for classes (and >> protocols if / when we get sealed protocols) is an important one. I also >> think doing it right requires the ability to match exact types (i.e. not >> match subclasses). Maybe there is a better mechanism than a new operators >> but they would certainly do the job well. >> >> >> >>> Do you have an alternative in mind for exhaustive pattern matching if we >>> do not introduce exact match cast operators? >>> >>> >>> ~Robert Widmann >>> >>> On Aug 24, 2016, at 5:08 PM, Charles Srstka via swift-evolution < >>> [email protected]> wrote: >>> >>> MOTIVATION: >>> >>> SE-0083 appears to be dead in the water, having been deferred until >>> later in Swift 3 back in May and not having been heard from since then, >>> with the Swift 3 release looming closer and closer. However, the >>> predictability gains that would have been provided by this change remain >>> desirable for cases where one needs to know the actual dynamic type of an >>> entity before any bridging magic is involved. Additionally, >>> performance-critical code may desire the ability to check something’s type >>> quickly without incurring the overhead of Objective-C bridging code. >>> >>> PROPOSED SOLUTION: >>> >>> I propose the following operators: really_is, really_as, really_as?, and >>> really_as!. These operators would only return a positive result if the type >>> actually was what was being asked for, instead of something that might be >>> able to bridge to that type. >>> >>> DETAILED DESIGN: >>> >>> let foo: Any = "Foo" >>> let bar: Any = NSString(string: "Bar") >>> >>> let fooIsString = foo is String // true >>> let fooReallyIsString = foo really_is String // true >>> >>> let fooIsNSString = foo is NSString // true >>> let fooReallyIsNSString = foo really_is NSString // false >>> >>> let barIsString = bar is String // true >>> let barReallyIsString = bar really_is String // false >>> >>> let barIsNSString = bar is NSString // true >>> let barReallyIsNSString = bar really_is NSString // true >>> >>> ALTERNATIVES CONSIDERED: >>> >>> Stick with using an unholy combination of Mirror and unsafeBitCast when >>> you need to know what you’ve actually got. >>> >>> Charles >>> >>> _______________________________________________ >>> 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 >>> >>> >>> >>> _______________________________________________ >>> 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
