> 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