Add an ifPresent function to Optional

Hi,

···

On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I am in favour of making optionals consistently act like 1-item-max collections.

Why stop there? Why not make all non-optionals collections of one?

I’m not convinced that making optionals conform to CollectionType actually improves matters: Yes, it may make the odd use here or there slightly more convenient, but at the cost of clarity IMO: Optionals have largely different set of concerns than collections, and having them suddenly inherit all CollectionType functionality and extensions doesn’t make their use (if it relies on them) any clearer, it obscures their “Optional”-ness instead.

  Daniel.

Hi,

I am in favour of making optionals consistently act like 1-item-max collections.

Why stop there? Why not make all non-optionals collections of one?

I don't quite see what advantage would that have. Could you elaborate?

There's precedent in map and flatMap for treating optionals this way.

···

On Mar 14, 2016, at 2:18 PM, Daniel Vollmer via swift-evolution <swift-evolution@swift.org> wrote:

On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I’m not convinced that making optionals conform to CollectionType actually improves matters: Yes, it may make the odd use here or there slightly more convenient, but at the cost of clarity IMO: Optionals have largely different set of concerns than collections, and having them suddenly inherit all CollectionType functionality and extensions doesn’t make their use (if it relies on them) any clearer, it obscures their “Optional”-ness instead.

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

I think that's exactly Daniel's point, that it would be absurd to do so.

Dmitri

···

On Mon, Mar 14, 2016 at 1:28 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:18 PM, Daniel Vollmer via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I am in favour of making optionals consistently act like 1-item-max collections.

Why stop there? Why not make all non-optionals collections of one?

I don't quite see what advantage would that have. Could you elaborate?

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types). We could name Optional.map()
differently, and that would be a separate decision from renaming
Collection.map(), but we used the name `map` primarily because of
precedent, not because there is a HKT notion of these two operations
being the same.

Dmitri

···

On Mon, Mar 14, 2016 at 3:37 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Mar 14, 2016, at 4:33 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Mon, Mar 14, 2016 at 1:28 PM, Erica Sadun via swift-evolution >> <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:18 PM, Daniel Vollmer via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I am in favour of making optionals consistently act like 1-item-max collections.

Why stop there? Why not make all non-optionals collections of one?

I don't quite see what advantage would that have. Could you elaborate?

I think that's exactly Daniel's point, that it would be absurd to do so.

Dmitri

Would you support removing map and flapMap from optionals then?

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types). We could name Optional.map()
differently, and that would be a separate decision from renaming
Collection.map(), but we used the name `map` primarily because of
precedent, not because there is a HKT notion of these two operations
being the same.

Convergent evolution then, like tenrecs and hedgehogs?

Because the way I've been thinking of it is like a teeny tiny collection that either can fit one thing snugly into it or not.

Optional.map returns an Optional.

Array.map returns an Array.
Set.map returns an Array.
<any other collection>.map returns an Array.

I can't say that it is not valid to think about an Optional as a tiny
collection, but as implemented in Swift, .map() does objectively
behave differently...

You're going to make me have completely different mental images when I use Optional.map now, and I don't even
have a mental metaphor to replace it with.

Don't know if it is helpful, but here's one: Optional is a result of a
computation that can fail. .map() allows you to chain more things
onto a computation if it succeeded, and do nothing if it failed
already.

Dmitri

···

On Mon, Mar 14, 2016 at 3:44 PM, Erica Sadun <erica@ericasadun.com> wrote:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

Would you support removing map and flapMap from optionals then?

-- E

···

On Mar 14, 2016, at 4:33 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Mon, Mar 14, 2016 at 1:28 PM, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:18 PM, Daniel Vollmer via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I am in favour of making optionals consistently act like 1-item-max collections.

Why stop there? Why not make all non-optionals collections of one?

I don't quite see what advantage would that have. Could you elaborate?

I think that's exactly Daniel's point, that it would be absurd to do so.

Dmitri

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types). We could name Optional.map()
differently, and that would be a separate decision from renaming
Collection.map(), but we used the name `map` primarily because of
precedent, not because there is a HKT notion of these two operations
being the same.

Convergent evolution then, like tenrecs and hedgehogs?

Because the way I've been thinking of it is like a teeny tiny collection that either can fit one thing snugly into it or not.
You're going to make me have completely different mental images when I use Optional.map now, and I don't even
have a mental metaphor to replace it with.

-- E

Optional.map returns an Optional.

Array.map returns an Array.
Set.map returns an Array.
<any other collection>.map returns an Array.

I can't say that it is not valid to think about an Optional as a tiny
collection, but as implemented in Swift, .map() does objectively
behave differently...

That behavior is, at least partially, because protocols don’t currently
support this:
protocol CollectionType {
    typealias T
    func map<U>(transform: T->U) -> Self<U> // error: Cannot specialize
non-generic type 'Self'
}

This feature is called higher-kinded types, and it is not planned for
design or implementation in the near future.

I *think* I remember reading on here somewhere that the intent is to change
map and flatMap to return “Self<U>" pretty much as soon as the language
supports it.

As a standard library engineer I can with certainty that this is not
the plan. We like the current formulation of map() that returns an
Array.

I don't think that having HKTs in the language would change the rationale.

Dmitri

···

On Mon, Mar 14, 2016 at 5:51 PM, <davesweeris@mac.com> wrote:

On Mar 14, 2016, at 5:51 PM, Dmitri Gribenko via swift-evolution > <swift-evolution@swift.org> wrote:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

That behavior is, at least partially, because protocols don’t currently support this:
protocol CollectionType {
    typealias T
    func map<U>(transform: T->U) -> Self<U> // error: Cannot specialize non-generic type 'Self'
}
I *think* I remember reading on here somewhere that the intent is to change map and flatMap to return “Self<U>" pretty much as soon as the language supports it. Someone from Apple would have to confirm that, though… my memory is quite hazy on the matter.

More to the point, in terms of what you could actual do with a variable, there’s no real difference between:
var foo: [Int] =
and
var foo: Int? = nil
In both cases you have to check foo's “count” so to speak, before you can safely access its element(s), otherwise the most you can do is pass it along to some other code. If the language had the features to support it, Optional could literally be defined like this:
typealias Optional<T> = Array<T where self.count <= 1>
While the syntax of how we’d interact with Optionals might change, functionally speaking, I can’t think of any difference at all. Both provide storage for a variable # of elements (only slightly variable in Optional’s case, but variable none the less), both throw equally fatal errors if you try to access elements that don’t exist, and provide quick access to those that do exist. Furthermore, within the limitation of how many “elements” an Optional can store, it’s trivial to convert between the two types:
extension Array {
    init(_ x: Element?) {
        switch x {
        case .None: self =
        case .Some(let value): self = [value]
        }
    }
}
extension Optional {
    init(arrayLiteral elements: [Optional.Wrapped]) {
        switch elements.count {
        case 0: self = .None
        case _: self = .Some(elements[0])
        }
    }
}

All this suggests, to me anyway, that at least in this regard, they’re the same “meta type”. What’s the harm in having the API reflect that?

- Dave Sweeris

P.S. Should we be having this conversation in a different thread? I’m *really* bad about going down every rabbit hole I can find, and I don’t want to upset the mailing list by dragging them along with me...

···

On Mar 14, 2016, at 5:51 PM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:

Optional.map returns an Optional.

Array.map returns an Array.
Set.map returns an Array.
<any other collection>.map returns an Array.

I can't say that it is not valid to think about an Optional as a tiny
collection, but as implemented in Swift, .map() does objectively
behave differently...

As a standard library engineer I can with certainty that this is not
the plan. We like the current formulation of map() that returns an
Array.

Oh, well that settles that, then. Plus, now I feel kinda silly trying to explain it to you. :-)

https://github.com/apple/swift/blob/master/docs/StdlibRationales.rst#high-order-functions-on-collections-return-arrays

Cool! I’d missed that, thanks!

- Dave Sweeris

···

On Mar 14, 2016, at 8:29 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

Hello all,

Firstly, I would like to "throw my hat in the ring" in support of
Optional.ifPresent().

I have come across many opportunities to use such a utility function and
have used begun using a similar function in Java 8's Optional object very
frequently.

If others feel similarly, I would happily support or issue a proposal for
that single addition:

public enum Optional<Wrapped>: ... {
    ...
    /// If `self == nil` the function call is a no-op. Otherwise, calls
body(self!).
    public func ifPresent(@noescape body: (Wrapped) throws -> Void)
rethrows -> Void {
        switch self {
        case .None: return
        case .Some(let wrapped): try body(wrapped)
        }
    }
  ...
}

However, in regard to expanding Optional's implementation from a simple
enum with an associated value to a CollectionType, I feel that this may be
a bit of a distraction and could fall into a category of "premature
optimization."

I would argue that attempting to simplify the implementation semantics
should be considered a secondary goal to keeping the end-user (swift
developer) semantics easy to use and understand. The addition of an
abstract "boxed type" to organize methods that share names and conceptual
actions but different implementations may not be absolutely immediately
necessary or helpful.

···

On Mon, Mar 14, 2016 at 1:18 PM, Daniel Vollmer via swift-evolution < swift-evolution@swift.org> wrote:

Hi,

> On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I am in favour of making optionals consistently act like 1-item-max
collections.

Why stop there? Why not make all non-optionals collections of one?

I’m not convinced that making optionals conform to CollectionType actually
improves matters: Yes, it may make the odd use here or there slightly more
convenient, but at the cost of clarity IMO: Optionals have largely
different set of concerns than collections, and having them suddenly
inherit all CollectionType functionality and extensions doesn’t make their
use (if it relies on them) any clearer, it obscures their “Optional”-ness
instead.

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

It’s a matter of interpretation:

map on a container type extracts the value from the container, applies the function, then puts the result in the container. The container doesn’t need to be a collection. Same for flatMap.

I think that a function like this would be useful, but I’d call it “apply”. Also, I think that the fact Optional is not a collection type is a good thing. While it can be treated as a collection of at most 1 element, semantically it’s not. We don’t really iterate over all elements in an optional value.

···

On Mar 14, 2016, at 4:28 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 14, 2016, at 2:18 PM, Daniel Vollmer via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

On 13 Mar 2016, at 18:04, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

I am in favour of making optionals consistently act like 1-item-max collections.

Why stop there? Why not make all non-optionals collections of one?

I don't quite see what advantage would that have. Could you elaborate?

There's precedent in map and flatMap for treating optionals this way.

I’m not convinced that making optionals conform to CollectionType actually improves matters: Yes, it may make the odd use here or there slightly more convenient, but at the cost of clarity IMO: Optionals have largely different set of concerns than collections, and having them suddenly inherit all CollectionType functionality and extensions doesn’t make their use (if it relies on them) any clearer, it obscures their “Optional”-ness instead.

  Daniel.
_______________________________________________
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

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types).

+1000.

Optional.map is already highly unfortunate. It makes optional arrays especially painful to deal with, but even in general, you can no longer glance at the code and see which parts are dealing with many items and which parts are dealing with single items.

I would definitely support renaming Optional.{map,flatMap}.

A.

RE: map etc. returning Array

You could currently return AnyCollection though, and that would then let
Optional.map also return AnyCollection.

There is also talk in completing generics so that map could return
Any<CollectionType where Element == Element> which would be even better
than AnyCollection since a wrapper is removed.

  -- Howard.

···

On 15 March 2016 at 12:29, Dmitri Gribenko via swift-evolution < swift-evolution@swift.org> wrote:

On Mon, Mar 14, 2016 at 5:51 PM, <davesweeris@mac.com> wrote:
>
> On Mar 14, 2016, at 5:51 PM, Dmitri Gribenko via swift-evolution > > <swift-evolution@swift.org> wrote:
>
> Optional.map returns an Optional.
>
> Array.map returns an Array.
> Set.map returns an Array.
> <any other collection>.map returns an Array.
>
> I can't say that it is not valid to think about an Optional as a tiny
> collection, but as implemented in Swift, .map() does objectively
> behave differently...
>
> That behavior is, at least partially, because protocols don’t currently
> support this:
> protocol CollectionType {
> typealias T
> func map<U>(transform: T->U) -> Self<U> // error: Cannot specialize
> non-generic type 'Self'
> }

This feature is called higher-kinded types, and it is not planned for
design or implementation in the near future.

> I *think* I remember reading on here somewhere that the intent is to
change
> map and flatMap to return “Self<U>" pretty much as soon as the language
> supports it.

As a standard library engineer I can with certainty that this is not
the plan. We like the current formulation of map() that returns an
Array.

https://github.com/apple/swift/blob/master/docs/StdlibRationales.rst#high-order-functions-on-collections-return-arrays

I don't think that having HKTs in the language would change the rationale.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Questions being raised in this discussion:

* Are the current stdlib names for optional map and flatMap misleading?
* Are the current stdlib functions for optional closure application appropriate and sufficient?

    @warn_unused_result
    public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?

    @warn_unused_result
    public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?

Assume there could be up to three stdlib functions just for applying closures to .some-case
optionals. Would they look like this?

public func f1<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
public func f2<U>(@noescape f: (Wrapped) throws -> U!) rethrows -> U!
public func f3<U>(@noescape f: (Wrapped) throws -> U) rethrows -> Void

Right now f2/flatMap returns U?, not U or U!, and won't throw if nil, right? Should it
stay that way or change to something that throws and returns a guaranteed value?
Or maybe the current "f2" model (flatMap) be discarded and replaced by an
"ifPresent"-like Void call?

And regardless of which functions are included, what would the appropriate
names for each function style be?

-- E

···

On Mar 20, 2016, at 11:22 AM, Andrey Tarantsov <andrey@tarantsov.com> wrote:

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types).

+1000.

Optional.map is already highly unfortunate. It makes optional arrays especially painful to deal with, but even in general, you can no longer glance at the code and see which parts are dealing with many items and which parts are dealing with single items.

I would definitely support renaming Optional.{map,flatMap}.

A.

Because flatMap. No other reason. I'm not advocating this.

-- E

···

On Mar 20, 2016, at 12:20 PM, Krzysztof Siejkowski <krzysztof@siejkowski.net> wrote:
However, I’m not sure about this one:

public func f2<U>(@noescape f: (Wrapped) throws -> U!) rethrows -> U!

I haven’t used implicitly unwrapped optionals at all, I just never found a good case for them. Why do you think this variant might be useful?

Questions being raised in this discussion:

* Are the current stdlib names for optional map and flatMap misleading?

Misleading makes it a harder question to answer. I can answer with my opinion though.

functional methods make sense on several ‘functional things’
1. An abstract generator of values, returning other generators of values which can be collected/reduced/folded into concrete results
2. A collection, returning concrete types to optimize the implementation as well as to eliminate the explicit the collection step (FWIW, I think map, etc should be moved off Sequence and onto Collection)
3. An unordered data set, returning unordered data sets, for processing in a parallel manner.
4. On optionals, where you are dealing with zero or one values

( Aside: To be clear, the above does represent two changes from the current state of things in Swift 3:
- I think LazySequence should be replaced by functional operations on generators
- I think the functional operations on Sequence should be moved to Collection if the goal is to have optimal/shortcut implementations )

You might be able to represent these all on a protocol hierarchy at some point in the future (if we get existential protocols in generics).

In the meantime, there will certainly be duplication. This doesn’t meant that one location is proper and the others are not.

IMHO the goal is functional composition, so the kind of container (single v multiple elements, lazy or immediate, sequenced or unsequenced data, parallel or not) does not determine whether map/flatMap are present

* Are the current stdlib functions for optional closure application appropriate and sufficient?

    @warn_unused_result
    public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?

Sure, you are calling a function to transform the value(s) in a container or sequence, and returning the appropriate container/sequence in the new type. You *could* call this something like bind to match Haskell, but really that would just be a synonym.

    @warn_unused_result
    public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?

Sure, you are calling a function to transform the value(s) in a container or sequence and returning a new container/sequence of some type of element, flattening that down, and returning the appropriate container/sequence in the new type.

One could say the lack of common types means that flatMap is too simplistic, and needs to support functions which return other types of containers, e.g.:

    @warn_unused_result
    public func flatMap<E,S:SequenceType where S.Generator.Element == E>(@noescape f: (Wrapped) throws -> S) rethrows -> [E]

which would return an empty array in the case of optional .none.

Assume there could be up to three stdlib functions just for applying closures to .some-case
optionals. Would they look like this?

public func f1<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
public func f2<U>(@noescape f: (Wrapped) throws -> U!) rethrows -> U!
public func f3<U>(@noescape f: (Wrapped) throws -> U) rethrows -> Void

Right now f2/flatMap returns U?, not U or U!, and won't throw if nil, right? Should it
stay that way or change to something that throws and returns a guaranteed value?
Or maybe the current "f2" model (flatMap) be discarded and replaced by an
"ifPresent"-like Void call?

The discussion in parallel about abolishing the ImplicitlyUnwrappedOptional is about representing IUO closer to what it really is - compiler + language rules which provide default runtime behavior for optionals.

So f2<U> is really

  public func f2<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?

AKA flatMap.

flatMap semantics are:
- if value is .none, return .none
- if value is .some, call function f with the .some value
   - if result of f is .none, return none
   - if result of f is .some value, return .some value

Even if you had IUO’s as a type, and had a variant that took a function that returned a IUO as a result, that would mean the function should behave closer to f1 aka map.

There are three good reasons to have forEach even if you have map:

- generators or lazy collections will not evaluate until they consume. forEach is a consuming function, map may not be.
- if you are using functional style, map indicates the function is not meant to have side effects. forEach *only* makes sense for operations which do have side effects
- map returns a value while forEach does not. The creation of that value may have non-zero cost

And regardless of which functions are included, what would the appropriate
names for each function style be?

I’m in favor of using map, flatMap, flatten, filter, etc. unless someone can beat the existing terms of art.

-DW

···

On Mar 20, 2016, at 11:52 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Great discussion!

Questions being raised in this discussion:

* Are the current stdlib names for optional map and flatMap misleading?
I believe they could be.

From what I could read, the core team and a majority of community doesn’t believe that including the abstractions like Functor or Monad into the stdlib is a good idea. Which is ok - we have a number of great 3rd party implementations avaliable, e.g. Swiftz. Scala took the same route.

If we’re not trying to go into Haskell land, than keeping names like map and flatMap for Optional is just making it harder for the developers who are not familiar with the functional programming jargon. At the same time, those accustomed to functional programming will grab the concept very easily regardless of what it’s called. The name already vary significantly in various languages (see Map (higher-order function) - Wikipedia ).

* Are the current stdlib functions for optional closure application appropriate and sufficient?
I think not. Again, if we’re not pushing people into “don’t leave the monad” mindset than it’s a very good idea to provide a standalone method for side effects. Erica wrote the signature:

public func f3<U>(@noescape f: (Wrapped) throws -> U) rethrows -> Void

However, I’m not sure about this one:

public func f2<U>(@noescape f: (Wrapped) throws -> U!) rethrows -> U!
I haven’t used implicitly unwrapped optionals at all, I just never found a good case for them. Why do you think this variant might be useful?

- Krzysztof

-- E

···

On Mar 20, 2016, at 11:22 AM, Andrey Tarantsov <andrey@tarantsov.com> wrote:

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types).

+1000.

Optional.map is already highly unfortunate. It makes optional arrays especially painful to deal with, but even in general, you can no longer glance at the code and see which parts are dealing with many items and which parts are dealing with single items.

I would definitely support renaming Optional.{map,flatMap}.

A.

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

* Are the current stdlib names for optional map and flatMap misleading?

It depends on the interpretation. The one that I came across in “Functional Swift” describes map and flatMap for container types that are not necessarily collections (Result is another container type that immediately comes to mind which is not a collection). Since these concepts are not specific to Swift, I think that it’s very important that Swift uses the names that are already established for these concepts.

* Are the current stdlib functions for optional closure application appropriate and sufficient?

I’d love to see what is called “ifPresent” in the subject of the thread. But I think that it should be called “apply” (https://en.wikipedia.org/wiki/Apply\)

···

On Mar 20, 2016, at 1:52 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Questions being raised in this discussion:

* Are the current stdlib names for optional map and flatMap misleading?
* Are the current stdlib functions for optional closure application appropriate and sufficient?

    @warn_unused_result
    public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?

    @warn_unused_result
    public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?

Assume there could be up to three stdlib functions just for applying closures to .some-case
optionals. Would they look like this?

public func f1<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
public func f2<U>(@noescape f: (Wrapped) throws -> U!) rethrows -> U!
public func f3<U>(@noescape f: (Wrapped) throws -> U) rethrows -> Void

Right now f2/flatMap returns U?, not U or U!, and won't throw if nil, right? Should it
stay that way or change to something that throws and returns a guaranteed value?
Or maybe the current "f2" model (flatMap) be discarded and replaced by an
"ifPresent"-like Void call?

And regardless of which functions are included, what would the appropriate
names for each function style be?

-- E

On Mar 20, 2016, at 11:22 AM, Andrey Tarantsov <andrey@tarantsov.com <mailto:andrey@tarantsov.com>> wrote:

No. My argument is that map on collections and on optionals are two
completely different things. They unify on a level that does not
exist in Swift (higher-kinded types).

+1000.

Optional.map is already highly unfortunate. It makes optional arrays especially painful to deal with, but even in general, you can no longer glance at the code and see which parts are dealing with many items and which parts are dealing with single items.

I would definitely support renaming Optional.{map,flatMap}.

A.

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

I tend to look at Sequence.map (and the like) as an optimized shortcut for

sequence.lazy.map(mappingFn).array

and where array, count maxElement, etc are optimized shortcuts for reductions

In that light, I don’t know if other collection types are needed for optimized forms. I might prefer promoting the use of reductions instead.

For instance, imagine I have a Set of employees, and I map based on wage. I want the flexibility for the behavior to be:
- Create a new Set, collapsing duplicate wages
- Create a new Array, allowing for duplicate wages
- Create a new Set, failing if two employees have the same wage (for some definition of failing)
- something else

examples of promoting the use of reductions would be supporting mutable reduction, and possibly having a protocol for reducers as types (example that springs to mind is java’s stream Collector)

-DW

···

On Mar 20, 2016, at 10:04 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

RE: map etc. returning Array

You could currently return AnyCollection though, and that would then let Optional.map also return AnyCollection.

There is also talk in completing generics so that map could return Any<CollectionType where Element == Element> which would be even better than AnyCollection since a wrapper is removed.

  -- Howard.

On 15 March 2016 at 12:29, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mon, Mar 14, 2016 at 5:51 PM, <davesweeris@mac.com <mailto:davesweeris@mac.com>> wrote:
>
> On Mar 14, 2016, at 5:51 PM, Dmitri Gribenko via swift-evolution > > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Optional.map returns an Optional.
>
> Array.map returns an Array.
> Set.map returns an Array.
> <any other collection>.map returns an Array.
>
> I can't say that it is not valid to think about an Optional as a tiny
> collection, but as implemented in Swift, .map() does objectively
> behave differently...
>
> That behavior is, at least partially, because protocols don’t currently
> support this:
> protocol CollectionType {
> typealias T
> func map<U>(transform: T->U) -> Self<U> // error: Cannot specialize
> non-generic type 'Self'
> }

This feature is called higher-kinded types, and it is not planned for
design or implementation in the near future.

> I *think* I remember reading on here somewhere that the intent is to change
> map and flatMap to return “Self<U>" pretty much as soon as the language
> supports it.

As a standard library engineer I can with certainty that this is not
the plan. We like the current formulation of map() that returns an
Array.

https://github.com/apple/swift/blob/master/docs/StdlibRationales.rst#high-order-functions-on-collections-return-arrays

I don't think that having HKTs in the language would change the rationale.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>>*/
_______________________________________________
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