Skip to content

Instantly share code, notes, and snippets.

@keybuk
Last active August 29, 2015 14:08
Show Gist options
  • Save keybuk/2dae7eff37b4e78c77f1 to your computer and use it in GitHub Desktop.
Save keybuk/2dae7eff37b4e78c77f1 to your computer and use it in GitHub Desktop.
Sub-property Black Magic in Swift
First we set up a struct, a by-value type:
1> struct Point {
2. var x, y: Int
3. }
And we make an array of them:
4> var points = [Point]()
points: [(Point)] = 0 values
5> points.append(Point(x: 0, y: 0))
6> points.append(Point(x: 3, y: 2))
7> points.append(Point(x: 2, y: -1))
8> points.append(Point(x: 3, y: 1))
If we use the a subscript, we can return one of those points structures:
9> points[1]
$R1: (Point) = {
x = 3
y = 2
}
We can place it in a new variable, modify it, and see that it doesn't affect the value in the array:
10> var point = points[1]
point: (Point) = {
x = 3
y = 2
}
11> point.x = -2
12> point
$R3: (Point) = {
x = -2
y = 2
}
13> points[1]
$R4: (Point) = {
x = 3
y = 2
}
But we if modify the value of x directly through the subscript, it changes the actual array member.
14> points[1].x = -2
15> points[1]
$R5: (Point) = {
x = -2
y = 2
}
So this didn't return a new copy of the value, and modify that. Black magic happened and it operated
directly on the value referred to by the array.
Does the same hold true for custom classes and subscript methods?
16> class Line {
17. var points = [Point]()
18. subscript(i: Int) -> Point {
19. get {
20. return points[i]
21. }
22. set {
23. points[i] = newValue
24. }
25. }
26. }
27> var line = Line()
line: Line = {
points = 0 values
}
28> line.points.append(Point(x: 0, y: 0))
29> line.points.append(Point(x: 3, y: 2))
30> line.points.append(Point(x: 2, y: -1))
31> line.points.append(Point(x: 3, y: 1))
Modify a point through a variable:
32> line[1]
$R6: Point = {
x = 3
y = 2
}
33> point = line[1]
point: Point = {
x = 3
y = 2
}
34> point.y = 4
35> point
$R7: Point = {
x = 3
y = 4
}
36> line[1]
$R8: Point = {
x = 3
y = 2
}
So that's the same, modifying via a variable only modifies the variable.
What about modifying directly through the subscript?
37> line[1].x = -1
38> line[1]
$R9: Point = {
x = -1
y = 2
}
Same too. Even though we wrote no special code, and just used "return", somehow the black
magic is preserved and we can modify through a subscript.
Okay, what about computed properties?
39> extension Line {
40. var start: Point {
41. get {
42. return points[0]
43. }
44. set {
45. points[0] = newValue
46. }
47. }
48. }
49> line.start
$R10: Point = {
x = 0
y = 0
}
50> line.start.x = 2
51> line.start
$R11: Point = {
x = 2
y = 0
}
Nyaargh!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment