> 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.

> 
> 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.

> 
> 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.

> 
> 
> On Thu, Aug 25, 2016 at 08:40 Matthew Johnson <[email protected] 
> <mailto:[email protected]>> wrote:
>> On Aug 24, 2016, at 9:33 PM, Xiaodi Wu <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> On Wed, Aug 24, 2016 at 9:25 PM, Matthew Johnson via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> 
>>> On Aug 24, 2016, at 9:09 PM, Robert Widmann via swift-evolution 
>>> <[email protected] <mailto:[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/Week-of-Mon-20160523/018799.html
>  
> <https://lists.swift.org/pipermail/swift-evolution/Week-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] <mailto:[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] <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] <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

Reply via email to