[swift-evolution] [Proposal] Type Narrowing

Haravikk swift-evolution at haravikk.me
Tue Nov 15 05:12:50 CST 2016


> On 15 Nov 2016, at 07:19, Jean-Daniel <dev at xenonium.com> wrote:
>> Le 14 nov. 2016 à 10:10, Haravikk <swift-evolution at haravikk.me <mailto:swift-evolution at haravikk.me>> a écrit :
>>> On 13 Nov 2016, at 16:16, Jean-Daniel via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>> Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution <swift-evolution at swift.org <mailto: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'll have to take a closer look at how Kotlin does this when I get a chance, but how would this affect the two proposals as they currently stand?
>> 
>> https://github.com/Haravikk/swift-evolution/blob/master/proposals/NNNN-type-narrowing.md <https://github.com/Haravikk/swift-evolution/blob/master/proposals/NNNN-type-narrowing.md>
>> https://github.com/Haravikk/swift-evolution/blob/master/proposals/NNNN-optional-unwrapping.md <https://github.com/Haravikk/swift-evolution/blob/master/proposals/NNNN-optional-unwrapping.md>
>> 
>> These keep automatic narrowing of polymorphic types, but requires explicit narrow/unwrapping of optionals (because we can define methods/properties on Optional there's no other choice unfortunately); it would work for both mutable and immutable values, but mutable reference types require an extra step due to the potential for unsafe operations.
>> 
>> I think that's about as flexible as we're going to be able to get without introducing other difficulties.
> 
> While the proposals try to be less restrictive than Kotlin, I don’t like the way they handle concurrency.
> All usage of the ‘!’ operator in swift guarantee a crash at the call site if something is wrong (try!, as!, optional!, …). In the proposals, the ‘!’ operator means that the app may crash at call site or may crash later.

The error should still be associated with the line that actually failed, the only difference here is that the type-checking or force-unwrapping is handled for you behind the scenes, as you've opted into it for that scope by forcing the unwrap/narrowing to occur. Put another way; when you force unwrap/narrow a reference type, it is treated like an implicitly unwrapped Optional or implicitly narrowed type, so is checked for correctness as necessary.

Since narrowing/unwrapping has (sort of) occurred, we can produce an error that better highlights the problem, e.g- "Force unwrapped reference was set to nil by another method or thread", as the unwrap/narrowing functionality ensures that you can't do it in the current scope without it being detected. The error that requires you to use force unwrapping/narrowing can likewise be more specific, e.g- "Reference type foo cannot be unwrapped/narrowed safely" (I suck at writing error messages btw), the idea being to encourage developers to consider why and decide for themselves whether it's better to force the unwrap/narrowing (because they're confident it will work) or to instead work with a copy and put it back later, use locking etc. etc.

The only other component is an attribute to indicate when a reference is safe; I'm favouring something like @concurrency(safe), but the difficulty is whether it's enough to just indicate this or if it also needs to be enforced somehow. I might use the attribute for example on a property I know will be used in a copy-on-write style, but is it feasible to enforce that, perhaps with some kind of behaviour similar to no-escape? It becomes tough to consider every possible case for something like that, and it'd probably need some other supporting features, like a @copy attribute for return types so we can account for methods methods that produce a new copy of an instance (e.g- if your return type has the @copy attribute then it can't return self). It's probably more of a separate proposal though for how we'll handle concurrency and reference types natively.

Little bit off track there, but the short version is; forcing the unwrap/narrowing doesn't make your code any more or less safe for references, it just removes the need for force-unwrap or type check everything manually.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161115/16c13456/attachment.html>


More information about the swift-evolution mailing list