Ah, I see what you're getting at. Yeah, I've been using Task's to start stream observer callbacks, but I've just been using raw loops since there is no forEach. Doesn't seem like there's any other option yet. forEach makes that slightly nicer for more complex chains.
You're right, I didn't think that through for the async case. In that case it seems easy to just return a custom type like all of the other async operators, one that just passes elements through.
This is why I would like to create a way for return, break, and continue to work in closures so that functions like forEach can behave and look more like for loops.
I've met this feature in Ruby, and I loved it (and I guess it's initially a Smalltalk thing). In Ruby, we distinguish procs from lambdas. Procs affect control flow one-level up. Lambdas can not.
Ruby procs & lambdas
# prints
# lambda 1: foo
# lambda 2: foo
# proc 1: bar
# f: bar
def f
l1 = lambda do 'foo' end
puts "lambda 1: #{l1[]}"
l2 = lambda do return 'foo' end
puts "lambda 2: #{l2[]}"
p1 = proc do 'bar' end
puts "proc 1: #{p1[]}"
p2 = proc do return 'bar' end
puts "proc 2: #{p2[]}"
puts "end"
end
puts "f: #{f()}"
There are other funny Ruby features, such as breaking with a value:
def f
[1, 2, 3].each do |x|
break x * 2 if x == 2
end
end
f # 4
Now of course, changing Swift's forEach behavior would be a breaking change:
func f() {
[1, 2, 3].forEach { x in
guard x != 2 else {
// Returning from f would be a rubyism, and a breaking change
return
}
print(x)
}
}
Why else would you want this features? A popular request is for SwiftUI’s ForEach, but that could be addressed with a lazy for-loop build method in result builders.
I use both extensively in my code, depending on context, to express emphasis and focus the readers attention: forEach to emphasize the collection as a whole, for in ... to focus attention on what is happening to each element.
One thing I don't see mentioned here is the fact that forEach is also very convenient to use when you have optional collections. Is the collection nil? Then simply don't execute the block.
When using for ... in ..., you have to have unwrap your collection first ¯\_(ツ)_/¯