Proposal: Add syntactic sugar for iterating over an Optional<SequenceType>


(Marco Masser) #1

In Objective-C, I liked that fast enumeration over an NSArray that was nil and one that was empty could be handled with the exact same code:

NSArray *strings = nil;
for (NSString *string in strings) {
    …
}

In Swift, an Optional<SequenceType> can’t be used this way:

let array: [AnyObject]? = nil
for object in array { // Compiler error: Value of optional type '[AnyObject]?' not unwrapped; did you mean to use '!' or '?'?
    …
}

I know this is a very minor thing and it can be worked around easily by code like this:

for object in array ?? [] {
    …
}

… or what I would consider the proper way:

if let array = array {
    for object in array {
        …
    }
}

Handling a sequence that is empty or one that is nil is often the same, at least in my experience. Granted, this points to an API that could be improved to return empty sequences instead of nil in many cases, but that is not always in one’s control. For example in AppKit, NSView’s subviews property is declared as [NSView], while NSWindow’s childWindows property is [NSWindow]?, an optional Array.

Although I’m not sure this justifies adding a special syntax to Swift, I thought I post this here to see what others think.
I’m proposing a feature that allows iterating over an Optional<SequenceType> if it is not nil, while doing nothing when it is nil. I think that this should be separate from the normal for loop (my first Swift code sample above with the compiler error), but a specialized syntax instead, like the following:

let array: [AnyObject]? = nil
for object in? array { // Note the “in?”
    …
}

With this specialized syntax, you’d be able to see at a glance whether you’re dealing with an Optional or not. The first Swift code sample in this message would still be a compiler error because it uses “for … in”, but Xcode could show a fix-it that points to the “for … in?” syntax.
This syntax would not interfere with other proposals discussed on this list, like adding a mandatory ? to identifiers to Optionals (although this does not imply endorsement on my part).

Also, this is not a proposal to make the Optional type conform to SequenceType as was also discussed previously. If that were to be implemented, my proposal would be pointless, but you’d lose the distinction between iterating over an Optional<SequenceType> and a SequenceType. Therefore, I’d prefer a specialized syntax to make a clear distinction between iterating over a SequenceType and an Optional<SequenceType>.

Cheers,

Marco


(Chris Lattner) #2

In Swift, an Optional<SequenceType> can’t be used this way:

let array: [AnyObject]? = nil
for object in array { // Compiler error: Value of optional type '[AnyObject]?' not unwrapped; did you mean to use '!' or '?'?
    …
}

This topic has come up in internal discussions several times. We’ve discussed adding new features to for/in loop to handle it, having something like “in?” as you suggest:

let array: [AnyObject]? = nil
for object in? array { // Note the “in?”
    …
}

etc. However, the discussion kept coming back to the fact that we have a pretty trivial way to express this already:

I know this is a very minor thing and it can be worked around easily by code like this:

for object in array ?? [] {
    …
}

Thus this isn’t really solving a big problem, and making the language more complex isn’t worth it.

-Chris

···

On Dec 16, 2015, at 6:17 AM, Marco Masser via swift-evolution <swift-evolution@swift.org> wrote:


Another try at allowing optional iteration
(Dave Abrahams) #3

In Swift, an Optional<SequenceType> can’t be used this way:

let array: [AnyObject]? = nil
for object in array { // Compiler error: Value of optional type '[AnyObject]?' not unwrapped; did you mean to use '!' or '?'?
    …
}

This topic has come up in internal discussions several times. We’ve discussed adding new features to for/in loop to handle it, having something like “in?” as you suggest:

let array: [AnyObject]? = nil
for object in? array { // Note the “in?”
    …
}

etc. However, the discussion kept coming back to the fact that we have a pretty trivial way to express this already:

I know this is a very minor thing and it can be worked around easily by code like this:

for object in array ?? [] {
    …
}

Thus this isn’t really solving a big problem, and making the language more complex isn’t worth it.

FWIW, the above only works when "array" is an array or set. In a generic context you might not even know how to construct an empty one.

a?.forEach { object in ... }

is the generic version I think.

-Chris

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

-Dave

···

On Dec 16, 2015, at 10:51 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
On Dec 16, 2015, at 6:17 AM, Marco Masser via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


(Paul Cantrell) #4

This is such a minor thing, but I’ve often wished for “for … in? …” and I like that syntax.

I do this a lot:

    for object in array ?? [] {

…and it does impair readability a bit at times.

P

···

On Dec 16, 2015, at 8:17 AM, Marco Masser via swift-evolution <swift-evolution@swift.org> wrote:

In Objective-C, I liked that fast enumeration over an NSArray that was nil and one that was empty could be handled with the exact same code:

NSArray *strings = nil;
for (NSString *string in strings) {
    …
}

In Swift, an Optional<SequenceType> can’t be used this way:

let array: [AnyObject]? = nil
for object in array { // Compiler error: Value of optional type '[AnyObject]?' not unwrapped; did you mean to use '!' or '?'?
    …
}

I know this is a very minor thing and it can be worked around easily by code like this:

for object in array ?? [] {
    …
}

… or what I would consider the proper way:

if let array = array {
    for object in array {
        …
    }
}

Handling a sequence that is empty or one that is nil is often the same, at least in my experience. Granted, this points to an API that could be improved to return empty sequences instead of nil in many cases, but that is not always in one’s control. For example in AppKit, NSView’s subviews property is declared as [NSView], while NSWindow’s childWindows property is [NSWindow]?, an optional Array.

Although I’m not sure this justifies adding a special syntax to Swift, I thought I post this here to see what others think.
I’m proposing a feature that allows iterating over an Optional<SequenceType> if it is not nil, while doing nothing when it is nil. I think that this should be separate from the normal for loop (my first Swift code sample above with the compiler error), but a specialized syntax instead, like the following:

let array: [AnyObject]? = nil
for object in? array { // Note the “in?”
    …
}

With this specialized syntax, you’d be able to see at a glance whether you’re dealing with an Optional or not. The first Swift code sample in this message would still be a compiler error because it uses “for … in”, but Xcode could show a fix-it that points to the “for … in?” syntax.
This syntax would not interfere with other proposals discussed on this list, like adding a mandatory ? to identifiers to Optionals (although this does not imply endorsement on my part).

Also, this is not a proposal to make the Optional type conform to SequenceType as was also discussed previously. If that were to be implemented, my proposal would be pointless, but you’d lose the distinction between iterating over an Optional<SequenceType> and a SequenceType. Therefore, I’d prefer a specialized syntax to make a clear distinction between iterating over a SequenceType and an Optional<SequenceType>.

Cheers,

Marco

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


(Marco Masser) #5

FWIW, the above only works when "array" is an array or set. In a generic
context you might not even know how to construct an empty one.

Right. And for types that don't conform to ArrayLiteralConvertible or
DictionaryLiteralConvertible, there's no chance to do a shortcut like that.

a?.forEach { object in ... }

is the generic version I think.

Unfortunately, this prevents break/continue from being very readable in the
"loop" body (IMHO) and doesn't allow a return out of the enclosing function
at all. But yeah, at least that works on any Optional<SequenceType>.


(Marco Masser) #6

This topic has come up in internal discussions several times. We’ve
discussed adding new features to for/in loop to handle it, having something
like “in?” as you suggest:

Glad to hear I didn't miss anything obvious!

etc. However, the discussion kept coming back to the fact that we have a

pretty trivial way to express this already:

I know this is a very minor thing and it can be worked around easily by
code like this:

for object in array ?? [] {
    …
}

Thus this isn’t really solving a big problem, and making the language more
complex isn’t worth it.

I suspected as much. Thanks for taking the time to look over it!


(Jeremy Pereira) #7

Does it? It seems fairly understandable to me even though I have never seen it before.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

In the first case, I think it would be more appropriate to handle the error separately to trying to iterate the results (e.g. guard). In the second case, the API is wrong. If there were no qualifying elements, the API should have returned an empty array rather than nil. The very slight clunkiness of the above serves to remind you that you need to change the API that returns the array (assuming you control it).

···

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

This is such a minor thing, but I’ve often wished for “for … in? …” and I like that syntax.

I do this a lot:

    for object in array ?? [] {

…and it does impair readability a bit at times.


(Slava Pestov) #8

In Objective-C, I liked that fast enumeration over an NSArray that was nil and one that was empty could be handled with the exact same code:

NSArray *strings = nil;
for (NSString *string in strings) {
    …
}

One thing we've discussed is adding attributes to import nil values of NSArray and such as empty arrays in Swift, rather than optionals of arrays. Would this solve your problem? Where are these optional arrays coming from in the first place, is it imported Cocoa APIs?

Handling a sequence that is empty or one that is nil is often the same, at least in my experience. Granted, this points to an API that could be improved to return empty sequences instead of nil in many cases, but that is not always in one’s control. For example in AppKit, NSView’s subviews property is declared as [NSView], while NSWindow’s childWindows property is [NSWindow]?, an optional Array.

Yeah, exactly. We want to be able to fix this.

Also, this is not a proposal to make the Optional type conform to SequenceType as was also discussed previously. If that were to be implemented, my proposal would be pointless, but you’d lose the distinction between iterating over an Optional<SequenceType> and a SequenceType. Therefore, I’d prefer a specialized syntax to make a clear distinction between iterating over a SequenceType and an Optional<SequenceType>.

Actually it depends on how the conformance was defined. If Optional<T> was a sequence iff T is a sequence, then yes it supersedes your proposal. Another way to imagine Optional<T> as a sequence is to make it a zero- or one-element sequence, depending on if it is None or Some, respectively. I'm not sure which, if either, is more useful.

···

On Dec 16, 2015, at 6:17 AM, Marco Masser via swift-evolution <swift-evolution@swift.org> wrote:

Cheers,

Marco

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


(Paul Cantrell) #9

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not populated / initialized yet. In that case, we often just want to leave a UI blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a lot of cases, and since Swift provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the `for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it distinguishes “no query string” from “empty query string”, but for the purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on existing code of a `for … in?` counterpart to `for … in`, it’s worth at least considering that option.

Cheers,

Paul

···

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:


(Marco Masser) #10

In Objective-C, I liked that fast enumeration over an NSArray that was nil and one that was empty could be handled with the exact same code:

NSArray *strings = nil;
for (NSString *string in strings) {
    …
}

One thing we've discussed is adding attributes to import nil values of NSArray and such as empty arrays in Swift, rather than optionals of arrays. Would this solve your problem? Where are these optional arrays coming from in the first place, is it imported Cocoa APIs?

Yes, mostly. But I still can imagine cases where it makes sense to have an API that returns an Optional Array but the caller doesn’t care about it being nil vs. it being empty – not that I have a practical example.

Importing an Objective-C API’s NSArray nil value as an empty array in Swift sounds nice!

Also, this is not a proposal to make the Optional type conform to SequenceType as was also discussed previously. If that were to be implemented, my proposal would be pointless, but you’d lose the distinction between iterating over an Optional<SequenceType> and a SequenceType. Therefore, I’d prefer a specialized syntax to make a clear distinction between iterating over a SequenceType and an Optional<SequenceType>.

Actually it depends on how the conformance was defined. If Optional<T> was a sequence iff T is a sequence, then yes it supersedes your proposal. Another way to imagine Optional<T> as a sequence is to make it a zero- or one-element sequence, depending on if it is None or Some, respectively. I'm not sure which, if either, is more useful.

I have to admit that I didn’t closely follow the discussion about Optionals being sequences of zero or one element and therefore don’t know all of the arguments for and against that – just enough that it would supersede my proposal.


(Radek Pietruszewski) #11

Personally, I’m -1 for the proposal. I see this as a solution to a very minor, fairly rare, and not generalizable problem.

Perhaps more importantly: the syntax is confusing to my eyes. `for object in? array` doesn’t immediately convey its semantics to me. It suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

In the vast majority of cases, arrays shouldn’t be optional in the first place. It’s rare that there’s a semantic difference between “empty array” and “no array”.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

That is a good point, albeit one that’s more broad than that — I dislike how `as?` often forces me to add additional parentheses — and not strong enough to warrant an introduction of a new `in?` construct IMHO.

— Radek

···

On 18 Dec 2015, at 21:56, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com <mailto:jeremy.j.pereira@googlemail.com>> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not populated / initialized yet. In that case, we often just want to leave a UI blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a lot of cases, and since Swift provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the `for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it distinguishes “no query string” from “empty query string”, but for the purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on existing code of a `for … in?` counterpart to `for … in`, it’s worth at least considering that option.

Cheers,

Paul

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


(Jacob Bandes-Storch) #12

How about `for? object in array` instead?

···

On Fri, Dec 18, 2015 at 1:13 PM, Paul Cantrell via swift-evolution < swift-evolution@swift.org> wrote:

`for object in? array` … suggests that there’s something optional about
checking for inclusion, not about the array itself. It could easily be
interpreted as “iterate for all non-nil elements of array (where array:
[T?])” — a use case arguably more common than this.

That’s a really good point.

P

On Dec 18, 2015, at 3:06 PM, Radosław Pietruszewski <radexpl@gmail.com> > wrote:

Personally, I’m -1 for the proposal. I see this as a solution to a very
minor, fairly rare, and not generalizable problem.

Perhaps more importantly: the syntax is confusing to my eyes. `for object
in? array` doesn’t immediately convey its semantics to me. It suggests that
there’s something optional about checking for inclusion, not about the
array itself. It could easily be interpreted as “iterate for all non-nil
elements of array (where array: [T?])” — a use case arguably more common
than this.

In the vast majority of cases, arrays shouldn’t be optional in the first
place. It’s rare that there’s a semantic difference between “empty array”
and “no array”.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax
itself, which is perfectly clear; it’s having that dangling off the end of
some longer expression. In real-world context, it does become additional
noise.

That is a good point, albeit one that’s more broad than that — I dislike
how `as?` often forces me to add additional parentheses — and not strong
enough to warrant an introduction of a new `in?` construct IMHO.

— Radek

On 18 Dec 2015, at 21:56, Paul Cantrell via swift-evolution < > swift-evolution@swift.org> wrote:

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira < > jeremy.j.pereira@googlemail.com> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution < > swift-evolution@swift.org> wrote:

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never
seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax
itself, which is perfectly clear; it’s having that dangling off the end of
some longer expression. In real-world context, it does become additional
noise.

I think there is a good reason for keeping this construct a bit “clunky”.
Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not
populated / initialized yet. In that case, we often just want to leave a UI
blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a *lot* of cases, and since Swift
provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the
`for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it
distinguishes “no query string” from “empty query string”, but for the
purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on
existing code of a `for … in?` counterpart to `for … in`, it’s worth at
least considering that option.

Cheers,

Paul

_______________________________________________
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


(Paul Cantrell) #13

`for object in? array` … suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

That’s a really good point.

P

···

On Dec 18, 2015, at 3:06 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Personally, I’m -1 for the proposal. I see this as a solution to a very minor, fairly rare, and not generalizable problem.

Perhaps more importantly: the syntax is confusing to my eyes. `for object in? array` doesn’t immediately convey its semantics to me. It suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

In the vast majority of cases, arrays shouldn’t be optional in the first place. It’s rare that there’s a semantic difference between “empty array” and “no array”.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

That is a good point, albeit one that’s more broad than that — I dislike how `as?` often forces me to add additional parentheses — and not strong enough to warrant an introduction of a new `in?` construct IMHO.

— Radek

On 18 Dec 2015, at 21:56, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com <mailto:jeremy.j.pereira@googlemail.com>> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not populated / initialized yet. In that case, we often just want to leave a UI blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a lot of cases, and since Swift provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the `for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it distinguishes “no query string” from “empty query string”, but for the purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on existing code of a `for … in?` counterpart to `for … in`, it’s worth at least considering that option.

Cheers,

Paul

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Radek Pietruszewski) #14

That’s… definitely an improvement as far as ambiguity is concerned, but I still don’t believe it passes the usefulness threshold, and I don’t really like the precedent of having a `for?`…

PS. FWIW, I like the spirit of the proposal, just not this solution. I’m all for “expressivity enhancements” — little things that helps me write cleaner code and express my intention better. But this doesn’t seem worth the trouble of extending the language.

— Radek

···

On 18 Dec 2015, at 22:20, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

How about `for? object in array` instead?

On Fri, Dec 18, 2015 at 1:13 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

`for object in? array` … suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

That’s a really good point.

P

On Dec 18, 2015, at 3:06 PM, Radosław Pietruszewski <radexpl@gmail.com <mailto:radexpl@gmail.com>> wrote:

Personally, I’m -1 for the proposal. I see this as a solution to a very minor, fairly rare, and not generalizable problem.

Perhaps more importantly: the syntax is confusing to my eyes. `for object in? array` doesn’t immediately convey its semantics to me. It suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

In the vast majority of cases, arrays shouldn’t be optional in the first place. It’s rare that there’s a semantic difference between “empty array” and “no array”.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

That is a good point, albeit one that’s more broad than that — I dislike how `as?` often forces me to add additional parentheses — and not strong enough to warrant an introduction of a new `in?` construct IMHO.

— Radek

On 18 Dec 2015, at 21:56, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com <mailto:jeremy.j.pereira@googlemail.com>> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not populated / initialized yet. In that case, we often just want to leave a UI blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a lot of cases, and since Swift provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the `for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it distinguishes “no query string” from “empty query string”, but for the purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on existing code of a `for … in?` counterpart to `for … in`, it’s worth at least considering that option.

Cheers,

Paul

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Marco Masser) #15

I have to admit that Radek’s comment about “for … in? …” meaning an iteration over a SequenceType containing Optional Values is valid.

But I think “for? … in …” is worse because it separates the “?” from the thing that is the Optional thing. Consider:

for? x in array { … }

vs.

for x in? array { … }

If any of these two is about iterating over an Optional<SequenceType>, it’s the second one – at least to me. The first one reads much more like the “x” could be optional.

Marco

···

On 2015-12-18, at 22:24, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

That’s… definitely an improvement as far as ambiguity is concerned, but I still don’t believe it passes the usefulness threshold, and I don’t really like the precedent of having a `for?`…

PS. FWIW, I like the spirit of the proposal, just not this solution. I’m all for “expressivity enhancements” — little things that helps me write cleaner code and express my intention better. But this doesn’t seem worth the trouble of extending the language.

— Radek

On 18 Dec 2015, at 22:20, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

How about `for? object in array` instead?

On Fri, Dec 18, 2015 at 1:13 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

`for object in? array` … suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

That’s a really good point.

P

On Dec 18, 2015, at 3:06 PM, Radosław Pietruszewski <radexpl@gmail.com <mailto:radexpl@gmail.com>> wrote:

Personally, I’m -1 for the proposal. I see this as a solution to a very minor, fairly rare, and not generalizable problem.

Perhaps more importantly: the syntax is confusing to my eyes. `for object in? array` doesn’t immediately convey its semantics to me. It suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

In the vast majority of cases, arrays shouldn’t be optional in the first place. It’s rare that there’s a semantic difference between “empty array” and “no array”.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

That is a good point, albeit one that’s more broad than that — I dislike how `as?` often forces me to add additional parentheses — and not strong enough to warrant an introduction of a new `in?` construct IMHO.

— Radek

On 18 Dec 2015, at 21:56, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com <mailto:jeremy.j.pereira@googlemail.com>> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not populated / initialized yet. In that case, we often just want to leave a UI blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a lot of cases, and since Swift provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the `for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it distinguishes “no query string” from “empty query string”, but for the purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on existing code of a `for … in?` counterpart to `for … in`, it’s worth at least considering that option.

Cheers,

Paul

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Tyler Cloutier) #16

The syntax could be
for x in array? {

}

It wouldn't necessarily be consistent with

if let foo = foo {

}

But as I've mentioned in another thread regarding the if let syntax and variable shadowing, it would probably make more sense to new users if the if let syntax was the following.

if let foo = foo? {

}

The ? is always used to conditionally unwrap optionals. It strikes me as odd that they are not used to unwrap them in control flow statements.

i.e. Why should

array?.forEach

be any different than,

for x in array?

Tyler

···

On Dec 20, 2015, at 12:15 PM, Marco Masser via swift-evolution <swift-evolution@swift.org> wrote:

I have to admit that Radek’s comment about “for … in? …” meaning an iteration over a SequenceType containing Optional Values is valid.

But I think “for? … in …” is worse because it separates the “?” from the thing that is the Optional thing. Consider:

for? x in array { … }

vs.

for x in? array { … }

If any of these two is about iterating over an Optional<SequenceType>, it’s the second one – at least to me. The first one reads much more like the “x” could be optional.

Marco

On 2015-12-18, at 22:24, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

That’s… definitely an improvement as far as ambiguity is concerned, but I still don’t believe it passes the usefulness threshold, and I don’t really like the precedent of having a `for?`…

PS. FWIW, I like the spirit of the proposal, just not this solution. I’m all for “expressivity enhancements” — little things that helps me write cleaner code and express my intention better. But this doesn’t seem worth the trouble of extending the language.

— Radek

On 18 Dec 2015, at 22:20, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

How about `for? object in array` instead?

On Fri, Dec 18, 2015 at 1:13 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

`for object in? array` … suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

That’s a really good point.

P

On Dec 18, 2015, at 3:06 PM, Radosław Pietruszewski <radexpl@gmail.com> wrote:

Personally, I’m -1 for the proposal. I see this as a solution to a very minor, fairly rare, and not generalizable problem.

Perhaps more importantly: the syntax is confusing to my eyes. `for object in? array` doesn’t immediately convey its semantics to me. It suggests that there’s something optional about checking for inclusion, not about the array itself. It could easily be interpreted as “iterate for all non-nil elements of array (where array: [T?])” — a use case arguably more common than this.

In the vast majority of cases, arrays shouldn’t be optional in the first place. It’s rare that there’s a semantic difference between “empty array” and “no array”.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

That is a good point, albeit one that’s more broad than that — I dislike how `as?` often forces me to add additional parentheses — and not strong enough to warrant an introduction of a new `in?` construct IMHO.

— Radek

On 18 Dec 2015, at 21:56, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 17, 2015, at 4:08 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com> wrote:

On 16 Dec 2015, at 19:52, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

I do this a lot:

   for object in array ?? [] {

…and it does impair readability a bit at times.

Does it? It seems fairly understandable to me even though I have never seen it before.

Sure, in that example it’s quite simple. It’s not the “?? []” syntax itself, which is perfectly clear; it’s having that dangling off the end of some longer expression. In real-world context, it does become additional noise.

I think there is a good reason for keeping this construct a bit “clunky”. Generally APIs give you a nil array for one of two reasons:

- there was some sort of error in retrieving the elements
- there were no qualifying elements found.

You’re forgetting the third case, the most common one: things not populated / initialized yet. In that case, we often just want to leave a UI blank, for example, and doing nothing is the right behavior.

Doing nothing is the right behavior in a lot of cases, and since Swift provides optional sugar for “do nothing if nil” in other cases:

    foo?.bar = baz
    if let foo = bar { }

…it makes sense to provide it in for loops too.

True, “do nothing” is not the right behavior in all cases. Thus the `for…in` / `for … in?` distinction.

In the second case, the API is wrong.

Then a lot of APIs are wrong! NSURLComponents, for example:

        for item in urlComponents.queryItems ?? []
            { queryDict[item.name] = item.value }

But then I don’t think NSURLComponents is making a mistake: it distinguishes “no query string” from “empty query string”, but for the purposes of the loop here, there upshot in both cases is “no query items.”

True, ?? [] is minor noise — but given the clarity and low impact on existing code of a `for … in?` counterpart to `for … in`, it’s worth at least considering that option.

Cheers,

Paul

_______________________________________________
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

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


Another try at allowing optional iteration