[Accepted and Focused Re-review] SE-0187: Introduce Sequence.filterMap(_:)

mapSome and especially mapNonNil both sound to me like they only map the non-nil values in the source sequence.

John.

···

On Nov 15, 2017, at 7:36 PM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 15, 2017, at 2:31 PM, BJ Homer via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 15, 2017, at 3:05 PM, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Odd… exactly that is the reason why I think filterMap is the worst choice:

Both are established terms of art, but one has a meaning that doesn’t fit to the operation.
Applying filter can remove elements, but it can never change types (I feel kind of silly to repeat this over and over, but so far, nobody took the time to falsify this).

The concern about filter changing types is only relevant if you think of the filter applying to the result of the map, instead of being a part of the filterMap operation itself (an operation that is distinct from map).

Let’s imagine that we had this instead:

enum SelectiveMapResult<T> {
    case use(T)
    case ignore
}

extension Sequence {
    func selectiveMap<T>(_ selectiveTransform: (Element)->SelectiveMapResult<T>) -> [T]
}

let actualNumbers =
    ["1", "2", "apple", "banana", "5"].selectiveMap({ (x)->SelectiveMapResult<Int> in
        if let value = Int(x) { return .use(value) }
        else { return .ignore }
    })

actualNumbers == [1, 2, 5]

The “selective” part of this operation doesn’t feel like it’s changing the type of the result, because SelectiveMapResult is easily understood to not be part of the mapping transformation; it just exists to tell us whether we should use the result of that particular transformation. Likewise, I don’t feel like the optional in filterMap is part of the mapping operation; it’s just serving the same role as SelectiveMapResult. (It should be obvious that SelectiveMapResult is just Optional with another name here.)

"selectiveMap" feels better in part due to grammar. "map" is obviously the verb and "selective" is obviously a modification of "map". "selectiveMap" is therefore performing some sort of special map operation.

"filterMap" feels bad for the same reason that "selectMap" would feel worse than "selectiveMap". "filter" and "map" are both verbs in this context. Grammatically the analogue to "selectiveMap" would be "filteredMap" or "filteringMap".

But even then "filteredMap" or "filteringMap" is insufficient to describe the operation. You additionally need to know that the "filter" here is not ordinary "filter", but instead the special case "filter { $0 != nil }".

The name filterMap focuses on removing the ignored values, as does compactMap. The name selectiveMap focuses on retaining the non-ignored values. I’m not sure whether focusing on the positive or negative aspects is clearer here. I don’t particularly like the name compactMap, simply because I don’t have a lot of experience with languages that use “compact” to mean “drop the nil values”, and without that experience it doesn’t seem intuitive. I think filterMap is better. But if we introduced Sequence.compact() alongside .compactMap(), I’d probably get used to it.

Swift doesn't use "filter" to mean "drop the nil values" either.

"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?

"mapSome" is great if you know about Optional.Some but terrible if you don't. ("Okay, it maps some elements, but which ones?")

"mapNonNil" is obvious and ugly and perhaps its obviousness makes it a winner.

func filterMap<T>(_ f: (Element) -> T?) -> [T] {
  return self.map(f).filter { $0 != nil }.map( $0! } // not an efficient implementation
}

A mapping function is applied to all elements of the source sequence. Unlike map, however, the mapping function can return nil, causing that value to be dropped from the result sequence. Since the result sequence can therefore not contain any (directly) nil values, a level of optionality is removed from the result element type. A common use case — perhaps the most common — is to simultaneously map and filter a sequence without introducing any unnecessary intermediate sequences, which is why it is often called filterMap in functional languages.

John.

···

On Nov 15, 2017, at 9:16 PM, Greg Parker <gparker@apple.com> wrote:

On Nov 15, 2017, at 5:53 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Nov 15, 2017, at 7:36 PM, Greg Parker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 15, 2017, at 2:31 PM, BJ Homer via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 15, 2017, at 3:05 PM, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Odd… exactly that is the reason why I think filterMap is the worst choice:

Both are established terms of art, but one has a meaning that doesn’t fit to the operation.
Applying filter can remove elements, but it can never change types (I feel kind of silly to repeat this over and over, but so far, nobody took the time to falsify this).

The concern about filter changing types is only relevant if you think of the filter applying to the result of the map, instead of being a part of the filterMap operation itself (an operation that is distinct from map).

Let’s imagine that we had this instead:

enum SelectiveMapResult<T> {
    case use(T)
    case ignore
}

extension Sequence {
    func selectiveMap<T>(_ selectiveTransform: (Element)->SelectiveMapResult<T>) -> [T]
}

let actualNumbers =
    ["1", "2", "apple", "banana", "5"].selectiveMap({ (x)->SelectiveMapResult<Int> in
        if let value = Int(x) { return .use(value) }
        else { return .ignore }
    })

actualNumbers == [1, 2, 5]

The “selective” part of this operation doesn’t feel like it’s changing the type of the result, because SelectiveMapResult is easily understood to not be part of the mapping transformation; it just exists to tell us whether we should use the result of that particular transformation. Likewise, I don’t feel like the optional in filterMap is part of the mapping operation; it’s just serving the same role as SelectiveMapResult. (It should be obvious that SelectiveMapResult is just Optional with another name here.)

"selectiveMap" feels better in part due to grammar. "map" is obviously the verb and "selective" is obviously a modification of "map". "selectiveMap" is therefore performing some sort of special map operation.

"filterMap" feels bad for the same reason that "selectMap" would feel worse than "selectiveMap". "filter" and "map" are both verbs in this context. Grammatically the analogue to "selectiveMap" would be "filteredMap" or "filteringMap".

But even then "filteredMap" or "filteringMap" is insufficient to describe the operation. You additionally need to know that the "filter" here is not ordinary "filter", but instead the special case "filter { $0 != nil }".

The name filterMap focuses on removing the ignored values, as does compactMap. The name selectiveMap focuses on retaining the non-ignored values. I’m not sure whether focusing on the positive or negative aspects is clearer here. I don’t particularly like the name compactMap, simply because I don’t have a lot of experience with languages that use “compact” to mean “drop the nil values”, and without that experience it doesn’t seem intuitive. I think filterMap is better. But if we introduced Sequence.compact() alongside .compactMap(), I’d probably get used to it.

Swift doesn't use "filter" to mean "drop the nil values" either.

"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?

"mapSome" is great if you know about Optional.Some but terrible if you don't. ("Okay, it maps some elements, but which ones?")

"mapNonNil" is obvious and ugly and perhaps its obviousness makes it a winner.

mapSome and especially mapNonNil both sound to me like they only map the non-nil values in the source sequence.

I thought it did map the non-nil values in the source sequence. Did I misunderstand what the proposed filterMap does? It occurs to me that the proposal does not have a standalone description of the filterMap operation.

Given the existence of filter already, I submit that filterMap is somewhat overloaded and users would expect that, like flatMap, it would map over all elements and then filter based on some predicate. While that’s awkward to express and likely isn’t useful enough to be in the standard library, to have it just handle nils would seem unexpected to anyone who hadn’t read the signature when finding it in the autocomplete list or reading in documentation. That why I like compact. It’s currently unused in Swift, so it can be given whatever meaning we want, and it coincides with Ruby’s use of it, meaning there’s at least some precedent for using it to remove nils.

Jon

···

On Nov 15, 2017, at 9:58 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 15, 2017, at 9:16 PM, Greg Parker <gparker@apple.com <mailto:gparker@apple.com>> wrote:

On Nov 15, 2017, at 5:53 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Nov 15, 2017, at 7:36 PM, Greg Parker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 15, 2017, at 2:31 PM, BJ Homer via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 15, 2017, at 3:05 PM, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Odd… exactly that is the reason why I think filterMap is the worst choice:

Both are established terms of art, but one has a meaning that doesn’t fit to the operation.
Applying filter can remove elements, but it can never change types (I feel kind of silly to repeat this over and over, but so far, nobody took the time to falsify this).

The concern about filter changing types is only relevant if you think of the filter applying to the result of the map, instead of being a part of the filterMap operation itself (an operation that is distinct from map).

Let’s imagine that we had this instead:

enum SelectiveMapResult<T> {
    case use(T)
    case ignore
}

extension Sequence {
    func selectiveMap<T>(_ selectiveTransform: (Element)->SelectiveMapResult<T>) -> [T]
}

let actualNumbers =
    ["1", "2", "apple", "banana", "5"].selectiveMap({ (x)->SelectiveMapResult<Int> in
        if let value = Int(x) { return .use(value) }
        else { return .ignore }
    })

actualNumbers == [1, 2, 5]

The “selective” part of this operation doesn’t feel like it’s changing the type of the result, because SelectiveMapResult is easily understood to not be part of the mapping transformation; it just exists to tell us whether we should use the result of that particular transformation. Likewise, I don’t feel like the optional in filterMap is part of the mapping operation; it’s just serving the same role as SelectiveMapResult. (It should be obvious that SelectiveMapResult is just Optional with another name here.)

"selectiveMap" feels better in part due to grammar. "map" is obviously the verb and "selective" is obviously a modification of "map". "selectiveMap" is therefore performing some sort of special map operation.

"filterMap" feels bad for the same reason that "selectMap" would feel worse than "selectiveMap". "filter" and "map" are both verbs in this context. Grammatically the analogue to "selectiveMap" would be "filteredMap" or "filteringMap".

But even then "filteredMap" or "filteringMap" is insufficient to describe the operation. You additionally need to know that the "filter" here is not ordinary "filter", but instead the special case "filter { $0 != nil }".

The name filterMap focuses on removing the ignored values, as does compactMap. The name selectiveMap focuses on retaining the non-ignored values. I’m not sure whether focusing on the positive or negative aspects is clearer here. I don’t particularly like the name compactMap, simply because I don’t have a lot of experience with languages that use “compact” to mean “drop the nil values”, and without that experience it doesn’t seem intuitive. I think filterMap is better. But if we introduced Sequence.compact() alongside .compactMap(), I’d probably get used to it.

Swift doesn't use "filter" to mean "drop the nil values" either.

"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?

"mapSome" is great if you know about Optional.Some but terrible if you don't. ("Okay, it maps some elements, but which ones?")

"mapNonNil" is obvious and ugly and perhaps its obviousness makes it a winner.

mapSome and especially mapNonNil both sound to me like they only map the non-nil values in the source sequence.

I thought it did map the non-nil values in the source sequence. Did I misunderstand what the proposed filterMap does? It occurs to me that the proposal does not have a standalone description of the filterMap operation.

func filterMap<T>(_ f: (Element) -> T?) -> [T] {
  return self.map(f).filter { $0 != nil }.map( $0! } // not an efficient implementation
}

A mapping function is applied to all elements of the source sequence. Unlike map, however, the mapping function can return nil, causing that value to be dropped from the result sequence. Since the result sequence can therefore not contain any (directly) nil values, a level of optionality is removed from the result element type. A common use case — perhaps the most common — is to simultaneously map and filter a sequence without introducing any unnecessary intermediate sequences, which is why it is often called filterMap in functional languages.

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

I vote for “mapNonNil”, “mapDroppingNil” or “unwrappingMap”(or some
variations using unwrap).

It’s not pretty, but does the job!

···

Em qua, 15 de nov de 2017 às 22:36, Greg Parker via swift-evolution < swift-evolution@swift.org> escreveu:

On Nov 15, 2017, at 2:31 PM, BJ Homer via swift-evolution < > swift-evolution@swift.org> wrote:

On Nov 15, 2017, at 3:05 PM, Tino Heth via swift-evolution < > swift-evolution@swift.org> wrote:

Odd… exactly that is the reason why I think filterMap is the worst choice:

Both are established terms of art, but one has a meaning that doesn’t fit
to the operation.
Applying filter can remove elements, but it can never change types (I feel
kind of silly to repeat this over and over, but so far, nobody took the
time to falsify this).

The concern about filter changing types is only relevant if you think of
the filter applying to the *result* of the map, instead of being a part
of the filterMap operation itself (an operation that is distinct from map
).

Let’s imagine that we had this instead:

enum SelectiveMapResult<T> {
    case use(T)
    case ignore
}

extension Sequence {
    func selectiveMap<T>(_ selectiveTransform: (Element)->
SelectiveMapResult<T>) -> [T]
}

let actualNumbers =
    ["1", "2", "apple", "banana", "5"].selectiveMap({ (x)->
SelectiveMapResult<Int> in
        if let value = Int(x) { return .use(value) }
        else { return .ignore }
    })

actualNumbers == [1, 2, 5]

The “selective” part of this operation doesn’t feel like it’s changing the
type of the result, because SelectiveMapResult is easily understood to
not be part of the mapping transformation; it just exists to tell us
whether we should *use the result* of that particular transformation.
Likewise, I don’t feel like the optional in filterMap is part of the
mapping operation; it’s just serving the same role as SelectiveMapResult.
(It should be obvious that SelectiveMapResult is just Optional with
another name here.)

"selectiveMap" feels better in part due to grammar. "map" is obviously the
verb and "selective" is obviously a modification of "map". "selectiveMap"
is therefore performing some sort of special map operation.

"filterMap" feels bad for the same reason that "selectMap" would feel
worse than "selectiveMap". "filter" and "map" are both verbs in this
context. Grammatically the analogue to "selectiveMap" would be
"filteredMap" or "filteringMap".

But even then "filteredMap" or "filteringMap" is insufficient to describe
the operation. You additionally need to know that the "filter" here is not
ordinary "filter", but instead the special case "filter { $0 != nil }".

The name filterMap focuses on removing the ignored values, as does
compactMap. The name selectiveMap focuses on retaining the non-ignored
values. I’m not sure whether focusing on the positive or negative aspects
is clearer here. I don’t particularly like the name compactMap, simply
because I don’t have a lot of experience with languages that use “compact”
to mean “drop the nil values”, and without that experience it doesn’t seem
intuitive. I think filterMap is better. But if we introduced
Sequence.compact() alongside .compactMap(), I’d probably get used to it.

Swift doesn't use "filter" to mean "drop the nil values" either.

"compactMap" is okay if "compact" is added. Is "compact" a common enough
operation in practice to pull its own weight?

"mapSome" is great if you know about Optional.Some but terrible if you
don't. ("Okay, it maps some elements, but which ones?")

"mapNonNil" is obvious and ugly and perhaps its obviousness makes it a
winner.

--
Greg Parker gparker@apple.com Runtime Wrangler

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

Lines containing code like `flatMap { $0 }`—which could be compacting optionals or flattening nested sequences—appear 89 times in the source compatibility suite. (I happen to have it on my hard drive right now.)

My main concern about adding a compacting method is…well, am I missing a better implementation than the slightly gross one I cooked up in a playground just now?

  protocol _OptionalProtocol {
      associatedtype _Wrapped
      var _optional: _Wrapped? { get }
  }
  
  extension Optional: _OptionalProtocol {
      var _optional: Wrapped? {
          return self
      }
  }
  
  extension Sequence where Element: _OptionalProtocol {
      func compacted() -> [Element._Wrapped] {
          return flatMap { $0._optional }
      }
  }
  
  let a = [1, nil, 2]
  a.compacted() // [1, 2]

···

On Nov 15, 2017, at 4:36 PM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?

--
Brent Royal-Gordon
Architechies

I agree with Gwendal’s reasoning about the introduction of the term “compact” into the API nomenclature. Removing non-existent values is qualitatively different than selecting a subset of a sequence based on properties of the contained values, and thus merits different terminology. Put a different way: A “filter" shouldn’t change the type of the sequence’s element.

In the case of filterMap(), we have two type transformations going on: T → U? and U? → U. Neither of these is a filter, because neither is an “A → A” transformation. So using the term “filter” is incorrect. The first is a map(), and the second is technically a reduce(). However, reduce() isn’t commonly used in Swift, and the special circumstances surrounding the use of Optional<U>, IMO, deserves a special term, given the frequency with which optionals are used. “Compact” fits that bill very nicely.

Therefore, a huge +1 from me on the choice of “compacted()/compacting()/compactMap()" over “filterMap” or whatever.

Dave

<snip>

"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?

It might be a good criteria, given placeholder ‘xxx’ which is a verb, to think of whether for xxxMap or xxxedMap, if xxx/xxxed would be acceptable and descriptive terms. We didn’t have flattened() for flatMap, so I think whether xxxed() is present or not is a separate question.

Optional is an adjective, so there may be an ‘xxx’ in the function xxxMap which is also an adjective. Not sure how that plays into the naming conventions.

"mapSome" is great if you know about Optional.Some but terrible if you don't. ("Okay, it maps some elements, but which ones?")

"mapNonNil" is obvious and ugly and perhaps its obviousness makes it a winner.

mapSome and especially mapNonNil both sound to me like they only map the non-nil values in the source sequence.

I thought it did map the non-nil values in the source sequence. Did I misunderstand what the proposed filterMap does? It occurs to me that the proposal does not have a standalone description of the filterMap operation.

It maps all values to optional results, discarding any results which are nil and returning just a collection of the unwrapped results - right?

Speaking of which, I don’t feel Sequence.unwrapped() passes muster per my stated criteria above.

-DW

···

On Nov 15, 2017, at 7:16 PM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 15, 2017, at 5:53 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Nov 15, 2017, at 7:36 PM, Greg Parker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Just throwing this out there, but would it be the worst thing in the world if `transform: (Optional<T>) throws -> U` defaulted to {item: T in return T}`?

Otherwise, I don't think `removeNils` is necessary as in my experience, the optional sequence or array was generated by some kind of transform operation.

-- E

···

On Nov 20, 2017, at 1:31 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 20, 2017, at 12:22 PM, BJ Homer <bjhomer@gmail.com <mailto:bjhomer@gmail.com>> wrote:

On Nov 20, 2017, at 10:09 AM, Drew Crawford via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The typical case for this function in my code is the identity closure, that is

    let a: [Int?] = ...
    print(a.filterMap {$0})

filterMap is quite poor for this situation because *each* component in the term is inaccurate:

filterMap is indeed an awkward name for this use case, just like flatMap is. In my experience, about half of my use cases use the identity closure, and half actually make use of the closure in a meaningful way. I would support a proposal to add something like Sequence.dropNils (actual name to be determined), and then we could let this proposal target the non-identity-closure use case.

If the identity closure (i.e. "please remove the nils from this sequence") is a common use case, then I absolutely agree that we should consider adding a specific operation for that, and that name might illuminate the right name for the mapping version.

John.

This is why I really like compact/compactMap.

···

On Nov 20, 2017, at 3:31 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 20, 2017, at 12:22 PM, BJ Homer <bjhomer@gmail.com <mailto:bjhomer@gmail.com>> wrote:

On Nov 20, 2017, at 10:09 AM, Drew Crawford via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The typical case for this function in my code is the identity closure, that is

    let a: [Int?] = ...
    print(a.filterMap {$0})

filterMap is quite poor for this situation because *each* component in the term is inaccurate:

filterMap is indeed an awkward name for this use case, just like flatMap is. In my experience, about half of my use cases use the identity closure, and half actually make use of the closure in a meaningful way. I would support a proposal to add something like Sequence.dropNils (actual name to be determined), and then we could let this proposal target the non-identity-closure use case.

If the identity closure (i.e. "please remove the nils from this sequence") is a common use case, then I absolutely agree that we should consider adding a specific operation for that, and that name might illuminate the right name for the mapping version.

John.

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

My favorite would be a variation of Scalas choice (collect / collectResults).
The word compact (or similar choices like condense, squeeze, pack, compress…) always remind me on compression — my first association of „compact“ would be a transform that turns [1, 2, 2, 3] into [1, 2, 3] (like the shell tool uniq).
But there’s a long list of verbs with similar meaning, so if there’s a consensus for compact (or compacted…), I join that camp.

I'll argue in favor of names which include the term "some".

"The Optional type is an enumeration with two cases. Optional.none is
equivalent to the nil literal. Optional.some(Wrapped) stores a wrapped
value." (https://developer.apple.com/documentation/swift/optional\)

let things = ["apple", nil, "cat", "dog"]

print( things )
print( things.flatMap {$0} )

// Equivalently: apply map, filter for non-nil, and apply force unwrap.
func transform(x: Any?) -> Any? {return x}
print( things.map(transform).filter { $0 != nil }.map { $0! } )

for x in things {
  switch x {
  case .some:
    print(x!)
  case .none:
    break
  }
}

[Optional("apple"), nil, Optional("cat"), Optional("dog")]

["apple", "cat", "dog"]
["apple", "cat", "dog"]
apple
cat
dog

Here's a variety of possible new names, in descending order of personal
preference:

mapUnwrappingSome
mapAndUnwrap // Thanks Nevin, this is surprisingly clear.
mapUnwrapSome
mapUnwrapIfSome
mapSome // For these last three, it's unclear when nil elements
are dropped. Before or after the map?
mapNonNil
mapStrippingNil

I'm opposed to filterMap. Combining the names of two commonly used methods
for this less frequent operation seems likely to cause as much confusion as
flatMap.
I'm opposed to compactMap. There are two English meanings of "compact", and
my initial thought was about enforcement of some kind of contract.
I think mapUnwrappingSome is explicit, puts clarity > brevity, and
maintains naming consistency within Swift. If the enumeration cases .some
and .none are taught along with Optionals, then this name is clear.

That's my 2-cents as a relatively inexperienced user.
-Dylan

···

On Wed, Nov 15, 2017 at 6:48 PM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:

On Wed, Nov 15, 2017 at 8:05 PM, Wallacy via swift-evolution < > swift-evolution@swift.org> wrote:

“unwrappingMap”(or some variations using unwrap).

I’d like to propose “mapAndUnwrap”.

It does what it says on the tin: map a sequence (into an optional type),
then unwrap the values which exist.

Nevin

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

I’d like to propose “mapAndUnwrap”.

It does what it says on the tin: map a sequence (into an optional type),
then unwrap the values which exist.

Nevin

···

On Wed, Nov 15, 2017 at 8:05 PM, Wallacy via swift-evolution < swift-evolution@swift.org> wrote:

“unwrappingMap”(or some variations using unwrap).

Welcome to the club :-) Sign in to GitHub · GitHub

Gwendal

···

Le 16 nov. 2017 à 11:06, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> a écrit :

On Nov 15, 2017, at 4:36 PM, Greg Parker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?

Lines containing code like `flatMap { $0 }`—which could be compacting optionals or flattening nested sequences—appear 89 times in the source compatibility suite. (I happen to have it on my hard drive right now.)

My main concern about adding a compacting method is…well, am I missing a better implementation than the slightly gross one I cooked up in a playground just now?

  protocol _OptionalProtocol {
      associatedtype _Wrapped
      var _optional: _Wrapped? { get }
  }

Here's a variety of possible new names, in descending order of personal preference:

mapUnwrappingSome
mapAndUnwrap // Thanks Nevin, this is surprisingly clear.
mapUnwrapSome
mapUnwrapIfSome
mapSome // For these last three, it's unclear when nil elements are dropped. Before or after the map?
mapNonNil
mapStrippingNil

An other explicit alternative

mapIfNotNil()

I dislike `mapSome` because, to me, it implies it will only pass the non-nil values of the sequence to the transformation closure.

`compactMap` isn’t an intuitive name, but I could get used to it. The thing I like about it is it could be paired with a `compacted` method that removes nils from the Sequence of optionals and returns a Sequence of non-optionals. If `compacted` is something that makes sense, then it would be nice if `compactMap` was just a merger of `map` and `compacted`. I would prefer to find a word other than compact that we could use here but I haven’t thought of one yet.

In isolation, I think that `filterMap` is best.

+1

···

Am 20.11.2017 um 21:32 schrieb Jon Shier via swift-evolution <swift-evolution@swift.org>:

This is why I really like compact/compactMap.

On Nov 20, 2017, at 3:31 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 20, 2017, at 12:22 PM, BJ Homer <bjhomer@gmail.com> wrote:
On Nov 20, 2017, at 10:09 AM, Drew Crawford via swift-evolution <swift-evolution@swift.org> wrote:

The typical case for this function in my code is the identity closure, that is

    let a: [Int?] = ...
    print(a.filterMap {$0})

filterMap is quite poor for this situation because *each* component in the term is inaccurate:

filterMap is indeed an awkward name for this use case, just like flatMap is. In my experience, about half of my use cases use the identity closure, and half actually make use of the closure in a meaningful way. I would support a proposal to add something like Sequence.dropNils (actual name to be determined), and then we could let this proposal target the non-identity-closure use case.

If the identity closure (i.e. "please remove the nils from this sequence") is a common use case, then I absolutely agree that we should consider adding a specific operation for that, and that name might illuminate the right name for the mapping version.

John.

_______________________________________________
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

I have a question regarding the general term "compact" vs something more
specific like "remove nil" :
Could we imagine other usages on different types for "compact" ?

map / flatmap has the whole category theory behind it, making it meaningful
for many different types. "Filter" is also generic, because the operation
of filtering has a wide range of application.

"Compact", like Tino suggested, would have the general meaning of "reducing
the size by removing similar elements". Removing nils doesn't seem to be a
special case of this general definition.

If we give "compact" the strict definition of "removing nil", then i don't
understand the need for a general term, instead of something like
"dropNils" (not much longer to write).

···

On Tue, Nov 21, 2017 at 10:47 AM, Tino Heth via swift-evolution < swift-evolution@swift.org> wrote:

My favorite would be a variation of Scalas choice (collect /
collectResults).
The word compact (or similar choices like condense, squeeze, pack,
compress…) always remind me on compression — my first association of
„compact“ would be a transform that turns [1, 2, 2, 3] into [1, 2, 3] (like
the shell tool uniq).
But there’s a long list of verbs with similar meaning, so if there’s a
consensus for compact (or compacted…), I join that camp.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I like mapAndUnwrap , but just for the record I'd like to add
"mapThenUnwrap"

I'm not a native english, but i think "and" doesn't convey as much meaning
relative to the order of the operation as "then".

As a sidenote, if we go this road I think flatMap should also be the object
of a renaming proposal. we would have
map,
mapThenFlatten and
mapThenUnwrap.

It doesn't look as functional style programming as flatMap and filterMap ,
but it's IMHO incredibly clearer. I remember being very puzzled by flatMap
the first time is discovered it and its type signature, making me think it
was "a different kind" of map, instead of a map plus something more in the
end of the process.

···

On Thu, Nov 16, 2017 at 11:23 AM, Jean-Daniel via swift-evolution < swift-evolution@swift.org> wrote:

Here's a variety of possible new names, in descending order of personal
preference:

mapUnwrappingSome
mapAndUnwrap // Thanks Nevin, this is surprisingly clear.
mapUnwrapSome
mapUnwrapIfSome
mapSome // For these last three, it's unclear when nil elements
are dropped. Before or after the map?
mapNonNil
mapStrippingNil

An other explicit alternative

mapIfNotNil()

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

Let’s think I little. If the ideia is choose the best name to explain the
function:

If the function drop the nil values and after that does a map operation.
Names like dropNilAndMap make sense, right?

But we are talking about functions that mimics the berraviour of Functional
programming languages, doesn’t apear the be “functional” drop nils and make
a map in the same operation instead in two steps: dropNils().map{**}

I think we only need to make a function (or a property) to easily drop
(remove or whatever name) and then feal free to call a map or other
function on it. (Or call a map and drop the nils after, how knows)

The role problem is the operation by itself, is confusing because is too
specific and the main use for this is the identity operation for just
remove the optional level.

Array.ToNonOptional()
Array.DropNil()
Array.WithNonOptional()
Etc...

If we only focus in this functionality, the ‘map’ part is already solved.

···

Em ter, 21 de nov de 2017 às 08:47, Benjamin G via swift-evolution < swift-evolution@swift.org> escreveu:

I have a question regarding the general term "compact" vs something more
specific like "remove nil" :
Could we imagine other usages on different types for "compact" ?

map / flatmap has the whole category theory behind it, making it
meaningful for many different types. "Filter" is also generic, because the
operation of filtering has a wide range of application.

"Compact", like Tino suggested, would have the general meaning of
"reducing the size by removing similar elements". Removing nils doesn't
seem to be a special case of this general definition.

If we give "compact" the strict definition of "removing nil", then i don't
understand the need for a general term, instead of something like
"dropNils" (not much longer to write).

On Tue, Nov 21, 2017 at 10:47 AM, Tino Heth via swift-evolution < > swift-evolution@swift.org> wrote:

My favorite would be a variation of Scalas choice (collect /
collectResults).
The word compact (or similar choices like condense, squeeze, pack,
compress…) always remind me on compression — my first association of
„compact“ would be a transform that turns [1, 2, 2, 3] into [1, 2, 3] (like
the shell tool uniq).
But there’s a long list of verbs with similar meaning, so if there’s a
consensus for compact (or compacted…), I join that camp.
_______________________________________________
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

FWIW +1
For me 'compact' means drop "empty space" and return data items in the same order.

I'd like to keep names exactly 'compact/compactMap' instead of 'compacted/compactedMap', but OK to have the latter if 'compact' will not be accepted as 'terms of art'.

Vladimir.

···

On 21.11.2017 8:47, Thorsten Seitz via swift-evolution wrote:

+1

Am 20.11.2017 um 21:32 schrieb Jon Shier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

This is why I really like compact/compactMap.

On Nov 20, 2017, at 3:31 PM, John McCall via swift-evolution <swift-evolution@swift.org >>> <mailto:swift-evolution@swift.org>> wrote:

On Nov 20, 2017, at 12:22 PM, BJ Homer <bjhomer@gmail.com <mailto:bjhomer@gmail.com>> wrote:

On Nov 20, 2017, at 10:09 AM, Drew Crawford via swift-evolution <swift-evolution@swift.org >>>>> <mailto:swift-evolution@swift.org>> wrote:

The typical case for this function in my code is the identity closure, that is

    let a: [Int?] = ...
    print(a.filterMap {$0})

filterMap is quite poor for this situation because *each* component in the term is inaccurate:

filterMap is indeed an awkward name for this use case, just like flatMap is. In my experience, about half of my use cases use the identity closure, and half actually make use of the closure in a meaningful way. I would support a proposal to add something like Sequence.dropNils (actual name to be determined), and then we could let this proposal target the non-identity-closure use case.

If the identity closure (i.e. "please remove the nils from this sequence") is a common use case, then I absolutely agree that we should consider adding a specific operation for that, and that name might illuminate the right name for the mapping version.

John.

_______________________________________________
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