Last active
July 22, 2016 00:59
-
-
Save gsheld/542a57c1ca5efe87892a28759215283e to your computer and use it in GitHub Desktop.
Example: Struct syntax for requesting a copy with an ivar set to an explicit value
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Foo { | |
var bar = 0 | |
var baz: String | |
} | |
let foo = Foo(bar: 1, baz: "baz") // Initial struct instance | |
let fooWithNewBar = foo.withBar(2) // Returns a new `Foo` with `bar` set to 2; `baz` remains set to "baz". | |
let fooWithNewBaz = foo.withBaz("BAZ") // Returns a new `Foo` with `baz` set to "BAZ"; `bar` remains set to 1. | |
let fooWithChaining = foo.withBar(3) // Example of method chaining using this approach. `bar` is set to 3 and | |
.withBaz("BaZ") // `baz` is set to "BaZ". | |
// Note that both `bar` and `baz` are var (mutable) properties. Although it is possible in certain situations to create | |
// a copy of an object with a let (constant) property** set to a certain value (e.g. when the value of the let property is | |
// directly injected into the initializer), it would be impossible to adapt the .withX() syntax to lets in all situations. | |
// The .withX() syntax proposed above is a simple syntactic sugar. The same affect can be achieved using | |
// already-available swift syntax: | |
struct Foo { | |
var bar = 0 | |
var baz: String | |
func withBar(bar: Int) -> Foo { | |
var newFoo = self | |
newFoo.bar = bar | |
return newFoo | |
} | |
func withBaz(baz: String) -> Foo { | |
var newFoo = self | |
newFoo.baz = baz | |
return newFoo | |
} | |
} | |
// Of course, the downside of this approach is the additional boilerplate required to generate these immutable "setters". | |
// It would require the enterprising developer to write similar code for *all* structs for which they would like to use | |
// this syntax. It would also force developers to extend those Structs for which they do not have the source code (e.g. | |
// String). | |
// Given Swift's focus on immmutability as evidenced by the design of Struct (e.g. the keyword "mutating" is explicitly | |
// required to achieve mutability in any Struct property or method), I feel the syntax proposed above would reduce the | |
// burden of developers interested in transitioning to more immutable-APIs. Of course, there is always the danger of | |
// overuse and potential for confusion with actual "setters" that do change the state of a particular instance. That is why | |
// feedback would be most welcome! | |
// ** The same logic can be applied to "private(set)" properties. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's worth noting that there is another similar suggestion by Erica Sadun which involves syntax for method cascading.
A form of method cascading can also be achieved with vanilla Swift 2.2 --
For setting a single property, method cascading is not quite as elegant but is more general use than what I propose -- e.g. the syntax is valid with both methods and properties in addition to working on Class-based abstractions. Its an interesting alternative to the method chaining I briefly outline above, but their use cases do seem somewhat different.