I would like to write some kind of fluent-like API with custom operators and functions. Here's an example of what I'm looking for:
var result = [Section]()
result +++= Section()
.appendTitle(title)
.appendPhotos(photos)
result +++= Section()
.appendSomething(sth)
.appendPhotos(photos)
.appendAnything()
return result
To do that, I've declared two custom operators:
infix operator +++{ associativity left precedence 95 }
func +++(lhs : [Section], rhs : Section) -> [Section] {
var result = lhs
result.append(rhs)
return result
}
infix operator +++= { associativity left precedence 95 }
func +++=(inout lhs : [Section], rhs : Section) {
lhs = lhs +++ rhs
}
And of course the correct extension for the Section
struct:
extension Section {
mutating func appendTitle(title: String?) -> Section {
guard let unwrappedTitle = title
else { return self }
...
return self
}
mutating func appendPhotos(photos: [Photo]?) -> Section {
...
}
...
}
Unfortunately that does not work as expected...
The line result +++= Section()
alone is correct, but when I add the .append
it does not compile.
The first message is:
Passing value of type '[Section]' to an inout parameter requires explicit '&'
Then I tried to put an &
in front of result
(but I've never done it for a += 1
) there's a second message:
Cannot use mutating member on immutable value: function call returns immutable value
So if anyone can help, it would be much appreciated.
I'm using Swift 2.2 and Xcode 7.
Well, You've found a solution. That's Great!
But Please allow me to explain what has actually happened here.
Let's take a closer look at your earlier implementation.
extension Section {
mutating func appendTitle(title: String?) -> Section {
guard let unwrappedTitle = title else { return self }
self.title = unwrappedTitle
return self
}
mutating func appendPhotos(photos: [Photo]?) -> Section {
guard let unwrappedPhotos = photos else { return self }
self.photos = unwrappedPhotos
return self
}
}
We know (atleast now) that operator overloading functions are absolutely fine, Nothing wrong there.
Given extension is changing values for a parameter, hence it should be mutating, and it is. Then why the error :
"Cannot use mutating member on immutable value: function call returns immutable value"
Reason : When "appendTitle" or "appendPhotos" is invoked, it returns a copy of self. Not the exact same reference!
This is because of the way swift deals with immutability. If value for a member property is changed for a value type, a copy is created with assigning the value to the respective member.
Hence, when you write : Section().appendTitle(title).appendPhotos(photos)
Section()
returns a copy of self i.e. an immutable version of Section.
Therefore one can't appendTitle
to it, or cannot mutate it in general.
That can be solved :
var section = Section()
section.appendTitle(title).appendPhotos(photos)
But now appendTitle(title)
returns a copy of self i.e. an immutable version of Section. and same problem persists.
What you did was that instead of changing anything with self
, you created a new instance, this time a mutable one using var
. Mutated it and returned it. Now it's not mutating self, hence it need not be a mutating func
.
The solution you provided works well here, but in reality it is a hack, which is needed here to cover what i would say a "bug" in Swift for now.
Other solutions can be changing struct Section
to class Section
. There you would not need to create var result
, just change the properties and return.
This is my first answer on SO :)