This one started over at swift-users, with a question on how to deal with looping over containers that may be nil.
Imho the beauty of the feature is that it's simple enough to be explained in the subject line, but here is the "long" story:
let test: [Int]? = nil
// this is possible now
if let test = test {
for i in test {
print(i)
}
}
// how it could be written with a modified keyword
for i in? test {
print(i)
}
I've been thinking "in?" had been brought up long ago, but as I haven't found such a proposal, I probably confused it with the cancelled plan to write one on my own (or I just was to stupid to search ;-).
Syntactic sugar like this is definitely nothing that has priority now, but discussing it shouldn't be a big distraction — and if it turns into a proposal that as well survives review, it might be even simple enough to act as a trigger for me to finally get my hands on some real work for Swift ;-)
I don't think this use case warrants a syntax change since it can already be expressed quite elegantly with
let test: [Int]? = nil
test?.forEach { i in
print(i)
}
Maybe "in?" could be used instead of
let test: [Int?] = [0,1,nil,3]
for case let i? in test {
print(i)
}
?
···
On 11 Feb 2017, at 12:48, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:
This one started over at swift-users, with a question on how to deal with looping over containers that may be nil.
Imho the beauty of the feature is that it's simple enough to be explained in the subject line, but here is the "long" story:
let test: [Int]? = nil
// this is possible now
if let test = test {
for i in test {
print(i)
}
}
// how it could be written with a modified keyword
for i in? test {
print(i)
}
I've been thinking "in?" had been brought up long ago, but as I haven't found such a proposal, I probably confused it with the cancelled plan to write one on my own (or I just was to stupid to search ;-).
Syntactic sugar like this is definitely nothing that has priority now, but discussing it shouldn't be a big distraction — and if it turns into a proposal that as well survives review, it might be even simple enough to act as a trigger for me to finally get my hands on some real work for Swift ;-)
On Sat, Feb 11, 2017 at 7:48 PM, Tino Heth via swift-evolution < swift-evolution@swift.org> wrote:
This one started over at swift-users, with a question on how to deal with
looping over containers that may be nil.
Imho the beauty of the feature is that it's simple enough to be explained
in the subject line, but here is the "long" story:
let test: [Int]? = nil
// this is possible now
if let test = test {
for i in test {
print(i)
}
}
// how it could be written with a modified keyword
for i in? test {
print(i)
}
I've been thinking "in?" had been brought up long ago, but as I haven't
found such a proposal, I probably confused it with the cancelled plan to
write one on my own (or I just was to stupid to search ;-).
Syntactic sugar like this is definitely nothing that has priority now, but
discussing it shouldn't be a big distraction — and if it turns into a
proposal that as well survives review, it might be even simple enough to
act as a trigger for me to finally get my hands on some real work for Swift
;-)
This could come for almost free after SE-0143 is implemented: an Optional of a Sequence could itself be made to conform to Sequence. It would cost no new syntax.
extension Optional: Sequence where Wrapped: Sequence {
func makeIterator() -> AnyIterator<Wrapped.Iterator.Element> {
switch self {
case .some(let sequence):
return AnyIterator(sequence.makeIterator())
case .none:
return AnyIterator { nil }
}
}
}
This would be more easily done than new syntax, surely.
Most alternatives already where discussed in swift-user:
Imho the "forEach" solution is flawed, because you can't break the loop, and the "?? " isn't perfect either:
I hope the compiler can optimise so that the assembly is as fast as the "if let" solution, but even if this is the case, it is not obvious for a human reader.
This
extension Optional where Wrapped: Sequence {
var elements: [Wrapped.Iterator.Element] {
switch (self) {
case .none:
return
case .some(let o):
return Array(o)
}
}
}
let test: [Int]? = nil
for i in test.elements {
print(i)
}
looks nice to me (except the return type — I guess there are better options), but I don't expect that the compiler can do much to optimise it.
But maybe there is something better:
for i in test? {
print(i)
if i == 42 {
break
}
}
This doesn't work — but it compiles fine when you replace the "?" with "!".
I haven't proposed "in?" earlier because it would be a new keyword (even if its not that new…), and I'm very skeptical towards such changes.
But it is a very common pattern in Swift to have a "!" form that may crash and a save "?" variant, so I think it is actually missing in the syntax of for-loops.
This would be more easily done than new syntax, surely.
… and it wouldn't increase the size of the language, so in general, I prefer library-solutions.
I'd expect some pushback against the conformance, but my personal opinion is that the difference between an empty collection and a missing collection doesn't matter most of the time.
Performance doesn't matter most of the time as well ;-), but imho it's a big plus if the most elegant solution is the fastest, too (and I have no idea if or when the compiler infrastructure is clever enough to recognise empty loops without instantiating useless objects).
But afaics, there is some consensus that Optional<Sequence> deserves some sugar applied to it — either in the language, or in the stdlib.
I have a question for you. How do you think we could use this pattern in the generalised situation:
In general ;-) I like things that can be used universally much more than a huge number of special cases.
But here, I'm not sure if it's not an increase of complexity:
I often if statements with several stages of unpacking, and when there is something similar for loops, imho it should act in the same way:
for let array? = test, i in array {
This would preserve the right order and keep the where clause reserved as it is now.