[Pitch] KeyPath based map, flatMap, filter


(Karl) #1

I agree that it should be completely implicit.
  
KeyPaths are simply chains of partially-applied properties and subscripts. At the same time, it was noted in the KeyPath proposal that a similar mechanism might be used to model chains of partially-applied functions. I think that having both types be convertible to a closure would be sensible.
  
In fact, you could argue for a general-purpose “Executable” protocol which would allow any conforming object to be implicitly used as a function/closure. Command-style objects such as predictes and transformers would also benefit from such a feature.
  
- Karl

···

  
On Jul 8, 2017 at 11:56 pm, <Benjamin Herzog via swift-evolution (mailto:swift-evolution@swift.org)> wrote:
  
Is this operator common in other languages? I would actually expect that the conversation is not 'almost-implicit' but completely implicit instead. I think both - a prefix and postfix operator - are not obvious enough what happens here, especially because this kind of conversion is not happening in other parts of the language.
All conversions are implicit (from explicit type to protocol, from Swift stdlib types to Objective-C types, from any type to Any, …) currently.
  
______________________
  
Benjamin Herzog
  
>
> On 8. Jul 2017, at 22:10, Hooman Mehr via swift-evolution <swift-evolution@swift.org (mailto:swift-evolution@swift.org)> wrote:
>
>
>
> I like this promote operator idea. I have been defining similar operators for specific projects almost at random. It makes sense to come up with a well-defined behavior and name for such operators, as a common practice as you suggest.
>
>
> The problem with the postfix operator is that it does not currently work without an extra set of parenthesis:
>
>
>
>
> postfix operator ^
>
>
>
> postfix func ^<T,U>(lhs: KeyPath<T,U>) -> (T)->U { return { $0[keyPath: lhs] } }
>
>
>
> struct Guy { let name: String }
>
>
>
> let guys = [
>
> Guy(name: "Benjamin"),
>
> Guy(name: "Dave"),
>
> Guy(name: "Brent"),
>
> Guy(name: "Max")
>
> ]
>
>
>
> guys.map(\.name^) // Error: Invalid component of Swift key path
>
>
>
> guys.map((\.name)^) // This works
>
>
>
>
> Is this a bug?
>
>
>
> That is the reason I used a prefix operator (~) in my suggestion in the a previous e-mail on this thread.
>
>
>
  
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution


(Benjamin Herzog) #2

In Scala you can implement an apply method which makes it possible to call an object just like a function. Example:

case class Foo(x: Int) {
  def apply(y: Int) = x + y
}

val foo = Foo(3)
val bar = foo(4)

That is similar to what you suggested to have a possibility to convert an object to a closure getting called. And I totally see the point for this! I think using a keyword or special name like apply is not a good idea because it's not obvious what it does and it also makes it possible to just call the method with its name: foo.apply(4).

However, having a protocol is kinda hard because it's not possible to have a flexible parameter list. Maybe having a method without a name? Swift example:

class Foo {
    var x: Int
    init(x: Int) { self.x = x }

    func (y: Int) -> Int {
        return self.x + y
    }
}

let foo = Foo(x: 3)
let bar = foo(y: 4)

I actually like that, would be like an anonymous function. It would also be possible to have multiple of those defined for one object (which would have to be unambiguous of course).

So getting back to KeyPath, it could look like this:

class KeyPath<Root, Value> {
    func (_ root: Root) -> Value {
        return root[keyPath: self]
    }
}

I see that this would be a much bigger change and would not justify the syntactic sugar for map, flatMap, etc. But it would still be a nice addition to the Swift programming language, especially for KeyPath, transformers etc.

What do you think?

···

______________________

Benjamin Herzog

On 9. Jul 2017, at 13:09, Karl Wagner <razielim@gmail.com> wrote:

I agree that it should be completely implicit.

KeyPaths are simply chains of partially-applied properties and subscripts. At the same time, it was noted in the KeyPath proposal that a similar mechanism might be used to model chains of partially-applied functions. I think that having both types be convertible to a closure would be sensible.

In fact, you could argue for a general-purpose “Executable” protocol which would allow any conforming object to be implicitly used as a function/closure. Command-style objects such as predictes and transformers would also benefit from such a feature.

- Karl