[swift-evolution] [Proposal] Type Narrowing

Dennis Lysenko dennis.s.lysenko at gmail.com
Sun Nov 13 20:35:15 CST 2016


Jean-Daniel, I agree with the first part of your assessment fully, which in
my opinion is actually why I think the Kotlin style combined with the Swift
style would pull in the best of both worlds and create a complete solution.
I do share some of your reservation in the second part of your assessment,
which is why I'm a little hesitant on the proposal, but as I've described
before I think it would help expressiveness.

On Sun, Nov 13, 2016 at 11:16 AM Jean-Daniel <dev at xenonium.com> wrote:

> Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution <
> swift-evolution at swift.org> a écrit :
>
> That's a good point in Jay's example and from what I can tell a good way
> to address it, Haravikk.
>
> I've done some work in a language that only provides type narrowing for
> immutable types (that'd be Kotlin as I've mentioned before) and whenever
> I've used it it feels like the only thing it's really been missing is the
> "if let" construct allowing you to bind and unwrap mutable values, which
> leads me to think that synergistically, in Swift, this would be fantastic.
> The main benefit probably is that it would allow code to read much better.
>
>
> IMHO, the Kotlin solution is flaw. The fact that type narrowing does not
> works for var and that there is no simple way to unwrap optional just force
> the developer either to introduce local variable, or to use the force
> unwrap operator.
> Moreover, introducing a unwrap syntax (if let) like in swift would just
> result in having 2 different and inconsistent way to do the same thing.
>
> I think the "type stack" phrasing in the proposal is throwing some people
> for a loop making them think it'll have way more mental overhead than it
> actually does in practice...really, in practice, I've used this either (a)
> for checking nullity or (b) for checking for a specific subclass. There's
> little to no mental overhead in either of those cases, as your "type stack"
> is simply 2-long (this was an Int? outside of this conditional block, and
> it's an Int inside. This was a UIViewController outside of this conditional
> block, and it's a UINavigationController inside.)
>
> While it may not be a panacea that allows new applications that no one
> could have thought of, I have no doubt that it would greatly improve the
> experience of coding in the language by, as you said, allowing more
> flexibility in expressiveness. Regardless of one's opinion on the efficacy
> of this feature as a whole, there *are* frequent situations where this
> feature leads to substantially better-reading code. The "unwrap" keyword
> proposed in another thread, critically, solves only *half* of the
>  problems that this proposal solves (as far as I could tell from reading a
> few emails in the chain, it left the subclass inference completely
> untouched). Ability to say "if (controller is SongSelectionViewController)
> { controller.search(for: "mozart") }" is mentally freeing and helps me stay
> in coder zen.
>
> IMO, it would effectively be the cream cheese icing on the top of the
> carrot cake of Swift's unwrapping and type inference features. A good
> tasteful cream cheese icing always improves a carrot cake.
>
> The question then becomes, is it really worth the implementation time?
> This is something that, presumably, someone from the Swift team would need
> to be involved in answering.
>
> On Fri, Nov 11, 2016 at 10:52 AM Haravikk via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> On 10 Nov 2016, at 21:42, Jay Abbott <jay at abbott.me.uk> wrote:
>
> Consider this code:
>
> struct Pet {
>     let name: String
>     weak var owner: Person?
>
>     init(name: String, owner: Person?) {
>         self.name = name
>         self.owner = owner
>         owner?.pet = self
>     }
>
>     mutating func transferOwnership(to newOwner: Person) {
>         let previousOwner = owner
>         owner = newOwner
>         newOwner.pet = self
>         if(previousOwner != nil) {
>             previousOwner!.pet = nil
>         }
>     }
>
>     func feed() {
>     }
> }
> class Person {
>     let name: String
>     var pet: Pet?
>
>     init(name: String) {
>         self.name = name
>     }
>
>     func givePetAway(to someone: Person) {
>         if pet != nil {
>             pet!.transferOwnership(to: someone)
>             //pet!.feed()
>         }
>     }
> }
> let bert = Person(name: "Bert")let ernie = Person(name: "Ernie")var elmo = Pet(name: "Elmo", owner: nil)
>
> elmo.transferOwnership(to: bert)print("Bert's pet is \(bert.pet) - Ernie's pet is \(ernie.pet)")
>
> bert.givePetAway(to: ernie)print("Bert's pet is \(bert.pet) - Ernie's pet is \(ernie.pet)")
>
> This works as expected, but if you uncomment pet!.feed() in
> givePetAway(to:) it will crash, because the mutating function modifies
> the two-way relationship between pet and owner.
>
> In the code I use if pet != nil to demonstrate, in your proposal for
> unwrap, if I used it to unwrap pet (a value-type, but accessed through
> self so it can be modified after unwrapping because it’s not nil at the
> moment) the compiler would assume I could use it and pet.feed() would
> crash, just as pet!.feed() does now. In your proposal for type narrowing,
> it would be the same problem. This is like your foo.value example from
> the proposal.
>
> I don’t think you can get around the fact that the compiler can’t
> guarantee a type-narrowed or even unwrapped mutable value, which is why if
> let works as it does with an immutable snapshot.
>
> However, type narrowing for immutable values would still be good.
>
> This isn't a problem of mutability, it's a problem due to the use of a
> reference type (Person); this is what the classes and concurrency section
> is supposed to be describing, but perhaps I haven't made it clear enough.
> So in the example you've given self.pet can't be unwrapped because self is
> a reference type, thus you need to either use force unwrapping either with
> the unwrap! keyword or direct force unwrapping like you've used (since
> behind the scenes it's the same thing).
>
> You are right though that the resulting error isn't necessarily a
> concurrency issue, so I'll make a note of this for the proposed new error,
> and also clarify that the reference type restriction doesn't just apply to
> the property itself, but also to whatever it belongs to (and so-on up the
> chain, so if any part of foo.bar.a.b.c is a reference type it can't be soft
> unwrapped).
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161114/85dc3966/attachment.html>


More information about the swift-evolution mailing list