Lenses into Swift properties - swift

Is there some way to automatically generate a getter/setter function pair for a property in a class in Swift? Something along the lines of a lens in Haskell.
I've been able to do the following manually:
class PropertyLens<U, T> {
let getter: U -> T
let setter: (U, T) -> ()
init(getter: (U -> T), setter: ((U, T) -> ())) {
self.getter = getter
self.setter = setter
}
func get(u: U) -> T {
return getter(u)
}
func set(u: U, t: T) {
setter(u, t)
}
}
// ...
let myPropertyLens = PropertyLens<MyClass, Int>(getter: { $0.myProperty }, setter: { $0.myProperty = $1 })
However, that becomes verbose, tedious, and more error-prone than I'd like. Is there a built-in feature I'm missing?

For the answer itself, so far (1.1) no language construct will substitute what you are doing (wrapping the access process of a stored property into a referenciable object).
For the opinion part of the answer, it looks like your code only works with public variables, which are nasty for they break basic encapsulation rules, is that correct?

You should give Sourcery a try. I have the same problem and I run into this tool, if you make a quick search you should easily find some already made templates for Sourcery that lets you generate lenses for your data types.

Related

Reduce array of closures into single closure

Suppose I have an array of closures which can all be composed with one another (i.e., endomorphisms, their input and output types are the same). How can I compose these closures into a single closure?
For reference, I was trying to design something like the following.
struct MyType {
typealias MyClosure: (T) -> T
private var myClosures: [MyClosure] = [ ... ]
public var closure: MyClosure {
get {
return ? // somehow compose all of myClosures into a single closure here
}
}
}
My first thought was to use reduce, à la myClosures.reduce(STARTING) { a, b in b(a) },
but this requires a starting value to be supplied, and then successively applies the closures to it. I don't want to apply the closures to anything (yet), but just synthesize the private list of closures into a single, public closure which can be applied later. Given the way reduce is
defined, I expect this would look something like
myClosures.reduce(identity) { a, b in compose(a, b) }
func identity(_ input: T) { return input }
func compose(a: MyClosure, b: MyClosure) -> MyClosure { return b(a) }
but the type of b(a) is T, not (T) -> T. How can this be accomplished? Is this a better way of going about closure composition?
Edit: My original answer misunderstood what your problem was. But seeing as my original answer might be useful to future readers, I'll leave it at the bottom.
Your compose function is nearly there! b(a) does not compile because MyClosure does not take another MyClosure. b(a) is invoking the closure ("function application"). not composition. Since compose returns a closure, why not return a closure? A typical closure looks like this in Swift:
{ (param) in return doSomethingTo(param) }
So let's return that!
return { (x) in return b(a(x)) }
This can be simplified to:
{ b(a($0)) } // "return" can be omitted as well!
This page (among other things) tells you how and when you can simplify closure syntaxes.
Original answer:
Using reduce is the correct choice here. The reduction operation is composition, so let's write a compose function first:
func compose<T>(_ x: #escaping (T) -> T, _ y: #escaping (T) -> T) -> (T) -> T {
{ y(x($0)) } // or { x(y($0)) } if you want it the other way
}
Then, we reduce. What's the identity? The identity is something that has these properties:
compose(identity, anything) == anything
compose(anything, identity) == anything
What function does that? The identity function!
So we get:
func reduceClosures<T>(_ closures: [(T) -> T]) -> (T) -> T {
closures.reduce({ $0 }, compose)
}

Why specializing a generic function explicitly is not allowed?

In Swift, one should use type of parameters or return value to implicitly specialize a generic function. The problem is, when I call function like this:
func serialize<T>(continuation: GenericWithLongName<T, NSError> -> Void) -> Void
I cannot just write
serialize<SomeType> {
obj in
...
}
It should be
serialize {
(obj: GenericWithLongName<SomeType, NSError>) -> Void in
...
}
which looks painful.
It seems this "feature" exists for a long time. Is it a design decision? Is there any negative implication from allowing explicitly specialization?
And is there any way to make code above neat and clean without refactoring that generic class?
One way to "specialize" the function is by including the generic type as a function parameter:
func serialize<T>(
t: T.Type,
continuation: GenericWithLongName<T, NSError> -> Void ) -> Void { }
Now you can "specialize" the function like this:
serialize(SomeType.self) {
obj in
...
}
I don't know the answer to why your requested feature is not available. I agree that the feature you recommend would be useful, but in the meantime this works just as well and is almost as concise.

How does a flatMap on a double-generic data-structure looks like?

I have the following (simple) data structure:
struct Work<Input, Output> {
let work: Input -> Output
}
This type represents work which can take an Input and turns in into a desired Output. I am trying to see whether this data structure conforms to some functional concepts like a functor or a monad.
Functor
extension Work {
func map<MoreOutput>(transform: Output -> MoreOutput) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> {
return transform(self.work($0))
}
}
}
That seems to be correct as far as I am aware. I am able to write a map function which can turn Work<Input, Output> into Work<Input, MoreOutput>
Monad
I have trouble thinking of the definition for a flatMap (or fold) function for Work. The only thing I can come up with is the following:
extension Work {
func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> { input in
return transform.work(self.work(input))
}
}
}
If you look up the flatMap definition for an Array in swift it looks like this (simplified):
func flatMap(transform: (Element) -> T?) -> [T]
This is a function where its argument is a function which transforms an Element into T and results an Array. I cannot think of a way to abstract this to the Work type.
From another functional book I found a general definition for flatMap as follows (on an object F holding type A):
func flatMap<B>(f: A -> F<B>) -> F<B>
which is a different definition of flatMap than Array seems to implement.
Can someone explain this difference to me? And is it even possible to define a 'correct' flatMap function on Work? Or does Work not satisfy the properties to be a Monad?
** Edit
Thanks phg for so much useful info. I've tried to do the Profunctor definition:
Making Work a Profunctor:
extension Work {
func diMap<A, B>(fa: A -> Input, fb: Output -> B) -> Work<A, B> {
return Work<A, B> { arg in
let input = fa(arg)
let output = self.work(input)
return fb(output)
}
}
}
Does that look right to you?
This:
func flatMap<B>(f: A -> F<B>) -> F<B>
is what you want flatMap to look like; it's the monad's usual "bind" operation. Specialized for functions over the second argument, you get the so-called Reader monad:
extension Work {
func flatMap<MoreOutput>(g: Output -> Work<Input, MoreOutput>) -> Work<Input, MoreOutput> {
// (Reader f) >>= g = Reader $ \x -> runReader (g (f x)) x
return Work<Input, MoreOutput> {
g(self.work($0)).work($0)
}
}
}
Note: I actually don't speak Swift, this code was just guessing -- hence the included Haskell original. Feel free to edit in a corrected version.
Now to the other definition:
func flatMap(transform: (Element) -> T?) -> [T]
I suppose T? means something like "optional T" or "nullable T". This is not what we usually understand as a monadic function, but it is related. Indeed, there has been a question about such "generalized flatMaps". The answer is, that if two monads are compatible, i.e., there exists a monad morphism F<A> -> G<A> preserving monadic structure, it makes sense to define
func wrappedFlatMap<B>(f: A -> F<B>) -> G<B>
which is probably exactly what is happening here for the "option type" and the list type, where the morphism is logically just
Just x ~> [x]
Nothing ~> []

Swift Generic constraints in init

I have generic and I want to be able to initialize it with specific constrains. The constraints are only there for initialization. The rest of the class doesn't care. Here is a simplified example:
struct Generic<T> {
let compare: (T, T) -> Bool
init<T: Equatable>(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
insert(data)
}
init(compareHandler: (T, T) -> Bool, data[T]) {
compare = self.compareHandler
insert(data)
}
}
You can see there's two initializers. The second one obviously works fine. However, in the first one the local type T is mismatched with the struct's generic Type. So, for example, attempting to insert data I get Cannot invoke 'insert' with an argument list of type '([T])'. Is it possible for me to specialize the Struct's generic type only for the initialization or a specific function?
Note, I've already tried init<T where T:Equatable>(data: [T]) to the same effect.
Update
I'm using the following workaround: I create a top level function and removing the specialized init:
func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
return left == right
}
Clients of the struct can initialize using: Generic(compareHandler: equatableHandler, data: data)
It's not quite the "convenience" of using a specialized init, but I suppose it works well enough for my purposes. I'm not a fan of creating top-level functions, but the generic is used so often for "Equatable" generics that it makes sense for me to define the handler once for clients to use.
The problem is that the first init method
init<T: Equatable>(data: [T])
introduces a local type placeholder T which hides (and is completely
unrelated to) the placeholder T of the Generic type, so it
is essentially the same problem as in Array extension to remove object by value.
As of Swift 2 you can solve that with a "restricted extension":
extension Generic where T : Equatable {
init(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
// ...
}
}
For Swift 1.x the only solution is probably to define a global helper
function
func makeGeneric<T : Equatable>(data: [T]) -> Generic<T> {
return Generic(compareHandler: { $0 == $1 }, data: data)
}
(and I could not think of a sensible name for the function :).

Swift protocol and return types on global functions

This is a followup to the question: Protocol func returning Self. The protocol is as follows:
protocol Copyable {
init(copy: Self)
func copy() -> Self
}
The following works fine but the copy() function is exactly the same for every implementation, namely
func copy() -> Self {
return self.dynamicType(copy: self)
}
In accordance to this http://nshipster.com/swift-default-protocol-implementations/ I tried a global func
func copy<T : Copyable>(makeCopy: T) -> T {
return makeCopy.dynamicType(copy: makeCopy)
}
However, when it's called in a class implementing a the below protocol
protocol Mutatable : Copyable {
func mutated() -> Self
}
class C : Mutatable {
var a = 0
required init(_ a: Int) {
self.a = a
}
required init(copy: C) {
a = copy.a
}
func mutated() -> Self {
let mutated = copy(self)
mutated.a++
return mutated // error: 'C' is not convertible to 'Self'
}
}
I get the error as noted. When I type mutated autocomplete shows mutated as (C) and I have no idea what that means. I've also tried adding required to func mutated() but apparently required is only allowed for inits. Any way to get this to work?
This question has the same form as the copy one, and the same solution. Make mutation an initializer rather than a method.
protocol Copyable {
init(copy: Self)
}
protocol Mutatable : Copyable {
init(byMutating: Self)
}
class C : Mutatable {
var a = 0
required init(_ a: Int) {
self.a = a
}
required init(copy: C) {
a = copy.a
}
required convenience init(byMutating: C) {
self.init(copy: byMutating)
self.a++
}
}
// These are purely for convenience
func copy<T : Copyable>(x: T) -> T {
return x.dynamicType(copy: x)
}
func mutated<T: Mutatable>(x: T) -> T {
return x.dynamicType(byMutating: x)
}
But to reiterate Mattt's point in the linked article, you can have a C(copy: x) syntax fairly conveniently, and you can have a copy(x) syntax pretty conveniently, and there is always x.dynamicType(copy: x). But you can't have a x.copy() syntax without some annoying work. You either have to duplicate func copy() -> Self { return copy(self) } in every class, or you have to create some concrete class that implements this method and C ultimately inherits from. This is currently a basic limitation of Swift. I agree with Mattt's diagnosis of possible solutions, and suspect that some kind of trait system, possibly along the lines of Scala's, will probably be added in the future.
It's worth focusing on Mattt's comment that "all of this highlights a significant tension between methods and functions in Swift." This is another way of saying that there are tensions between the object-oriented paradigm and the functional paradigm, and moving between them can create some disconnects. Languages try to paper-over that issue with various features, but there are important differences between objects with messages and properties, vs functions with data and combinators, and "getting the best of both worlds" can sometimes create some rough edges.
It's easy to forget, when comparing Swift to other languages, that there is a big difference between v0.9 and v2.11. Many things we take for granted in our favorite languages did not exist in their v1 either.
To your comment, you may be thinking that mutated is of type Self. But it's of type C, as your autocomplete indicates. As before, C is not the same as Self unless you can promise that there are no subclasses (C being either final or a struct). Swift types are resolved at compile-time, not runtime, unless you use dynamicType.
To be a little more specific, Swift looks at this line:
let mutated = copy(self)
It notes that copy is generic on the type of its parameter, and it must construct a version of copy at compile-time to call. There is no type Self. It's just a placeholder, and must be resolved at compile-time. The type of self in this lexical scope is C. So it constructs copy<C>. But if you subclassed C, this could be the wrong function (and in this case, would be). This is very closely related to: https://stackoverflow.com/a/25549841/97337.
The fact that type autocomplete says (C) rather than C is a minor side-effect of how Swift functions and tuples work, and comes up pretty regularly, but I've yet to encounter a case where it really mattered. A Swift function like func f(x: Int, y:Int) does not actually have two parameters. It has one 2-tuple parameter of type (Int, Int). This fact is important to how the currying syntax works (see the Swift Programming Language for more on currying in Swift). So when you specialize copy, you specialized it with a 1-tuple of type (C). (Or possibly, the compiler is just trying to do that as one of various attempts, and that's just the one it reports on.) In Swift any value can be trivially exchanged for a 1-tuple of the same type. So the return of copy is actually the 1-tuple of C, written (C). I suspect that the Swift compiler will improve its messages over time to remove the extraneous parentheses, but that's why they show up sometimes.