Add function application to Swift's standard library

To do this, we need to be able to write an extension that adds apply to all types. I don't have an opinion on whether this is a good idea or not, but I read somewhere that Swift might never allow this. I think one of the arguments against it is that it pollutes every type, so I'm trying to find a solution that does not conflict with user defined methods.

If we decide that extensions on an unconstrained generic type is a good idea, then I'm all for just adding 'apply' to every type. For the moment, under the assumption we will not get this feature, I'm trying to explore the space we have outside of this.

Would it be more clear if we add an argument label?

let foo = [1,2,3]
    .map { $0 * 2 }
    .(apply: Set.init)

This also allows us to add variations, similar to Kotlin's scope functions:

extension<T> {
    func _<U>(apply transform: (Self) -> U) -> U { transform(self) }
    func _   (also perform: (Self) -> ()) -> Self { perform(self); return self }
    func _   (also perform: () -> ()) -> Self { perform(); return self }
}

And if we get a label for the first trailing closure, this could give us:

let foo = [1,2,3]
    .map { $0 * 2 }
    . also: { print($0) }
    .map { $0 + 1 }
    . apply: { Set($0) }

Note: What is proposed here as 'apply' is more like Kotlin's 'let'. We might want to consider using a different name and leave room for a future 'apply' that is more similar to Kotlin's 'apply' (if possible with Swift's mutation model). I don't really like the name let (although perhaps I should just get used to it). Perhaps 'into' could be a good name.

Unconstrained generic type extensions or not?

The last example comes very close to what we'd get with extensions on unconstrained generics. Just change the different argument labels into multiple function names and remove the colon on the call site.

Some questions I think need to be explored are:

  • Do we want to be able to create extensions that apply to all types?
  • Do we want to make that available for everyone, or only to the standard library?
  • If we can do this, do we add regular methods like apply, also, etc., or do we use a nameless method in order to prevent conflicts with user defined methods?
  • Will we get support for a label for the first trailing closure? This makes the nameless method with argument labels option a reasonable alternative to regular methods. Otherwise I'm not sure it will be worth it.
  • Do we need variations, or is just the originally proposed apply enough?