Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-15 Thread Haravikk via swift-evolution

> On 15 Nov 2016, at 07:19, Jean-Daniel  wrote:
>> Le 14 nov. 2016 à 10:10, Haravikk > > a écrit :
>>> On 13 Nov 2016, at 16:16, Jean-Daniel via swift-evolution 
>>> > wrote:
 Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution 
 > 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/-type-narrowing.md
>>  
>> 
>> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-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 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-14 Thread Jean-Daniel via swift-evolution

> Le 14 nov. 2016 à 10:10, Haravikk  a écrit :
> 
> 
>> On 13 Nov 2016, at 16:16, Jean-Daniel via swift-evolution 
>> > wrote:
>> 
>>> 
>>> Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution 
>>> > 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/-type-narrowing.md
>  
> 
> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-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.



___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-14 Thread Haravikk via swift-evolution

> On 13 Nov 2016, at 16:16, Jean-Daniel via swift-evolution 
>  wrote:
> 
>> 
>> Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution 
>> > 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/-type-narrowing.md
https://github.com/Haravikk/swift-evolution/blob/master/proposals/-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.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-13 Thread Dennis Lysenko via swift-evolution
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  wrote:

> Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution <
> swift-evolution@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@swift.org> wrote:
>
>
> On 10 Nov 2016, at 21:42, Jay Abbott  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 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-13 Thread Jean-Daniel via swift-evolution

> Le 13 nov. 2016 à 03:37, Dennis Lysenko via swift-evolution 
>  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 
> > wrote:
> 
>> On 10 Nov 2016, at 21:42, Jay Abbott > > 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 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-12 Thread Dennis Lysenko via swift-evolution
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.

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@swift.org> wrote:

>
> On 10 Nov 2016, at 21:42, Jay Abbott  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 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-11 Thread Haravikk via swift-evolution

> On 10 Nov 2016, at 21:42, Jay Abbott  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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-10 Thread Jay Abbott via swift-evolution
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.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-10 Thread Haravikk via swift-evolution

> On 10 Nov 2016, at 16:53, Jay Abbott  wrote:
> 
> Haravikk,
> 
> I think you missed ilya’s point with the owner/pet example:
> 
> // This is inside the Owner class...
> func freeMyPetIfIHaveOne {
>   if pet != nil {
> pet.setFree() // this sets pet = nil
> // self.pet is now nil - not due to concurrency, it was set to nil on 
> this thread in the function above.
> // However, the compiler considers it a non-optional at this point
> pet.doStuff() // Compiler allows, bad things happen!
>   }
> }
> As Dennis mentioned, narrowing only works for immutable values, and since 
> optionals are always mutable it defeats the whole justification for it. I 
> like the concept, but maybe it should be for immutables only?
> 
If pet is of type Optional then a .setFree() method on T cannot set self = 
nil, as self is of type T only in that scope.

The only way you can do something like that is to declare the setFree() method 
on Optional where Element:T, but that won't work on the updated proposal which 
uses a keyword to explicitly unwrap the variable (to avoid precisely that kind 
of Optional vs T method conflict), you can view the updated proposals here:

https://github.com/Haravikk/swift-evolution/blob/master/proposals/-optional-unwrapping.md
 

https://github.com/Haravikk/swift-evolution/blob/master/proposals/-type-narrowing.md
 


I've also checked and a similar case like this for polymorphic types shouldn't 
be an issue either, as you can't assign self to a wider (or even orthogonal) 
type.

In other words, the only way that .setFree() can make changes that would break 
narrowing would be to have a reference to the instance you're working with, 
which is what the proposals now guard against. But for value types this should 
not be an issue at all.

This is all of course unless I'm missing something else, but I tried in a 
playground and I can't assign anything to self that would break 
narrowing/unwrapping that I can see, except through a reference type.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-10 Thread Jay Abbott via swift-evolution
Haravikk,

I think you missed ilya’s point with the owner/pet example:

// This is inside the Owner class...func freeMyPetIfIHaveOne {
  if pet != nil {
pet.setFree() // this sets pet = nil
// self.pet is now nil - not due to concurrency, it was set to nil
on this thread in the function above.
// However, the compiler considers it a non-optional at this point
pet.doStuff() // Compiler allows, bad things happen!
  }
}

As Dennis mentioned, narrowing only works for immutable values, and since
optionals are always mutable it defeats the whole justification for it. I
like the concept, but maybe it should be for immutables only?
​

On Thu, 10 Nov 2016 at 11:27 Haravikk via swift-evolution <
swift-evolution@swift.org> wrote:

> On 10 Nov 2016, at 10:32, Dennis Lysenko 
> wrote:
>
> So a lot of concerns here especially ilya's are ones that wouldn't be
> brought up if people looked at existing successful implementations like
> Kotlin where they are clearly solved. (fyi, answer is only narrowing with
> immutable values.)
>
> Personally I think type narrowing with explicit opt-in has no value. All
> or nothing, the whole meat of the proposal is in it being implicit.
>
> Right you are, I think an explicit keyword is only required for optionals;
> stripping them out into their own proposal simplifies things considerably.
> I've tweaked the type-narrowing specific proposal to return implicit
> narrowing (or explicit via the is keyword and assignment, depending upon
> how you want to look at it).
>
> I do think there is still value in handling reference types as well, but
> I'm proposing that this is done with a new force is! keyword which forces
> the narrowing (but causes a runtime concurrent modification error if the
> type no longer matches what the type-checker expects), as well as a new
> @concurrency(safe) attribute that can be used to indicate variables that
> posses a safe reference to an instance, e.g- for types that use a storage
> class for copy-on-write functionality, or where the value is local to a
> method etc. (though this isn't enforced).
>
> if it makes compilation times even slower I'm probably against it - xcode
> in general has been driving me up a wall lately with a matter of minutes
> for compiling and signing our (not huge) project, so any compiler speed
> improvements take on increased precedence for me.
>
> While I agree that the current performance can leave a lot to be desired,
> I don't think that this should actually slow it down by any meaningful
> amount; most variables won't narrow so will just be a single type as
> normal, and with optionals removed from the narrowing process the
> type-checker should only ever need to compare against the narrowest type on
> the stack, i.e- the only time wider types are considered is when you assign
> a wider type to a narrowed variable, and that's just popping types off the
> stack to get the new current type.
>
> But yeah, if it were have a big impact on performance I'd recommend
> delaying it until major optimisation work has been done, but I don't see
> that it should make much of a difference, and it really shouldn't be any
> more of a burden than shadowing is today.
>
> On Wed, Nov 9, 2016, 13:52 Haravikk via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> So I'm trying to re-write the proposal with the use of a keyword for
> unwrapping in mind, to keep it simpler for myself I've done this as two
> separate proposals for the time being, one for simpler unwrapping of
> optionals, and one for type-narrowing of polymorphic types:
>
>
> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-optional-unwrapping.md
>
> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-type-narrowing.md
>
> In addition to feedback on each proposal, I'm interested to know whether
> people think it is better to keep these separate? They're still very
> similar features, but the differences make it pretty awkward to keep them
> in one big proposal.
>
> I've also given up on integrating enums generically into it; as I don't
> think it's possible to do it in a similar enough way, and some extension to
> pattern matching would probably be better anyway.
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-10 Thread Haravikk via swift-evolution

> On 10 Nov 2016, at 10:32, Dennis Lysenko  wrote:
> So a lot of concerns here especially ilya's are ones that wouldn't be brought 
> up if people looked at existing successful implementations like Kotlin where 
> they are clearly solved. (fyi, answer is only narrowing with immutable 
> values.)
> 
> Personally I think type narrowing with explicit opt-in has no value. All or 
> nothing, the whole meat of the proposal is in it being implicit.
> 
Right you are, I think an explicit keyword is only required for optionals; 
stripping them out into their own proposal simplifies things considerably. I've 
tweaked the type-narrowing specific proposal to return implicit narrowing (or 
explicit via the is keyword and assignment, depending upon how you want to look 
at it).

I do think there is still value in handling reference types as well, but I'm 
proposing that this is done with a new force is! keyword which forces the 
narrowing (but causes a runtime concurrent modification error if the type no 
longer matches what the type-checker expects), as well as a new 
@concurrency(safe) attribute that can be used to indicate variables that posses 
a safe reference to an instance, e.g- for types that use a storage class for 
copy-on-write functionality, or where the value is local to a method etc. 
(though this isn't enforced).
> if it makes compilation times even slower I'm probably against it - xcode in 
> general has been driving me up a wall lately with a matter of minutes for 
> compiling and signing our (not huge) project, so any compiler speed 
> improvements take on increased precedence for me.
> 
While I agree that the current performance can leave a lot to be desired, I 
don't think that this should actually slow it down by any meaningful amount; 
most variables won't narrow so will just be a single type as normal, and with 
optionals removed from the narrowing process the type-checker should only ever 
need to compare against the narrowest type on the stack, i.e- the only time 
wider types are considered is when you assign a wider type to a narrowed 
variable, and that's just popping types off the stack to get the new current 
type.

But yeah, if it were have a big impact on performance I'd recommend delaying it 
until major optimisation work has been done, but I don't see that it should 
make much of a difference, and it really shouldn't be any more of a burden than 
shadowing is today.

>> On Wed, Nov 9, 2016, 13:52 Haravikk via swift-evolution 
>> > wrote:
>> So I'm trying to re-write the proposal with the use of a keyword for 
>> unwrapping in mind, to keep it simpler for myself I've done this as two 
>> separate proposals for the time being, one for simpler unwrapping of 
>> optionals, and one for type-narrowing of polymorphic types:
>> 
>> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-optional-unwrapping.md
>>  
>> 
>> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-type-narrowing.md
>>  
>> 
>> 
>> In addition to feedback on each proposal, I'm interested to know whether 
>> people think it is better to keep these separate? They're still very similar 
>> features, but the differences make it pretty awkward to keep them in one big 
>> proposal.
>> 
>> I've also given up on integrating enums generically into it; as I don't 
>> think it's possible to do it in a similar enough way, and some extension to 
>> pattern matching would probably be better anyway.
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-10 Thread Dennis Lysenko via swift-evolution
So a lot of concerns here especially ilya's are ones that wouldn't be
brought up if people looked at existing successful implementations like
Kotlin where they are clearly solved. (fyi, answer is only narrowing with
immutable values.)

Personally I think type narrowing with explicit opt-in has no value. All or
nothing, the whole meat of the proposal is in it being implicit.

I see too many people predisposed to considering this as if it's "compiler
magic" to the point where I don't feel the cost of arguing is worth what it
would bring to the language. Sure, it's a nice piece of syntax sugar but
it's not going to revolutionise it, and if it makes compilation times even
slower I'm probably against it - xcode in general has been driving me up a
wall lately with a matter of minutes for compiling and signing our (not
huge) project, so any compiler speed improvements take on increased
precedence for me.

Just my 2c.

Dennis

On Wed, Nov 9, 2016, 13:52 Haravikk via swift-evolution <
swift-evolution@swift.org> wrote:

> So I'm trying to re-write the proposal with the use of a keyword for
> unwrapping in mind, to keep it simpler for myself I've done this as two
> separate proposals for the time being, one for simpler unwrapping of
> optionals, and one for type-narrowing of polymorphic types:
>
>
> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-optional-unwrapping.md
>
> https://github.com/Haravikk/swift-evolution/blob/master/proposals/-type-narrowing.md
>
> In addition to feedback on each proposal, I'm interested to know whether
> people think it is better to keep these separate? They're still very
> similar features, but the differences make it pretty awkward to keep them
> in one big proposal.
>
> I've also given up on integrating enums generically into it; as I don't
> think it's possible to do it in a similar enough way, and some extension to
> pattern matching would probably be better anyway.
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Haravikk via swift-evolution
So I'm trying to re-write the proposal with the use of a keyword for unwrapping 
in mind, to keep it simpler for myself I've done this as two separate proposals 
for the time being, one for simpler unwrapping of optionals, and one for 
type-narrowing of polymorphic types:

https://github.com/Haravikk/swift-evolution/blob/master/proposals/-optional-unwrapping.md
https://github.com/Haravikk/swift-evolution/blob/master/proposals/-type-narrowing.md

In addition to feedback on each proposal, I'm interested to know whether people 
think it is better to keep these separate? They're still very similar features, 
but the differences make it pretty awkward to keep them in one big proposal.

I've also given up on integrating enums generically into it; as I don't think 
it's possible to do it in a similar enough way, and some extension to pattern 
matching would probably be better anyway.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Rien via swift-evolution
I get narrowing, and have admittedly often wished for it myself. Hence I have 
kept out of this discussion.
But the argument for cognitive overload is imo convincing.

When we create examples, there is almost no (or even negative) cognitive load 
associated with narrowing.
However when you get a piece of code in front of you with 10+ optionals, 5 
if-statements deep with loops intermixed, and you have to find where the 
nil-error occurs?
It would drive me nuts… especially in these kind of cases:

if foo != nil {
…
foo = newFoo()
…
if foo != nil {
…
}
}

Mind you, I am against automagic narrowing because I like things to be simple, 
but it is not a make or break deal.

Btw, I think that using a keyword makes it more palatable.

if unwrap foo {
…
foo = newFoo()
…
if unwrap foo {
…
}
}

Now it is clear that something is done to foo, its no longer a compare with 
side effects but an operation on foo itself.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl




> On 09 Nov 2016, at 15:28, Haravikk  wrote:
> 
> 
>> On 9 Nov 2016, at 12:19, Rien  wrote:
>>> On 9 Nov 2016, at 06:51, David Hart  wrote:
 On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution 
  wrote:
 
 This looks like a lot of complexity for very little gain.
 
 Aside from any implementation concerns, this proposal substantially 
 increases the cognitive load on developers. To figure out what a piece of 
 code means, someone reading it will have to mentally keep track of a “type 
 stack” for every variable. That is the opposite of “clarity at the point 
 of use”.
 
 Very well said. I think this is perhaps the number one complaint I have 
 about the proposal.
>>> 
>>> Did you see my response to this? There should be no particular cognitive 
>>> load increase; think of the feature like type inference, the idea here is 
>>> that the type-checker is gaining the same knowledge that you already have, 
>>> i.e- you know something isn't nil, so the type-checker should too.
>> 
>> Locally in short routines yes.
>> But in larger modules and non-local this does not apply.
> 
> I'm not sure what you mean; type-narrowing doesn't occur across scopes, 
> ultimately you will always have some starting type where the variable was 
> declared as a property, function argument or local variable, and it is narrow 
> only where it is used, and the narrowing only occurs within that scope for as 
> long as it is relevant.
> 
> In other words, the narrowing is always local. If you know your method takes 
> an optional string for example then you know that that variable is still an 
> optional string throughout that method, type-narrowing just helps to 
> guarantee that it is nil or non-nil where you expect it to be.
> 
>> Imo it should always be possible to look at a type declaration and -from 
>> that- derive all necessary knowledge about the type.
> 
> As I say, narrowing never changes the type; if you have a variable with a 
> declared type of Foo, that is narrowed to Bar, then it is because Bar extends 
> Foo and thus is compatible with it, giving you access to any additional 
> methods of Bar without interfering with what you know of Foo.
> 
>> Besides when using a narrowed type as a parameter for an optional it must be 
>> automatically be widened again? hence you would mentally keep track of the 
>> status of that variable.
> 
> I'm not sure I follow this question; do you mean something like this:
> 
>   func someMethod(foo:Foo?) {
>   var bar:Foo? = nil // bar is Optional.none
>   if (foo != nil) { // foo is Optional.some
>   bar = foo // both foo and bar are Optional.some
>   }
>   // both foo and bar are Optional (alternative branch 
> places no mutual guarantee on type)
>   if bar != nil { // bar is Optional.some
>   bar.someMutatingMethod()
>   }
>   }
> 
> But these are all things that the developer knows; bar can't be non-nil until 
> a value for it is set, foo is definitely non-nil within the block etc. The 
> only difference here is that instead of the developer having to use ! 
> unnecessarily (or risk making a mistake) they can just use their knowledge of 
> what it is to interact directly, as the type-checker will now also know the 
> same thing.
> 
> However, with the Optional to T method shadowing issue it seems we 
> probably will need to require a keyword, or at the very least restrict 
> automatic narrowing to polymorphism. For optionals the code will have to look 
> something like this:
> 
>   func someMethod(foo:Foo?) {
>   var bar:Foo? = nil
>   if 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread ilya via swift-evolution
> The difference here is that unlike shadowing (if let foo = foo), if foo
were mutable then it could still be mutated directly, no need to do it with
force unwrapping.

FWIW, there is no need for force unwrapping in any case.

var bar:Foo? = nil

if let real_foo = foo {
bar = real_foo
}

if var bar_copy = bar {
bar_copy.someMutatingMethod()
bar = bar_copy
}

On Wed, Nov 9, 2016 at 3:28 PM Haravikk  wrote:

> On 9 Nov 2016, at 12:19, Rien  wrote:
>
> On 9 Nov 2016, at 06:51, David Hart  wrote:
>
> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> This looks like a lot of complexity for very little gain.
>
> Aside from any implementation concerns, this proposal substantially
> increases the cognitive load on developers. To figure out what a piece of
> code means, someone reading it will have to mentally keep track of a “type
> stack” for every variable. That is the opposite of “clarity at the point of
> use”.
>
>
> Very well said. I think this is perhaps the number one complaint I have
> about the proposal.
>
>
> Did you see my response to this? There should be no particular cognitive
> load increase; think of the feature like type inference, the idea here is
> that the type-checker is gaining the same knowledge that you already have,
> i.e- you know something isn't nil, so the type-checker should too.
>
>
> Locally in short routines yes.
> But in larger modules and non-local this does not apply.
>
>
> I'm not sure what you mean; type-narrowing doesn't occur across scopes,
> ultimately you will always have some starting type where the variable was
> declared as a property, function argument or local variable, and it is
> narrow only where it is used, and the narrowing only occurs within that
> scope for as long as it is relevant.
>
> In other words, the narrowing is always local. If you know your method
> takes an optional string for example then you know that that variable is
> still an optional string throughout that method, type-narrowing just helps
> to guarantee that it is nil or non-nil where you expect it to be.
>
> Imo it should always be possible to look at a type declaration and -from
> that- derive all necessary knowledge about the type.
>
>
> As I say, narrowing never changes the type; if you have a variable with a
> declared type of Foo, that is narrowed to Bar, then it is because Bar
> extends Foo and thus is compatible with it, giving you access to any
> additional methods of Bar without interfering with what you know of Foo.
>
> Besides when using a narrowed type as a parameter for an optional it must
> be automatically be widened again? hence you would mentally keep track of
> the status of that variable.
>
>
> I'm not sure I follow this question; do you mean something like this:
>
> func someMethod(foo:Foo?) {
> var bar:Foo? = nil // bar is Optional.none
> if (foo != nil) { // foo is Optional.some
> bar = foo // both foo and bar are Optional.some
> }
> // both foo and bar are Optional (alternative branch places no mutual
> guarantee on type)
> if bar != nil { // bar is Optional.some
> bar.someMutatingMethod()
> }
> }
>
> But these are all things that the developer knows; bar can't be non-nil
> until a value for it is set, foo is definitely non-nil within the block
> etc. The only difference here is that instead of the developer having to
> use ! unnecessarily (or risk making a mistake) they can just use their
> knowledge of what it is to interact directly, as the type-checker will now
> also know the same thing.
>
> However, with the Optional to T method shadowing issue it seems we
> probably will need to require a keyword, or at the very least restrict
> automatic narrowing to polymorphism. For optionals the code will have to
> look something like this:
>
> func someMethod(foo:Foo?) {
> var bar:Foo? = nil
> if unwrap foo {
> bar = foo
> }
>
> if unwrap bar {
> bar.someMutatingMethod()
> }
> }
>
> The difference here is that unlike shadowing (if let foo = foo), if foo
> were mutable then it could still be mutated directly, no need to do it with
> force unwrapping. Of course in these simple examples you could just use the
> question mark operator instead, but pretend we're doing more than one thing
> per conditional 
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Haravikk via swift-evolution

> On 9 Nov 2016, at 12:19, Rien  wrote:
>> On 9 Nov 2016, at 06:51, David Hart  wrote:
>>> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution 
>>>  wrote:
>>> 
>>> This looks like a lot of complexity for very little gain.
>>> 
>>> Aside from any implementation concerns, this proposal substantially 
>>> increases the cognitive load on developers. To figure out what a piece of 
>>> code means, someone reading it will have to mentally keep track of a “type 
>>> stack” for every variable. That is the opposite of “clarity at the point of 
>>> use”.
>>> 
>>> Very well said. I think this is perhaps the number one complaint I have 
>>> about the proposal.
>> 
>> Did you see my response to this? There should be no particular cognitive 
>> load increase; think of the feature like type inference, the idea here is 
>> that the type-checker is gaining the same knowledge that you already have, 
>> i.e- you know something isn't nil, so the type-checker should too.
> 
> Locally in short routines yes.
> But in larger modules and non-local this does not apply.

I'm not sure what you mean; type-narrowing doesn't occur across scopes, 
ultimately you will always have some starting type where the variable was 
declared as a property, function argument or local variable, and it is narrow 
only where it is used, and the narrowing only occurs within that scope for as 
long as it is relevant.

In other words, the narrowing is always local. If you know your method takes an 
optional string for example then you know that that variable is still an 
optional string throughout that method, type-narrowing just helps to guarantee 
that it is nil or non-nil where you expect it to be.

> Imo it should always be possible to look at a type declaration and -from 
> that- derive all necessary knowledge about the type.

As I say, narrowing never changes the type; if you have a variable with a 
declared type of Foo, that is narrowed to Bar, then it is because Bar extends 
Foo and thus is compatible with it, giving you access to any additional methods 
of Bar without interfering with what you know of Foo.

> Besides when using a narrowed type as a parameter for an optional it must be 
> automatically be widened again? hence you would mentally keep track of the 
> status of that variable.

I'm not sure I follow this question; do you mean something like this:

func someMethod(foo:Foo?) {
var bar:Foo? = nil // bar is Optional.none
if (foo != nil) { // foo is Optional.some
bar = foo // both foo and bar are Optional.some
}
// both foo and bar are Optional (alternative branch 
places no mutual guarantee on type)
if bar != nil { // bar is Optional.some
bar.someMutatingMethod()
}
}

But these are all things that the developer knows; bar can't be non-nil until a 
value for it is set, foo is definitely non-nil within the block etc. The only 
difference here is that instead of the developer having to use ! unnecessarily 
(or risk making a mistake) they can just use their knowledge of what it is to 
interact directly, as the type-checker will now also know the same thing.

However, with the Optional to T method shadowing issue it seems we probably 
will need to require a keyword, or at the very least restrict automatic 
narrowing to polymorphism. For optionals the code will have to look something 
like this:

func someMethod(foo:Foo?) {
var bar:Foo? = nil
if unwrap foo {
bar = foo
}

if unwrap bar {
bar.someMutatingMethod()
}
}

The difference here is that unlike shadowing (if let foo = foo), if foo were 
mutable then it could still be mutated directly, no need to do it with force 
unwrapping. Of course in these simple examples you could just use the question 
mark operator instead, but pretend we're doing more than one thing per 
conditional ___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Rien via swift-evolution

> On 09 Nov 2016, at 10:51, Haravikk via swift-evolution 
>  wrote:
> 
> 
>> On 8 Nov 2016, at 12:22, ilya  wrote:
>> 
>> (1) You can define different methods with the same name on T and Optional 
>> (description is such an example). Then what does this do?
>> 
>> // someMethod is defined both for T and T?
>> // var foo: T?
>> if foo != nil {
>> foo.someMethod()
>> }
>> 
>> I say there is a clear expectation that foo.someMethod() should call the 
>> method of T?, even inside the if block, since this is how the dot works. 
>> However, according to the proposal it will call another method (or become an 
>> error?).
>> 
>> I think the languages that use optional narrowing are the ones where T? is 
>> not a separate type, so that it cannot have its own methods.
> 
> Hmm, that is definitely a wrinkle in the plan; it's very much an edge case 
> (someone defining something on optionals that they probably shouldn't) but 
> not an easy one to resolve. I suppose I'll have to amend the proposal to 
> suggest type widening in that case, such that you would need to use ! or ? as 
> normal to specify the unwrapped value. The tricky part is that it means the 
> value would have to be widened from the start, otherwise you'd be accessing 
> the value in two different ways in the same block of code, which would mean 
> that narrowing would need to be blocked if there's an incompatible statement 
> further down… ugh, perhaps a keyword will be necessary then? I was really 
> hoping to avoid having to add one though.
> 
>> (2) Should this work?
>> 
>> // compilcatedStuff is a method of T
>> // class A { var foo: T? }
>> 
>> if foo != nil {
>> foo.compilcatedStuff()
>> foo.compilcatedStuff()
>> foo.compilcatedStuff()
>> }
>> 
>> Suppose the compiler doesn't have enough information about compilcatedStuff 
>> to know what happens inside. Then it's possible that foo.compilcatedStuff 
>> will actually change foo (for example, foo could be a relationship and 
>> compilcatedStuff may be deleting the relationship). So, what is the 
>> suggestion for this example? Perhaps
>> 
>> if foo != nil {
>> foo.compilcatedStuff()
>> foo?.compilcatedStuff()
>> foo?.compilcatedStuff()
>> }
>> 
>> or some other choice?
> 
> What do you imagine being inside .complicatedStuff()? It shouldn't be 
> possible for it to change foo to nil, as even if .complicatedStuff() 
> reassigned this, it would be doing so as type T.
> 
>> On 9 Nov 2016, at 06:51, David Hart  wrote:
>>> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution 
>>>  wrote:
>>> 
>>> This looks like a lot of complexity for very little gain.
>>> 
>>> Aside from any implementation concerns, this proposal substantially 
>>> increases the cognitive load on developers. To figure out what a piece of 
>>> code means, someone reading it will have to mentally keep track of a “type 
>>> stack” for every variable. That is the opposite of “clarity at the point of 
>>> use”.
>> 
>> Very well said. I think this is perhaps the number one complaint I have 
>> about the proposal.
> 
> Did you see my response to this? There should be no particular cognitive load 
> increase; think of the feature like type inference, the idea here is that the 
> type-checker is gaining the same knowledge that you already have, i.e- you 
> know something isn't nil, so the type-checker should too.

Locally in short routines yes.
But in larger modules and non-local this does not apply.
Imo it should always be possible to look at a type declaration and -from that- 
derive all necessary knowledge about the type.
Besides when using a narrowed type as a parameter for an optional it must be 
automatically be widened again? hence you would mentally keep track of the 
status of that variable.





Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl




___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Haravikk via swift-evolution

> On 9 Nov 2016, at 10:00, ilya  wrote:
> 
> > What do you imagine being inside .complicatedStuff()? It shouldn't be 
> > possible for it to change foo to nil, as even if .complicatedStuff() 
> > reassigned this, it would be doing so as type T.
> 
> Why do you think so? All objects can be changed in any method. Let's rename 
> foo to pet and complicatedStuff to setFree to give a specific example:
> 
> class Pet {
> var owner: Person?
> func setFree() 
> {
>// Maintain the relationship correctness.
> owner?.pet = nil
> owner = nil
> }
> }
> 
> class Person { 
> 
> var pet: Pet? 
> 
> func ... {
>   if pet != nil {
> pet.setFree() // this sets pet = nil
> pet.setFree() //  what does this do 
> pet.setFree()
>   }
> }
> }

Ah, this comes back to the issue of class concurrency problems; the solution to 
this is that class references won't be narrowed, but the type-narrowing checks 
will still note cases that *could* have been narrowed, so that they can produce 
concurrency errors at runtime rather than the more generic error.

I just realised I never did provide a link to the working copy of the proposal, 
you can view some of the updates I've made here, which includes a note on 
classes and concurrency:
https://github.com/Haravikk/swift-evolution/blob/master/proposals/-type-narrowing.md

Though there is still a lot to do, especially if I'm going to have to change 
the proposal to use a keyword instead to avoid the Optional to T method 
shadowing problem.

So yeah, in other words I'm assuming narrowing only on structs, as these are 
the only types where it is possible for the type-checker to be certain; though 
this could be extended to classes in future if we gain some attribute for 
indicating when they are "safe" (e.g- changed through copy-on-write, thus safe 
for narrowing).
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread ilya via swift-evolution
> What do you imagine being inside .complicatedStuff()? It shouldn't be
possible for it to change foo to nil, as even if .complicatedStuff()
reassigned this, it would be doing so as type T.

Why do you think so? All objects can be changed in any method. Let's rename
foo to pet and complicatedStuff to setFree to give a specific example:

class Pet {
var owner: Person?
func setFree()
{
   // Maintain the relationship correctness.
owner?.pet = nil
owner = nil
}
}

class Person {

var pet: Pet?

func ... {
  if pet != nil {
pet.setFree() // this sets pet = nil
pet.setFree() //  what does this do 
pet.setFree()
  }
}
}

On Wed, Nov 9, 2016 at 10:51 AM Haravikk 
wrote:

> On 8 Nov 2016, at 12:22, ilya  wrote:
>
> (1) You can define different methods with the same name on T and
> Optional (description is such an example). Then what does this do?
>
> // someMethod is defined both for T and T?
> // var foo: T?
> if foo != nil {
> foo.someMethod()
> }
>
> I say there is a clear expectation that foo.someMethod() should call the
> method of T?, even inside the if block, since this is how the dot works.
> However, according to the proposal it will call another method (or become
> an error?).
>
> I think the languages that use optional narrowing are the ones where T? is
> not a separate type, so that it cannot have its own methods.
>
>
> Hmm, that is definitely a wrinkle in the plan; it's very much an edge case
> (someone defining something on optionals that they probably shouldn't) but
> not an easy one to resolve. I suppose I'll have to amend the proposal to
> suggest type widening in that case, such that you would need to use ! or ?
> as normal to specify the unwrapped value. The tricky part is that it means
> the value would have to be widened from the start, otherwise you'd be
> accessing the value in two different ways in the same block of code, which
> would mean that narrowing would need to be blocked if there's an
> incompatible statement further down… ugh, perhaps a keyword will be
> necessary then? I was really hoping to avoid having to add one though.
>
> (2) Should this work?
>
> // compilcatedStuff is a method of T
> // class A { var foo: T? }
>
> if foo != nil {
> foo.compilcatedStuff()
> foo.compilcatedStuff()
> foo.compilcatedStuff()
> }
>
> Suppose the compiler doesn't have enough information about
> compilcatedStuff to know what happens inside. Then it's possible
> that foo.compilcatedStuff will actually change foo (for example, foo could
> be a relationship and compilcatedStuff may be deleting the relationship).
> So, what is the suggestion for this example? Perhaps
>
> if foo != nil {
> foo.compilcatedStuff()
> foo?.compilcatedStuff()
> foo?.compilcatedStuff()
> }
>
> or some other choice?
>
>
> What do you imagine being inside .complicatedStuff()? It shouldn't be
> possible for it to change foo to nil, as even if .complicatedStuff()
> reassigned this, it would be doing so as type T.
>
> On 9 Nov 2016, at 06:51, David Hart  wrote:
>
> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution <
> swift-evolution@swift.org> wrote:
>
>
> This looks like a lot of complexity for very little gain.
>
>
> Aside from any implementation concerns, this proposal substantially
> increases the cognitive load on developers. To figure out what a piece of
> code means, someone reading it will have to mentally keep track of a “type
> stack” for every variable. That is the opposite of “clarity at the point of
> use”.
>
>
> Very well said. I think this is perhaps the number one complaint I have
> about the proposal.
>
>
> Did you see my response to this? There should be no particular cognitive
> load increase; think of the feature like type inference, the idea here is
> that the type-checker is gaining the same knowledge that you already have,
> i.e- you know something isn't nil, so the type-checker should too.
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Haravikk via swift-evolution

> On 8 Nov 2016, at 12:22, ilya  wrote:
> 
> (1) You can define different methods with the same name on T and Optional 
> (description is such an example). Then what does this do?
> 
> // someMethod is defined both for T and T?
> // var foo: T?
> if foo != nil {
> foo.someMethod()
> }
> 
> I say there is a clear expectation that foo.someMethod() should call the 
> method of T?, even inside the if block, since this is how the dot works. 
> However, according to the proposal it will call another method (or become an 
> error?).
> 
> I think the languages that use optional narrowing are the ones where T? is 
> not a separate type, so that it cannot have its own methods.

Hmm, that is definitely a wrinkle in the plan; it's very much an edge case 
(someone defining something on optionals that they probably shouldn't) but not 
an easy one to resolve. I suppose I'll have to amend the proposal to suggest 
type widening in that case, such that you would need to use ! or ? as normal to 
specify the unwrapped value. The tricky part is that it means the value would 
have to be widened from the start, otherwise you'd be accessing the value in 
two different ways in the same block of code, which would mean that narrowing 
would need to be blocked if there's an incompatible statement further down… 
ugh, perhaps a keyword will be necessary then? I was really hoping to avoid 
having to add one though.

> (2) Should this work?
> 
> // compilcatedStuff is a method of T
> // class A { var foo: T? }
> 
> if foo != nil {
> foo.compilcatedStuff()
> foo.compilcatedStuff()
> foo.compilcatedStuff()
> }
> 
> Suppose the compiler doesn't have enough information about compilcatedStuff 
> to know what happens inside. Then it's possible that foo.compilcatedStuff 
> will actually change foo (for example, foo could be a relationship and 
> compilcatedStuff may be deleting the relationship). So, what is the 
> suggestion for this example? Perhaps
> 
> if foo != nil {
> foo.compilcatedStuff()
> foo?.compilcatedStuff()
> foo?.compilcatedStuff()
> }
> 
> or some other choice?

What do you imagine being inside .complicatedStuff()? It shouldn't be possible 
for it to change foo to nil, as even if .complicatedStuff() reassigned this, it 
would be doing so as type T.

> On 9 Nov 2016, at 06:51, David Hart  wrote:
>> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution 
>> > wrote:
>> 
>> This looks like a lot of complexity for very little gain.
>> 
> 
>> Aside from any implementation concerns, this proposal substantially 
>> increases the cognitive load on developers. To figure out what a piece of 
>> code means, someone reading it will have to mentally keep track of a “type 
>> stack” for every variable. That is the opposite of “clarity at the point of 
>> use”.
> 
> Very well said. I think this is perhaps the number one complaint I have about 
> the proposal.


Did you see my response to this? There should be no particular cognitive load 
increase; think of the feature like type inference, the idea here is that the 
type-checker is gaining the same knowledge that you already have, i.e- you know 
something isn't nil, so the type-checker should too.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-09 Thread Rien via swift-evolution

> On 09 Nov 2016, at 07:51, David Hart via swift-evolution 
>  wrote:
> 
> 
>> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution 
>>  wrote:
>> 
>> This looks like a lot of complexity for very little gain.
>> 
>> Aside from any implementation concerns, this proposal substantially 
>> increases the cognitive load on developers. To figure out what a piece of 
>> code means, someone reading it will have to mentally keep track of a “type 
>> stack” for every variable. That is the opposite of “clarity at the point of 
>> use”.
> 
> Very well said. I think this is perhaps the number one complaint I have about 
> the proposal.

Exactly.
-1.


Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl




___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-08 Thread David Hart via swift-evolution

> On 3 Nov 2016, at 20:23, Nevin Brackett-Rozinsky via swift-evolution 
>  wrote:
> 
> This looks like a lot of complexity for very little gain.
> 
> Aside from any implementation concerns, this proposal substantially increases 
> the cognitive load on developers. To figure out what a piece of code means, 
> someone reading it will have to mentally keep track of a “type stack” for 
> every variable. That is the opposite of “clarity at the point of use”.

Very well said. I think this is perhaps the number one complaint I have about 
the proposal.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-08 Thread ilya via swift-evolution
If I correctly understand the proposal, I'm -1 on this.

(1) You can define different methods with the same name on T and
Optional (description is such an example). Then what does this do?

// someMethod is defined both for T and T?
// var foo: T?
if foo != nil {
foo.someMethod()
}

I say there is a clear expectation that foo.someMethod() should call the
method of T?, even inside the if block, since this is how the dot works.
However, according to the proposal it will call another method (or become
an error?).

I think the languages that use optional narrowing are the ones where T? is
not a separate type, so that it cannot have its own methods.

(2) Should this work?

// compilcatedStuff is a method of T
// class A { var foo: T? }

if foo != nil {
foo.compilcatedStuff()
foo.compilcatedStuff()
foo.compilcatedStuff()
}

Suppose the compiler doesn't have enough information about compilcatedStuff
to know what happens inside. Then it's possible that foo.compilcatedStuff
will actually change foo (for example, foo could be a relationship and
compilcatedStuff may be deleting the relationship). So, what is the
suggestion for this example? Perhaps

if foo != nil {
foo.compilcatedStuff()
foo?.compilcatedStuff()
foo?.compilcatedStuff()
}

or some other choice?


On Tue, Nov 8, 2016 at 9:44 AM Haravikk via swift-evolution <
swift-evolution@swift.org> wrote:

> On 7 Nov 2016, at 19:31, Charlie Monroe  wrote:
> There are two cases:
>
> if foo != nil {
> foo!.doSomething()
> }
>
>
> Currently, accessing a non-optional value with ! produces an error:
>
> let foo = Bar()
> foo!.doSomething() // ERROR
>
>
> Second:
>
> if foo != nil {
> // Using ? to be extra cautious, if foo is var
> foo?.doSomething()
> }
>
>
> This again currently produces an error:
>
> let foo = Bar()
> foo?.doSomething() // ERROR
>
>
> Which is generally, what would semantically happen - the variable would
> loose it optionality. Or am I wrong?
>
>
> I probably haven't clarified well enough but under type-narrowing these
> would be warnings rather than errors; i.e- the general type of foo is still
> Optional, the type-checker merely knows that it can't be nil at that point,
> so would inform you that the ? or ! are unnecessary.
>
> This is what I was trying to get at in the type-widening section;
> basically, if you have a variable whose type is narrowed, but do something
> that makes no sense for the narrowed type, then the type is widened until
> either a match is found or it can't go any wider (producing an error as
> normal).
>
> So in your examples foo is Optional.some, as a result the ? and !
> operators make no sense, so the type is widened back to Optional where
> it does make sense and the code compiles, but a warning is produced to
> inform you that you don't need to use those operators.
>
> On 7 Nov 2016, at 19:31, Charlie Monroe  wrote:
> I agree that designing a language around the compiler speed is wrong, but
> I believe designing the language without taking it into account is just as
> wrong. It's not worth designing features that would make the compilation so
> slow it would render the language unusable.
>
> Note that I have only very limited experience with compiler
> implementation, I've only made a few minor things with Clang a few years
> back, so please feel free to correct me.
>
>
> I'm not that familiar with the actual architecture either, but narrowing
> *should* be fairly simple; basically any time the compiler hits a condition
> or statement defined as a narrowing trigger, it pops the new narrower type
> onto a stack of types for that variable (in that branch). Now whenever the
> compiler reaches another statement for that variable (method call etc.) it
> resolves it first against the narrowest type, otherwise it goes up the
> stack (widening) till it finds a match or fails.
>
> When a branch closes with a stack of types, the compiler will compare to
> other branches to see which type is the narrowest that they have in common;
> this is actually fairly simple (shorten the stack for each branch to the
> length of the shortest stack, then discard elements until the current one
> is a match for all branches, thus you now know what the narrowest type is
> past that point).
>
> So, for types that never narrow there should be no speed difference, while
> for narrowed types there shouldn't be much of a difference, as these stacks
> of types shouldn't get very large in most cases (I'd expect anything more
> than three to be pretty rare).
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-08 Thread Haravikk via swift-evolution

> On 7 Nov 2016, at 19:31, Charlie Monroe  wrote:
> There are two cases:
> 
> if foo != nil { 
> foo!.doSomething() 
> }
> 
> Currently, accessing a non-optional value with ! produces an error:
> 
> let foo = Bar()
> foo!.doSomething() // ERROR
> 
> Second:
> 
> if foo != nil { 
> // Using ? to be extra cautious, if foo is var
> foo?.doSomething() 
> }
> 
> This again currently produces an error:
> 
> let foo = Bar()
> foo?.doSomething() // ERROR
> 
> Which is generally, what would semantically happen - the variable would loose 
> it optionality. Or am I wrong?

I probably haven't clarified well enough but under type-narrowing these would 
be warnings rather than errors; i.e- the general type of foo is still Optional, 
the type-checker merely knows that it can't be nil at that point, so would 
inform you that the ? or ! are unnecessary.

This is what I was trying to get at in the type-widening section; basically, if 
you have a variable whose type is narrowed, but do something that makes no 
sense for the narrowed type, then the type is widened until either a match is 
found or it can't go any wider (producing an error as normal).

So in your examples foo is Optional.some, as a result the ? and ! 
operators make no sense, so the type is widened back to Optional where it 
does make sense and the code compiles, but a warning is produced to inform you 
that you don't need to use those operators.

> On 7 Nov 2016, at 19:31, Charlie Monroe  wrote:
> I agree that designing a language around the compiler speed is wrong, but I 
> believe designing the language without taking it into account is just as 
> wrong. It's not worth designing features that would make the compilation so 
> slow it would render the language unusable.
> 
> Note that I have only very limited experience with compiler implementation, 
> I've only made a few minor things with Clang a few years back, so please feel 
> free to correct me.

I'm not that familiar with the actual architecture either, but narrowing 
*should* be fairly simple; basically any time the compiler hits a condition or 
statement defined as a narrowing trigger, it pops the new narrower type onto a 
stack of types for that variable (in that branch). Now whenever the compiler 
reaches another statement for that variable (method call etc.) it resolves it 
first against the narrowest type, otherwise it goes up the stack (widening) 
till it finds a match or fails.

When a branch closes with a stack of types, the compiler will compare to other 
branches to see which type is the narrowest that they have in common; this is 
actually fairly simple (shorten the stack for each branch to the length of the 
shortest stack, then discard elements until the current one is a match for all 
branches, thus you now know what the narrowest type is past that point).

So, for types that never narrow there should be no speed difference, while for 
narrowed types there shouldn't be much of a difference, as these stacks of 
types shouldn't get very large in most cases (I'd expect anything more than 
three to be pretty rare).___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Charlie Monroe via swift-evolution

> On Nov 7, 2016, at 8:03 PM, Haravikk  wrote:
> 
> 
>> On 7 Nov 2016, at 16:29, Charlie Monroe  wrote:
>> I'm simply worried a little about unwanted effects and additional compiler 
>> "cleverness".
> 
> I don't believe there should be any; either the type is narrowed or it isn't, 
> if you rely on it being a type the type-checker can't verify, you'll get an 
> error, otherwise you won't. There shouldn't be scope for anything unexpected.

True. 

I'm simply worried about the compiler speed in general, that's what I meant by 
"cleverness". The implicit variable typing and other features of Swift already 
IMHO make it incredibly slow and various features analyzing the code in order 
to determine the correct type can slow it even further. For comparison, a 
100KLOC project of mine in pure Swift takes about 8 minutes to compile, vs. 3 
minutes when it was in ObjC. With no optimizations turned on.

But I agree that designing a language around the compiler speed is wrong, but I 
believe designing the language without taking it into account is just as wrong. 
It's not worth designing features that would make the compilation so slow it 
would render the language unusable.

Note that I have only very limited experience with compiler implementation, 
I've only made a few minor things with Clang a few years back, so please feel 
free to correct me.

>> Xcode's migration is "nice", but I'd like to point out that migration to 
>> Swift 3 of my project took 6 hours (!) and I spent almost 2 more days 
>> manually changing what the migrator didn't manage to do on its own. And that 
>> was one of my projects. I really don't want to go through this once more.
> 
> I agree, but the only code that should be affected by this is code where 
> there is unwrapping that can be determined to either be redundant, or is 
> definitely incorrect; in the former case it will only be a warning (so you 
> can remove force unwrapping that is no longer needed) and in the latter it 
> will be an error because the type-checker has actually identified something 
> that will definitely cause a run-time error.


There are two cases:

if foo != nil { 
foo!.doSomething() 
}

Currently, accessing a non-optional value with ! produces an error:

let foo = Bar()
foo!.doSomething() // ERROR

Second:

if foo != nil { 
// Using ? to be extra cautious, if foo is var
foo?.doSomething() 
}

This again currently produces an error:

let foo = Bar()
foo?.doSomething() // ERROR

Which is generally, what would semantically happen - the variable would loose 
it optionality. Or am I wrong?

Which would require migration, where within all scopes, where you check if a a 
variable is not nil, it removes all ? and !...


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread T.J. Usiyan via swift-evolution
I am mostly opposed because I don't see how this could avoid being
complicated to explain compiler magic. Making this accessible as a feature
for our types and operations would be a challenge and doesn't look to have
a worthwhile yield for the effort. We can accomplish most, if not all, of
this with shadowing.

TJ

On Mon, Nov 7, 2016 at 2:03 PM, Haravikk via swift-evolution <
swift-evolution@swift.org> wrote:

>
> > On 7 Nov 2016, at 16:29, Charlie Monroe 
> wrote:
> > I'm simply worried a little about unwanted effects and additional
> compiler "cleverness".
>
> I don't believe there should be any; either the type is narrowed or it
> isn't, if you rely on it being a type the type-checker can't verify, you'll
> get an error, otherwise you won't. There shouldn't be scope for anything
> unexpected.
>
> > Xcode's migration is "nice", but I'd like to point out that migration to
> Swift 3 of my project took 6 hours (!) and I spent almost 2 more days
> manually changing what the migrator didn't manage to do on its own. And
> that was one of my projects. I really don't want to go through this once
> more.
>
> I agree, but the only code that should be affected by this is code where
> there is unwrapping that can be determined to either be redundant, or is
> definitely incorrect; in the former case it will only be a warning (so you
> can remove force unwrapping that is no longer needed) and in the latter it
> will be an error because the type-checker has actually identified something
> that will definitely cause a run-time error.
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Haravikk via swift-evolution

> On 7 Nov 2016, at 16:29, Charlie Monroe  wrote:
> I'm simply worried a little about unwanted effects and additional compiler 
> "cleverness".

I don't believe there should be any; either the type is narrowed or it isn't, 
if you rely on it being a type the type-checker can't verify, you'll get an 
error, otherwise you won't. There shouldn't be scope for anything unexpected.

> Xcode's migration is "nice", but I'd like to point out that migration to 
> Swift 3 of my project took 6 hours (!) and I spent almost 2 more days 
> manually changing what the migrator didn't manage to do on its own. And that 
> was one of my projects. I really don't want to go through this once more.

I agree, but the only code that should be affected by this is code where there 
is unwrapping that can be determined to either be redundant, or is definitely 
incorrect; in the former case it will only be a warning (so you can remove 
force unwrapping that is no longer needed) and in the latter it will be an 
error because the type-checker has actually identified something that will 
definitely cause a run-time error.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Nevin Brackett-Rozinsky via swift-evolution
The more I think about it, the more I realize what I actually want is an
“alias” or “view” or “lens” that will let me give a new name to an existing
entity, without copying or moving it.

This is useful in general if you need to work “down the rabbit hole”, so
you could write something like:

alias size = anArray[idx].someProperty.size
// Work with “size” as a shorthand, including mutations

In the situation from my previous example, where we only want to take
action when the nested property is a certain type, it might look like:

if alias b = c.a as? B {
b.x = 12
}

I think this sort of feature is far more versatile than type-narrowing, and
it retains the clarity of type information in source code.

Nevin


On Sun, Nov 6, 2016 at 10:52 PM, Chris Lattner via swift-evolution <
swift-evolution@swift.org> wrote:

>
> > On Nov 3, 2016, at 10:04 AM, Haravikk via swift-evolution <
> swift-evolution@swift.org> wrote:
> >
> > To avoid hijacking the guard let x = x thread entirely I've decided to
> try to write up a proposal on type narrowing in Swift.
> > Please give your feedback on the functionality proposed, as well as the
> clarity of the proposal/examples themselves; I've tried to keep it
> straightforward, but I do tend towards being overly verbose, I've always
> tried to have the examples build upon one another to show how it all stacks
> up.
>
> FWIW, we have specifically considered something like this proposal in the
> past.  You didn’t mention it, but the ?: operator is a specific example
> that frequently comes up.  People often expect to be able to do something
> like:
>
> … = foo is B ? foo.bMethod() : …
>
> which is the same sort of flow sensitive type refinement as you’re
> proposing here.  This topic also came up in the design discussion around
> #available (which shipped in Swift 2, but was discussed much earlier),
> because unavailable decls could be available as optionals when not
> specifically checked for.
>
> This is just MHO, but while I have been in favor of this in the (distant)
> past, I became convinced that this would be a bad idea when it comes to
> code maintenance over the long term.  With our current (intentional
> shadowing based) design, you can always jump to the definition of a value
> to see where it was defined, and definitions always specify a type.
> Introducing flow senstitive type refinement breaks this model because the
> type of a decl depends not just on its declaration, but on a potentially
> arbitrary number of imperative checks that occur between the declaration
> and the use.  This can make it much more difficult to understand code.
>
> -Chris
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Charlie Monroe via swift-evolution

> On Nov 7, 2016, at 2:08 PM, Haravikk  wrote:
> 
> 
>> On 7 Nov 2016, at 11:58, Charlie Monroe > > wrote:
>> 
>> I'd personally not make this automatic, but require explicit action from the 
>> developer.
>> 
>> In case of nullability, I have previously suggested "nonnil" keyword:
>> 
>> let foo: String? = "Hello World"
>> guard nonnil foo else {
>> return
>> }
>> 
>> In which way you explicitly request the type narrowing. Or:
>> 
>> let foo: Any
>> guard foo as String else {
>> return
>> }
>> 
>> I.e. not using "is" which returns a boolean, but using the cast operator, 
>> which IMHO makes more sense and prevents from unintentional type narrowing…
> 
> Normally I'm a proponent of being more rather than less explicit, but the 
> biggest draw of type-narrowing to me is that you're *already* telling the 
> type-checker, it's really just confirming what you know automatically.
> 
> So if I do:
> 
>   if foo is String {
>   // Do lots of non-string stuff
>   (foo as String).somethingStringSpecific
>   }
> 
> On the last line of the block the type-checker is able to remind me that I 
> already know that foo is a String, so I don't need to cast it.
> 
> Really when it comes down to it the type-narrowing never takes anything away 
> from you; you can always handle the value as a less specific (wider) type if 
> you want to, but if you want to treat it like a String because you know it's 
> one, then you can do that too.
> 
> I'm concerned that if the feature had to be explicit, it would lack 
> discoverability, and really the point is almost to get rid of the need to do 
> things explicitly when you don't need to. It's like type inference on 
> overdrive in a way.
> 
> 
> I guess I just don't see why you'd think that "guard nonnil foo" is really 
> more explicit than "guard foo != nil", in both cases you know that foo can't 
> be nil past that point, so is a new keyword really justified?

I'm simply worried a little about unwanted effects and additional compiler 
"cleverness". I'd simply much rather opt-in to it using a keyword or a slightly 
different syntax. And instead of

if foo is String { ... }

I'd prefer

if foo as? String { ... }

which is syntactically closer to

if let foo = foo as? String { ... }

which is generally what we're after.

Also, it would maintain code compatibility. The current proposal would change 
semantics of the code - mostly when comparing to nil.

Xcode's migration is "nice", but I'd like to point out that migration to Swift 
3 of my project took 6 hours (!) and I spent almost 2 more days manually 
changing what the migrator didn't manage to do on its own. And that was one of 
my projects. I really don't want to go through this once more.

Not to mention the already growing non-macOS base of Swift users.

I know now is the time for the last incompatible changes, but are the benefits 
of implicit type narrowing so great to warrant this?


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Haravikk via swift-evolution

> On 7 Nov 2016, at 11:58, Charlie Monroe  wrote:
> 
> I'd personally not make this automatic, but require explicit action from the 
> developer.
> 
> In case of nullability, I have previously suggested "nonnil" keyword:
> 
> let foo: String? = "Hello World"
> guard nonnil foo else {
> return
> }
> 
> In which way you explicitly request the type narrowing. Or:
> 
> let foo: Any
> guard foo as String else {
> return
> }
> 
> I.e. not using "is" which returns a boolean, but using the cast operator, 
> which IMHO makes more sense and prevents from unintentional type narrowing…

Normally I'm a proponent of being more rather than less explicit, but the 
biggest draw of type-narrowing to me is that you're *already* telling the 
type-checker, it's really just confirming what you know automatically.

So if I do:

if foo is String {
// Do lots of non-string stuff
(foo as String).somethingStringSpecific
}

On the last line of the block the type-checker is able to remind me that I 
already know that foo is a String, so I don't need to cast it.

Really when it comes down to it the type-narrowing never takes anything away 
from you; you can always handle the value as a less specific (wider) type if 
you want to, but if you want to treat it like a String because you know it's 
one, then you can do that too.

I'm concerned that if the feature had to be explicit, it would lack 
discoverability, and really the point is almost to get rid of the need to do 
things explicitly when you don't need to. It's like type inference on overdrive 
in a way.


I guess I just don't see why you'd think that "guard nonnil foo" is really more 
explicit than "guard foo != nil", in both cases you know that foo can't be nil 
past that point, so is a new keyword really justified?___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Charlie Monroe via swift-evolution
I'd personally not make this automatic, but require explicit action from the 
developer.

In case of nullability, I have previously suggested "nonnil" keyword:

let foo: String? = "Hello World"
guard nonnil foo else {
return
}

In which way you explicitly request the type narrowing. Or:

let foo: Any
guard foo as String else {
return
}

I.e. not using "is" which returns a boolean, but using the cast operator, which 
IMHO makes more sense and prevents from unintentional type narrowing...


> On Nov 7, 2016, at 12:34 PM, Haravikk via swift-evolution 
>  wrote:
> 
> 
>> On 7 Nov 2016, at 03:52, Chris Lattner > > wrote:
>> Introducing flow senstitive type refinement breaks this model because the 
>> type of a decl depends not just on its declaration, but on a potentially 
>> arbitrary number of imperative checks that occur between the declaration and 
>> the use.  This can make it much more difficult to understand code.
> 
> This seems like more of a challenge for the IDE; if it can tap into the 
> type-checker then it can determine what the narrowed type is at any given 
> point in your code, indeed I would expect it to for the purposes of 
> auto-completion anyway. I know you don't necessarily want a language that's 
> reliant on good IDE support, but if you're doing something complex enough 
> where this would become a problem and NOT using a good IDE then it seems kind 
> of like a self-inflicted problem to me.
> 
> Even so there's nothing in this feature that would prevent you from using 
> shadowing if you want to, for example if a block is especially large and you 
> feel it adds clarity.
> 
> Actually though I'd say that for maintenance narrowing may be better, as it 
> can clarify what a type is supposed to be at a given point, and if you break 
> the narrowing then you'll create errors and warning that show you how you've 
> changed the meaning of the code. Consider for example:
> 
>   func doSomething(value:Int?) {
>   if (value == nil) { value = 5 } // value is narrow to 
> Optional.some
> 
>   // Lots of really important code that never causes value to 
> become nil
> 
>   print(value!.description)
>   }
> 
> Say you come back later and decide to remove the conditional at the top, now 
> that value!, though a fair assumption at the time, can cause a runtime 
> failure. With narrowing however you wouldn't have had to force unwrap because 
> of the known non-nil value, but your change will break that, resulting in an 
> error that forces you to fix it.
> 
> 
> I'm still struggling how best to phrase my motivation section; so far I seem 
> to have an increasingly large grab-bag of individual problems that 
> type-narrowing can solve, with no way to put it more succinctly.
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-07 Thread Haravikk via swift-evolution

> On 7 Nov 2016, at 03:52, Chris Lattner  wrote:
> Introducing flow senstitive type refinement breaks this model because the 
> type of a decl depends not just on its declaration, but on a potentially 
> arbitrary number of imperative checks that occur between the declaration and 
> the use.  This can make it much more difficult to understand code.

This seems like more of a challenge for the IDE; if it can tap into the 
type-checker then it can determine what the narrowed type is at any given point 
in your code, indeed I would expect it to for the purposes of auto-completion 
anyway. I know you don't necessarily want a language that's reliant on good IDE 
support, but if you're doing something complex enough where this would become a 
problem and NOT using a good IDE then it seems kind of like a self-inflicted 
problem to me.

Even so there's nothing in this feature that would prevent you from using 
shadowing if you want to, for example if a block is especially large and you 
feel it adds clarity.

Actually though I'd say that for maintenance narrowing may be better, as it can 
clarify what a type is supposed to be at a given point, and if you break the 
narrowing then you'll create errors and warning that show you how you've 
changed the meaning of the code. Consider for example:

func doSomething(value:Int?) {
if (value == nil) { value = 5 } // value is narrow to 
Optional.some

// Lots of really important code that never causes value to 
become nil

print(value!.description)
}

Say you come back later and decide to remove the conditional at the top, now 
that value!, though a fair assumption at the time, can cause a runtime failure. 
With narrowing however you wouldn't have had to force unwrap because of the 
known non-nil value, but your change will break that, resulting in an error 
that forces you to fix it.


I'm still struggling how best to phrase my motivation section; so far I seem to 
have an increasingly large grab-bag of individual problems that type-narrowing 
can solve, with no way to put it more succinctly.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-06 Thread Jean-Daniel via swift-evolution

> Le 7 nov. 2016 à 04:52, Chris Lattner via swift-evolution 
>  a écrit :
> 
> 
>> On Nov 3, 2016, at 10:04 AM, Haravikk via swift-evolution 
>>  wrote:
>> 
>> To avoid hijacking the guard let x = x thread entirely I've decided to try 
>> to write up a proposal on type narrowing in Swift.
>> Please give your feedback on the functionality proposed, as well as the 
>> clarity of the proposal/examples themselves; I've tried to keep it 
>> straightforward, but I do tend towards being overly verbose, I've always 
>> tried to have the examples build upon one another to show how it all stacks 
>> up.
> 
> FWIW, we have specifically considered something like this proposal in the 
> past.  You didn’t mention it, but the ?: operator is a specific example that 
> frequently comes up.  People often expect to be able to do something like:
> 
>   … = foo is B ? foo.bMethod() : …
> 

For the case of the ?: operator, I think it can be replaced by a ?? operator 
for most cases:

… = (foo as B)?.bMethod() ?? …


___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-06 Thread Chris Lattner via swift-evolution

> On Nov 3, 2016, at 10:04 AM, Haravikk via swift-evolution 
>  wrote:
> 
> To avoid hijacking the guard let x = x thread entirely I've decided to try to 
> write up a proposal on type narrowing in Swift.
> Please give your feedback on the functionality proposed, as well as the 
> clarity of the proposal/examples themselves; I've tried to keep it 
> straightforward, but I do tend towards being overly verbose, I've always 
> tried to have the examples build upon one another to show how it all stacks 
> up.

FWIW, we have specifically considered something like this proposal in the past. 
 You didn’t mention it, but the ?: operator is a specific example that 
frequently comes up.  People often expect to be able to do something like:

… = foo is B ? foo.bMethod() : …

which is the same sort of flow sensitive type refinement as you’re proposing 
here.  This topic also came up in the design discussion around #available 
(which shipped in Swift 2, but was discussed much earlier), because unavailable 
decls could be available as optionals when not specifically checked for.

This is just MHO, but while I have been in favor of this in the (distant) past, 
I became convinced that this would be a bad idea when it comes to code 
maintenance over the long term.  With our current (intentional shadowing based) 
design, you can always jump to the definition of a value to see where it was 
defined, and definitions always specify a type.  Introducing flow senstitive 
type refinement breaks this model because the type of a decl depends not just 
on its declaration, but on a potentially arbitrary number of imperative checks 
that occur between the declaration and the use.  This can make it much more 
difficult to understand code.

-Chris
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-06 Thread Haravikk via swift-evolution

> On 3 Nov 2016, at 22:56, Nevin Brackett-Rozinsky 
>  wrote:
> 
> Okay, I think I found an actual shortcoming that type narrowing might 
> address, namely mutating a property in place if it is a subtype. Here is a 
> small example setup:
> 
> protocol A { var x: Int {get} }
> struct B: A { var x: Int }
> struct C { var a: A }
> var c = C(a: B(x: 4))
> 
> Note that “A” does not promise the “x” property will be mutable, while B 
> does. I use “x: Int” as a minimal example, but any solution should also work 
> for more complex scenarios.
> 
> Now suppose we wish to test whether “c.a” is of type B, and if so change its 
> “x” value. We could, of course, make a local copy, mutate it, and reassign to 
> “c.a”. But if those operations are expensive we would rather avoid doing so. 
> And if B uses copy-on-write, we would want to remove the value from “c” 
> entirely so that we hopefully have a unique reference. This is hard to get 
> right.
> 
> We would prefer to write something like the following:
> 
> (c.a as? B)?.x = 12
> 
> But that does not currently work, resulting in the error “Cannot assign to 
> immutable expression of type 'Int'”.
> 
> Will the proposed type-narrowing feature provide a simple way to mutate “c.a” 
> in place, contingent upon its being of type B?
> How does it compare to an alternative such as inout return values, which 
> could preserve mutability in the above?

That's a good example, and yes it should be possible for type-narrowing to 
simplify stuff like this, I'll add a section on that I should probably go into 
more detail on how I intend working with narrowed mutable values to work, as 
for the advantage vs inout it's really just a matter of simplicity I think; 
using type narrowing should allow it to just work without having to pass to 
methods or design the API specifically for that kind of thing.



> If we are going to have any sort of type narrowing, I would strongly prefer 
> that it be explicit. For example we could use a keyword such as “rebind” to 
> narrow the type of an existing symbol in a scope:
> 
> if rebind c.a as B {
> c.a.x = 12
> }

I don't see what's really gained by making it explicit vs implicit; if the 
condition was c.a is B then I'm not sure how that's any less clear?

> Furthermore, I think the proposal to treat enum cases as types is a major 
> change to Swift’s type system, and probably introduces many unforeseen 
> headaches. It also smells somewhat of a backdoor way for union types to sneak 
> into the language.

I'd say that in a sense enums are types, after all they can have unique 
associated value types of their own. Really though my intent is primarily to 
support optionals, but I figure it makes sense to try and do it from the 
perspective of general purpose enums since that's all optionals really are 
anyway.


Also, I've been thinking about thread safety and it occurs to me that type 
narrowing could actually be of significant benefit to it, rather than a 
detriment.

Consider:

struct Foo { var value:Int }
struct Bar { var foo?:Foo }

var a = Foo(value: 5)
var b = Bar(foo: a)

b.foo.value = 10

Now, in this case we're only dealing with structs, and we know that b.foo has a 
value, thus b.foo.value is nice and safe; in fact no force unwrapping needs to 
occur behind the scenes, it can optimise away completely.

Instead, let's assume Bar is a class we're handling in a potentially shared way:

class Bar { var foo?:Foo }

func myMethod(bar:Bar) {
b.foo = new Foo(5) // We now know that b.foo shouldn't be nil
b.foo!.value = 10
}

In this case, since Bar is a class we don't have total control over, we can't 
be certain that b.foo is non-nil when we try to modify it a second time; as a 
result, type-narrowing won't occur (because it's a class from another scope), 
however, because the type-checker knows that bar.foo should have a value, we 
can actually issue a more informative error message if force unwrapping fails, 
e.g- concurrent modification error.

In other words, we can potentially use it to help detect concurrency issues. 
It's another thing that's going to require a section on the proposal though, I 
have a feeling it's going to get pretty big!___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-03 Thread Nevin Brackett-Rozinsky via swift-evolution
Okay, I think I found an actual shortcoming that type narrowing might
address, namely mutating a property in place if it is a subtype. Here is a
small example setup:

protocol A { var x: Int {get} }
struct B: A { var x: Int }
struct C { var a: A }
var c = C(a: B(x: 4))

Note that “A” does not promise the “x” property will be mutable, while B
does. I use “x: Int” as a minimal example, but any solution should also
work for more complex scenarios.

Now suppose we wish to test whether “c.a” is of type B, and if so change
its “x” value. We could, of course, make a local copy, mutate it, and
reassign to “c.a”. But if those operations are expensive we would rather
avoid doing so. And if B uses copy-on-write, we would want to remove the
value from “c” entirely so that we hopefully have a unique reference. This
is hard to get right.

We would prefer to write something like the following:

(c.a as? B)?.x = 12

But that does not currently work, resulting in the error “Cannot assign to
immutable expression of type 'Int'”.

Will the proposed type-narrowing feature provide a simple way to mutate
“c.a” in place, contingent upon its being of type B?

How does it compare to an alternative such as inout return values, which
could preserve mutability in the above?

• • •

If we are going to have any sort of type narrowing, I would strongly prefer
that it be explicit. For example we could use a keyword such as “rebind” to
narrow the type of an existing symbol in a scope:

if rebind c.a as B {
c.a.x = 12
}

Furthermore, I think the proposal to treat enum cases as types is a major
change to Swift’s type system, and probably introduces many unforeseen
headaches. It also smells somewhat of a backdoor way for union types to
sneak into the language.

Also, irrespective of everything else, you really need to make the
“Motivation” section of your proposal a lot stronger. That section should
stand on its own and make people understand exactly what problem you are
trying to solve and why it is important.

Nevin


On Thu, Nov 3, 2016 at 5:43 PM, Haravikk 
wrote:

>
> On 3 Nov 2016, at 19:23, Nevin Brackett-Rozinsky <
> nevin.brackettrozin...@gmail.com> wrote:
> For the motivating examples, there is already a much cleaner solution:
> (foo as? B)?.someMethodSpecificToB()
>
>
> Eh, kinda; you've taken an example showing branching and boiled it down
> into a single line; what if my intention was to call multiple B specific
> methods on foo? I think you've seen a simple example and tried to simplify
> it further, but I suppose I could put another method call in it to clarify.
>
> Aside from any implementation concerns, this proposal substantially
> increases the cognitive load on developers.
>
>
> I'm not so sure of this; the type is never going to be wider than what you
> originally set, so at the very least you can do whatever its original
> explicit type or inferred type would let you do, the main difference is
> that if you do something that makes no sense anymore then the type-checker
> can inform you of this. Otherwise if you know you've narrowed the type,
> then you can do things with that narrowed type and either the type-checker
> will allow it, or inform you that it's not possible, thus warning you that
> your conditional(s) etc. don't work as intended.
>
> Really the burden is no different to the techniques that already exist; if
> you've tested a value with `is` then *you* know what the type is within
> that block of code, this is just ensuring that the type checker also knows
> it. Likewise with an optional, if you test that it's not nil then you know
> it's not, and so should the type-checker.
>
> I should probably put more under motivation about why this feature works
> for the example cases given, and what the impact is on a larger scale; as
> the narrowing has the potential to pick up a bunch of little errors that
> standard type-checking alone may not, the trick is coming up with the
> example code to show it that isn't enormous, as I'm trying to avoid too
> much complexity in the Motivation section so I can build up the examples;
> maybe I'll add an "Advantages" section further down to detail more of what
> can be done *after* demonstrating the feature in stages, rather than trying
> to do it at the start.
>
> the proposed “solution” has the same concurrency failure, but hides it
> even worse because the force-unwrap operator doesn’t even appear in the
> code:
>
> var foo:A? = A()
> if foo != nil {
>foo.someMethod()  // Bad news!
>foo.someMutatingMethod()  // Bad news!
> }
>
>
> Actually the issue *is* visible in the code; it's the conditional. If you
> can't trust `foo` not to change then testing its value and then acting upon
> the result without some form of local copy or locking is the part that
> explicitly isn't thread safe.
>
> I'm not really sure of the need to focus on thread safety issues here as
> I'm not sure they're unique to this feature, or even to optionals; 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-03 Thread Haravikk via swift-evolution

> On 3 Nov 2016, at 19:23, Nevin Brackett-Rozinsky 
>  wrote:
> For the motivating examples, there is already a much cleaner solution:
> (foo as? B)?.someMethodSpecificToB()

Eh, kinda; you've taken an example showing branching and boiled it down into a 
single line; what if my intention was to call multiple B specific methods on 
foo? I think you've seen a simple example and tried to simplify it further, but 
I suppose I could put another method call in it to clarify.

> Aside from any implementation concerns, this proposal substantially increases 
> the cognitive load on developers.

I'm not so sure of this; the type is never going to be wider than what you 
originally set, so at the very least you can do whatever its original explicit 
type or inferred type would let you do, the main difference is that if you do 
something that makes no sense anymore then the type-checker can inform you of 
this. Otherwise if you know you've narrowed the type, then you can do things 
with that narrowed type and either the type-checker will allow it, or inform 
you that it's not possible, thus warning you that your conditional(s) etc. 
don't work as intended.

Really the burden is no different to the techniques that already exist; if 
you've tested a value with `is` then you know what the type is within that 
block of code, this is just ensuring that the type checker also knows it. 
Likewise with an optional, if you test that it's not nil then you know it's 
not, and so should the type-checker.

I should probably put more under motivation about why this feature works for 
the example cases given, and what the impact is on a larger scale; as the 
narrowing has the potential to pick up a bunch of little errors that standard 
type-checking alone may not, the trick is coming up with the example code to 
show it that isn't enormous, as I'm trying to avoid too much complexity in the 
Motivation section so I can build up the examples; maybe I'll add an 
"Advantages" section further down to detail more of what can be done *after* 
demonstrating the feature in stages, rather than trying to do it at the start.

> the proposed “solution” has the same concurrency failure, but hides it even 
> worse because the force-unwrap operator doesn’t even appear in the code:
> 
> var foo:A? = A()
> if foo != nil {
>foo.someMethod()  // Bad news!
>foo.someMutatingMethod()  // Bad news!
> }

Actually the issue is visible in the code; it's the conditional. If you can't 
trust `foo` not to change then testing its value and then acting upon the 
result without some form of local copy or locking is the part that explicitly 
isn't thread safe.

I'm not really sure of the need to focus on thread safety issues here as I'm 
not sure they're unique to this feature, or even to optionals; anything that is 
part of a shared class and thus potentially shared with other threads is 
unsafe, whether it's optional or not. While optionals might produce errors if 
force unwrapped and nil, they just as easily might not but end up with 
inconsistent values instead, so I'm not sure having the force unwrap operators 
actually makes you any safer; put another way, if you're relying on force 
unwrapping to catch thread safety issues then I'm not sure that's a good 
strategy, as it can only detect the issues at runtime, and only if the exact 
conditions necessary actually occur to trigger the failure.

I don't know what's planned for Swift's native concurrency support, but 
personally I'm hoping we might get a feature of classes that requires them 
(and/or their methods) to be marked as explicitly safe (except where it can be 
inferred), producing warnings otherwise, forcing developers to consider if 
their type/method has been properly reviewed for thread safety. Thread safety 
after all really is specific to classes, which are mostly discouraged in Swift 
anyway, so it makes sense to focus efforts towards making classes safer, and 
that you're handling your struct copies efficiently.

>> On Thu, Nov 3, 2016 at 1:04 PM, Haravikk via swift-evolution 
>> > wrote:
>> 
>> To avoid hijacking the guard let x = x thread entirely I've decided to try 
>> to write up a proposal on type narrowing in Swift.
>> Please give your feedback on the functionality proposed, as well as the 
>> clarity of the proposal/examples themselves; I've tried to keep it 
>> straightforward, but I do tend towards being overly verbose, I've always 
>> tried to have the examples build upon one another to show how it all stacks 
>> up.
>> 
>> 
>> 
>> Type Narrowing
>> 
>> Proposal: SE- 
>> 
>> Author: Haravikk 
>> Status: Awaiting review
>> Review manager: TBD
>>  
>> Introduction
>> 
>> This 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-03 Thread Xiaodi Wu via swift-evolution
This proposal seems well-reasoned, but like Nevin I worry about the
interactions between type narrowing, reference types or capture of mutable
values, and concurrency or async. How will these things play together?

On Thu, Nov 3, 2016 at 14:23 Nevin Brackett-Rozinsky via swift-evolution <
swift-evolution@swift.org> wrote:

> This looks like a lot of complexity for very little gain.
>
> Aside from any implementation concerns, this proposal substantially
> increases the cognitive load on developers. To figure out what a piece of
> code means, someone reading it will have to mentally keep track of a “type
> stack” for every variable. That is the opposite of “clarity at the point of
> use”.
>
> For the motivating examples, there is already a much cleaner solution:
>
> (foo as? B)?.someMethodSpecificToB()
>
> Even in the case where foo gets passed as an argument to a function that
> takes a B, so optional chaining is not available, we are still okay. If foo
> is an instance of a struct, then passing it to a function won’t change its
> value so we can write:
>
> if let newFoo = foo as? B {
> funcThatTakesB(newFoo)
> }
>
> And if foo is an instance of a class, then the same thing *still* works,
> because any changes the function makes to newFoo are also observed in foo
> since they reference the same object.
>
> • • •
>
> The proposal’s other example is actually a great illustration of why
> shadowing is undesirable. After all, simply binding to a different name
> solves the so-called problem, *and* lets us bind to a constant:
>
> var foo: A? = A()
> if let newFoo = foo {
> newFoo.someMethod()
> foo!.someMutatingMethod()  // Works now!
> }
>
> Full disclosure: both this and the original example have a *deeper*
> problem, which is that they are not thread-safe. If foo is modified between
> the conditional binding and the force-unwrap, the force-unwrap could fail.
> Sure, that can’t happen when foo is a local variable like this, but if it
> were a property of a class then it could.
>
> Moreover, the proposed “solution” has the same concurrency failure, but
> hides it even worse because the force-unwrap operator doesn’t even appear
> in the code:
>
> var foo:A? = A()
> if foo != nil {
>foo.someMethod()  // Bad news!
>foo.someMutatingMethod()  // Bad news!
> }
>
> In summary, I do not see sufficient motivation for this proposal. The
> motivation which I do see appears superfluous. The problem being described
> already has an elegant solution in Swift. And the proposed changes
> introduce an exceptionally taxing cognitive burden on developers just to
> figure out what the type of a variable is on any given line of code.
>
> Plus, in the face of concurrency, such implicit type-narrowing has the
> potential to hide serious issues.
>
> Nevin
>
>
> On Thu, Nov 3, 2016 at 1:04 PM, Haravikk via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> To avoid hijacking the guard let x = x thread entirely I've decided to try
> to write up a proposal on type narrowing in Swift.
> Please give your feedback on the functionality proposed, as well as the
> clarity of the proposal/examples themselves; I've tried to keep it
> straightforward, but I do tend towards being overly verbose, I've always
> tried to have the examples build upon one another to show how it all stacks
> up.
>
>
>
> Type Narrowing
>
>- Proposal: SE-
>
> 
>- Author: Haravikk 
>- Status: Awaiting review
>- Review manager: TBD
>
>
> 
> Introduction
>
> This proposal is to introduce type-narrowing to Swift, enabling the
> type-checker to automatically infer a narrower type from context such as
> conditionals.
>
> Swift-evolution thread: Discussion thread topic for that proposal
> 
>
> 
> Motivation
>
> Currently in Swift there are various pieces of boilerplate required in
> order to manually narrow types. The most obvious is in the case of
> polymorphism:
>
> let foo:A = B() // B extends A
> if foo is B {
> (foo as B).someMethodSpecificToB()
> }
>
> But also in the case of unwrapping of optionals:
>
> var foo:A? = A()
> if var foo = foo { // foo is now unwrapped and shadowed
> foo.someMethod()
> foo!.someMutatingMethod() // Can't be done
> }
>
>
> Proposed
> solution
>
> The proposed solution to the boiler-plate is to introduce type-narrowing,
> essentially a finer grained knowledge of type based upon context. Thus as
> any contextual clue indicating a more or less specific type are
> encountered, the type of the variable will reflect this from that point
> onwards.
>
> 

Re: [swift-evolution] [Proposal] Type Narrowing

2016-11-03 Thread Callionica (Swift) via swift-evolution
Great. I'd like to see something like this. Couple of comments:

You don't explicitly address overload selection. Do you intend it to
be affected?

Impact on existing code section could be more descriptive.

On Thursday, November 3, 2016, Haravikk via swift-evolution <
swift-evolution@swift.org> wrote:

> To avoid hijacking the guard let x = x thread entirely I've decided to try
> to write up a proposal on type narrowing in Swift.
> Please give your feedback on the functionality proposed, as well as the
> clarity of the proposal/examples themselves; I've tried to keep it
> straightforward, but I do tend towards being overly verbose, I've always
> tried to have the examples build upon one another to show how it all stacks
> up.
>
>
>
> Type Narrowing
>
>- Proposal: SE-
>
> 
>- Author: Haravikk 
>- Status: Awaiting review
>- Review manager: TBD
>
>
> 
> Introduction
>
> This proposal is to introduce type-narrowing to Swift, enabling the
> type-checker to automatically infer a narrower type from context such as
> conditionals.
>
> Swift-evolution thread: Discussion thread topic for that proposal
> 
>
> 
> Motivation
>
> Currently in Swift there are various pieces of boilerplate required in
> order to manually narrow types. The most obvious is in the case of
> polymorphism:
>
> let foo:A = B() // B extends A
> if foo is B {
> (foo as B).someMethodSpecificToB()
> }
>
> But also in the case of unwrapping of optionals:
>
> var foo:A? = A()
> if var foo = foo { // foo is now unwrapped and shadowed
> foo.someMethod()
> foo!.someMutatingMethod() // Can't be done
> }
>
>
> Proposed
> solution
>
> The proposed solution to the boiler-plate is to introduce type-narrowing,
> essentially a finer grained knowledge of type based upon context. Thus as
> any contextual clue indicating a more or less specific type are
> encountered, the type of the variable will reflect this from that point
> onwards.
>
> Detailed
> design
>
> The concept of type-narrowing would essentially treat all variables as
> having not just a single type, but instead as having a stack of
> increasingly specific (narrow) types.
>
> Whenever a contextual clue such as a conditional is encountered, the type
> checker will infer whether this narrows the type, and add the new narrow
> type to the stack from that point onwards. Whenever the type widens again
> narrower types are popped from the stack.
>
> Here are the above examples re-written to take advantage of type-narrowing:
>
> let foo:A = B() // B extends A
> if foo is B { // B is added to foo's type stack
> foo.someMethodSpecificToB()
> }
> // B is popped from foo's type stack
>
> var foo:A? = A()
> if foo != nil { // Optional.some is added to foo's type stack
>foo.someMethod()
>foo.someMutatingMethod() // Can modify mutable original
> }
> // Optional.some is popped from foo's type stack
>
>
> Enum
> Types
>
> As seen in the simple optional example, to implement optional support each
> case in an enum is considered be a unique sub-type of the enum itself,
> thus allowing narrowing to nil (.none) and non-nil (.some) types.
>
> This behaviour actually enables some other useful behaviours,
> specifically, if a value is known to be either nil or non-nil then the
> need to unwrap or force unwrap the value can be eliminated entirely, with
> the compiler able to produce errors if these are used incorrectly, for
> example:
>
> var foo:A? = A()
> foo.someMethod() // A is non-nil, no operators required!
> foo = nil
> foo!.someMethod() // Error: foo is always nil at this point
>
> However, unwrapping of the value is only possible if the case contains
> either no value at all, or contains a single value able to satisfy the
> variable's original type requirements. In other words, the value stored in
> Optional.some satisfies the type requirements of var foo:A?, thus it
> is implicitly unwrapped for use. For general enums this likely means no
> cases are implicitly unwrapped unless using a type of Any.
>
> Type
> Widening
>
> In some cases a type may be narrowed, only to be used in a way that makes
> no sense for the narrowed type. In cases such as these the operation is
> tested against each type in the stack to determine whether the type must
> instead be widened. If a widened type is found it is selected (with
>