[swift-evolution] Remove forEach?

Tim Hawkins tim.thawkins at gmail.com
Thu Dec 31 18:55:12 CST 2015


Just my 2 cents,

forEach is a simple concept to understand, it exists in most other
languages that have a language level understanding of containers, retaining
it has no downsides, but has the upside of making swift more approachable.

'map' on the otherhand may be much more powerful a construct, but it is
less famliar as a concept.

Is there any reason why both cant coexist, with one being a simple form of
the other.
On Jan 1, 2016 7:31 AM, "Howard Lovatt via swift-evolution" <
swift-evolution at swift.org> wrote:

> I suspect that if there were an 'advanced' `map` it would largely
> eliminate `forEach` since a main use of `forEach` is because of
> limitation in map like multiple returns, combined map and filtering, etc.
>
> The comment that you have to ignore a warning is however a valid point,
> perhaps like other languages, e.g. Java, you could have a
> `@suppress_unused_result_warning` annotation.
>
> Sent from my iPad
>
> On 31 Dec 2015, at 9:41 PM, ilya via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> I like having separate forEach. As already said, forEach produces
> different visual grouping of logic compared to for operator. It's
> especially useful if you just pass a named function to it.
>
> forEach is also not the same as map:
>
> let block: Int -> Void = ...
> [1,2,3].map(block)
>
> Here the result has the type [Void], not Void and the compiler correctly
> produces a warning. We'd have to explicitly assign the result to silence
> it, which now hides the fact that block wasn't producing anything in the
> first place.
>
> This will hold true for any advanced variant of map.
>
> Ilya.
> On Thu, Dec 31, 2015 at 10:30 Dave Abrahams via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>>
>> -Dave
>>
>> On Dec 30, 2015, at 8:48 PM, Kevin Ballard via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> Swift didn't use to have forEach(). It was added fairly late, and I
>> suspect (though I don't actually know) that it was done so to appease
>> people who kept abusing map() for the same function, as well as the
>> die-hard everything-must-be-functional crowd.
>>
>>
>> Those are two of the reasons.  But the reason that put forEach over the
>> line and convinced me to add it, just slightly, was syntactic:
>>
>> for x in some.very.long[chain]
>>   .of.map { $0 }
>>   .filter { something }.whatever {
>>   ...
>> }
>>
>> reads "inside-out," like nested(free(function(calls())))) vs.
>>
>> some.very.long[chain]
>>   .of.map { $0 }
>>   .filter { something }.whatever
>>   .forEach { x in
>>      ...
>>    }
>>
>>
>> Personally, I'd rather we didn't have it because it encourages people to
>> use it, but I suppose it's better to give people an appropriate tool than
>> to keep watching them abuse map().
>>
>> -Kevin Ballard
>>
>> On Wed, Dec 30, 2015, at 04:50 PM, Craig Cruden via swift-evolution wrote:
>>
>> I don’t see the benefit of taking a simple declarative expression (map,
>> flatMap, filter) and turning it into a complicated imperative/iterative
>> loop.  You already have the ability to iterate through a set and do
>> whatever you want to do with with whatever logic you want to use using.  I
>> would have no problem for the most part removing foreach - it is more of a
>> convenience method for doing an iterative loop through a collection - and
>> to be quite honest rarely use outside of maybe putting in a print statement
>> temporarily in there (but more often just turn the resulting set into comma
>> delimited output and printing it).
>>
>>
>>
>> On 2015-12-31, at 5:10:22, Howard Lovatt via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>>
>> You could replace `forEach` with a supped up `map` that also allowed
>> `break` and `continue`. The following library function gives `continue`
>> and `break` and also combines `repeat`, `times`, `forEach`, `filter`,
>> `flatMap`, and `map` into one:
>>
>>
>> public final class MapController<E, R> {
>> var results = [R]()
>>
>> var isContinuing = true
>>
>> init<C: CollectionType where C.Generator.Element == E>(_ collection: C,
>> sizeEstimate: Int = 0, @noescape mapper: (controller: MapController<E,
>> R>, element: E) throws -> R?) rethrows {
>>         results.reserveCapacity(sizeEstimate)
>> for var generator = collection.generate(), element = generator.next();
>> element != nil && isContinuing; element = generator.next() {
>> let result = try mapper(controller: self, element: element!)
>> if let actualResult = result {
>>                 results.append(actualResult)
>>             }
>>         }
>>     }
>> }
>>
>> extensionCollectionType {
>> /// Controllable `map`, additional controls beyond simple `map` are:
>> ///
>> ///   1. Continue without returning a result (`return nil`)
>> ///   2. Return multiple results (`control.results += [...]` then `return
>> nil`)
>> ///   3. Break (`control.isContinuing = false` then `return nil`)
>> ///
>> /// These additional controls allow this `map` to function like `repeat`,
>> `times`, `forEach`, `filter`, `flatMap`, and `map` combined into one as
>> well as providing an early termination (break).
>> @warn_unused_result func map<R>(sizeEstimate sizeEstimate: Int = 0,
>> @noescape mapper: (controller: MapController<Self.Generator.Element, R>,
>> element: Self.Generator.Element) throws -> R?) rethrows -> [R] {
>> return try MapController(self, sizeEstimate: sizeEstimate, mapper:
>> mapper).results
>>     }
>> }
>>
>> // Demonstration of full functionality including continue, break, and
>> multiple returns
>> var result = (0 ..< 5).map { (control, index) -> Int? in
>> switch index {
>> case 1:
>> returnnil// Continue - skip 1 (`filter`)
>> case 2:
>>         control.results.append(2) // Yield two results - this one and
>> the 'return’ yield (`flatMap`)
>> case 3:
>>         control.isContinuing = false// Break after next yield - which
>> could be `return nil` if there are no more results
>> default:
>> break
>>     }
>> return index // Yield next result - except for case 1 all the above
>> yield `index`
>> }
>> print(result) // prints `[0, 2, 2, 3]` note missing "1", double "2", and
>> last is "3"
>>
>> // Demonstration of `repeat`/`forEach`/`times` like usage - note `(_, _)
>> -> Void?`
>> result = [Int]()
>> (0 ..< 3).map { (_, _) -> Void? in
>>     result.append(1) // Do whatever - in this case append to a global
>> returnnil// Don't yield any results
>> }
>> print(result) // prints `[1, 1, 1]`
>>
>>
>> Would this be a superior alternative to both `forEach` and `times` in the
>> library and `repeat` as a language feature?
>>
>> Sent from my iPad
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>> *_______________________________________________*
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160101/65840153/attachment.html>


More information about the swift-evolution mailing list