﻿1
00:00:00,480 --> 00:00:04,600
This video will focus
on an advanced aspect of Pharo,

2
00:00:04,800 --> 00:00:10,800
which is the reflective operations
needed for the live programming we use.

3
00:00:11,680 --> 00:00:16,680
We will look at what happens
when we recompile a class.

4
00:00:17,040 --> 00:00:20,080
And we'll explain
the reflective operations

5
00:00:20,200 --> 00:00:24,720
needed for implementing
live programming.

6
00:00:24,920 --> 00:00:26,560
Here's a typical case.

7
00:00:26,720 --> 00:00:30,320
We usually start by defining a class,

8
00:00:30,600 --> 00:00:34,640
then we add methods
and create instances for this class.

9
00:00:35,160 --> 00:00:40,400
Then we redefine the class
and add new instance variables.

10
00:00:41,200 --> 00:00:45,640
So, what do we do with the instances
that already existed

11
00:00:46,160 --> 00:00:48,440
when there was one less attribute?

12
00:00:48,680 --> 00:00:53,920
We must set up a mechanism
to migrate these instances

13
00:00:54,280 --> 00:00:57,360
over to the new version of the class.

14
00:00:57,640 --> 00:00:59,160
Then we keep working.

15
00:00:59,600 --> 00:01:03,200
After that, we will look at operations

16
00:01:04,440 --> 00:01:09,160
that enable dynamic class redefinition,
method recompilation,

17
00:01:09,600 --> 00:01:11,040
and which allow for

18
00:01:11,400 --> 00:01:15,160
an automatic and transparent
migration of instances

19
00:01:15,360 --> 00:01:18,200
to the new version of the class.

20
00:01:18,520 --> 00:01:22,560
To do this, we need to
collect all the class instances.

21
00:01:22,840 --> 00:01:28,280
Then we need to switch over
everything that used these objects

22
00:01:28,840 --> 00:01:31,920
and assign their pointers
to new objects.

23
00:01:32,400 --> 00:01:33,400
Okay?

24
00:01:34,160 --> 00:01:38,920
First, how do we collect
all the instances of a class?

25
00:01:39,400 --> 00:01:43,560
If we send the allInstances message
to a class,

26
00:01:43,800 --> 00:01:47,320
it shows all the objects
that are its instances.

27
00:01:47,640 --> 00:01:51,440
It's a collection
of all the standard objects.

28
00:01:51,640 --> 00:01:57,800
If we send it to Window class,
we get a collection of Window objects.

29
00:01:58,280 --> 00:02:02,760
We can retrieve the first element
and send a "close" message,

30
00:02:02,920 --> 00:02:06,840
since the "close" method
is defined in the Window class.

31
00:02:07,360 --> 00:02:11,840
Another reflective primitive
is pointersTo.

32
00:02:12,160 --> 00:02:16,920
If we send this message to an object,
we access the collection

33
00:02:17,400 --> 00:02:21,000
of all objects that store
a reference to the object.

34
00:02:21,200 --> 00:02:23,040
This is very useful

35
00:02:23,200 --> 00:02:27,320
when we want to swap objects.

36
00:02:29,560 --> 00:02:34,080
The primitive for swapping pointers
is "become."

37
00:02:34,600 --> 00:02:39,760
The idea is to enable us
to exchange two objects.

38
00:02:41,160 --> 00:02:43,840
We want to swap them symmetrically.

39
00:02:44,200 --> 00:02:48,200
Everything that pointed to this object
in the system,

40
00:02:48,720 --> 00:02:51,160
in this case we have two pointers,

41
00:02:51,360 --> 00:02:55,840
will be inverted so that the elements
now point to this object.

42
00:02:57,280 --> 00:03:01,720
We break the links for the pointers
that were on this side,

43
00:03:02,280 --> 00:03:04,080
so they switch objects.

44
00:03:06,360 --> 00:03:11,680
"Become" means to invert all pointers
in the system symmetrically.

45
00:03:13,280 --> 00:03:15,080
Here's an example.

46
00:03:15,320 --> 00:03:17,600
I create a point 1,

47
00:03:17,800 --> 00:03:22,320
which points to the object point 0@0
and a variable pt2,

48
00:03:22,840 --> 00:03:25,320
which also points to the object 0@0.

49
00:03:25,560 --> 00:03:29,560
Plus a variable pt3
that points to the point 100@100.

50
00:03:29,800 --> 00:03:33,200
Then I write the primitive
pt1 become: pt3.

51
00:03:34,160 --> 00:03:38,680
Everything that pointed to the object
denoted by the variable pt1

52
00:03:38,920 --> 00:03:41,440
will now point to point 3.

53
00:03:42,200 --> 00:03:44,400
That is, all the pointers to pt1.

54
00:03:44,600 --> 00:03:49,760
We see that the variable pt2
pointed to the same object as pt1,

55
00:03:49,920 --> 00:03:54,400
and now it points to
that which was referenced by pt3.

56
00:03:54,760 --> 00:04:00,440
As for pt3, since it's symmetrical,
it will point to what pt1 pointed to.

57
00:04:00,640 --> 00:04:01,760
Up the top.

58
00:04:02,800 --> 00:04:06,080
And pt1 points to what pt3 pointed to.

59
00:04:06,280 --> 00:04:10,000
The pointers have thus been swapped
symmetrically.

60
00:04:11,200 --> 00:04:14,800
The asymmetrical variant
is becomeForward.

61
00:04:15,440 --> 00:04:18,400
It indicates
that we want to swap pointers.

62
00:04:18,640 --> 00:04:23,360
Everything that pointed to this object
will swap over to that object.

63
00:04:24,080 --> 00:04:28,400
But not the contrary.
Pointers to this object stay the same.

64
00:04:31,520 --> 00:04:34,640
Here's another example using points.

65
00:04:35,280 --> 00:04:39,640
When we execute a becomeForward,

66
00:04:39,920 --> 00:04:45,080
we see that it impacts on pt1 and pt2.

67
00:04:45,600 --> 00:04:48,640
Pt3 was not affected
by the becomeForward,

68
00:04:48,840 --> 00:04:53,000
and those that pointed
to this object are unchanged.

69
00:04:55,400 --> 00:04:59,840
Another reflective primitive
is adoptInstance.

70
00:05:00,200 --> 00:05:02,640
This changes an object's class.

71
00:05:02,840 --> 00:05:07,920
We ask a class to adopt a new instance,
passed as a parameter.

72
00:05:08,560 --> 00:05:13,400
Changing a class is a very powerful,
but rather limited, tool.

73
00:05:13,640 --> 00:05:17,520
It's essential
that the object's original class

74
00:05:18,160 --> 00:05:19,840
in this case, anInstance,

75
00:05:20,040 --> 00:05:24,680
is compatible with the format
of the target class.

76
00:05:25,440 --> 00:05:29,160
You can't just swap any object.

77
00:05:29,360 --> 00:05:31,840
Sometimes it's indexed, etcetera.

78
00:05:32,080 --> 00:05:36,000
The format of an object
is very important.

79
00:05:36,680 --> 00:05:40,640
Let's look at
what a class is in essence.

80
00:05:40,920 --> 00:05:43,360
A class is essentially a format.

81
00:05:43,640 --> 00:05:47,200
A format specifies the number
of instance variables

82
00:05:47,400 --> 00:05:52,520
and the type of variables,
as we explained in an earlier course.

83
00:05:52,840 --> 00:05:56,000
It has a superclass
and a method dictionary.

84
00:05:56,840 --> 00:06:01,680
Here we have Behavior class,
which is a superclass

85
00:06:02,080 --> 00:06:07,520
of Class class,
which defines basic class behavior.

86
00:06:08,160 --> 00:06:11,000
It's the basic minimum for a class.

87
00:06:11,200 --> 00:06:14,720
So, a class has a superclass,
a method dictionary,

88
00:06:14,840 --> 00:06:18,200
and format specifications.

89
00:06:19,200 --> 00:06:24,440
I'll now summarize
all the reflective behavior features

90
00:06:25,000 --> 00:06:27,360
that we've discussed so far,

91
00:06:28,440 --> 00:06:33,440
which give certain instances
behavior that is specific to them.

92
00:06:34,760 --> 00:06:37,800
I'll explain the code as we go along.

93
00:06:38,000 --> 00:06:42,400
We'll create an instance
of Behavior class on these three lines.

94
00:06:42,640 --> 00:06:44,280
Remember, it's a class.

95
00:06:44,640 --> 00:06:50,080
I create an instance of the class,
which I name Behavior.

96
00:06:51,600 --> 00:06:54,400
That gives me an object named Behavior.

97
00:06:55,040 --> 00:07:00,600
I indicate that this object
inherits from Model class.

98
00:07:02,000 --> 00:07:03,000
Like this.

99
00:07:03,680 --> 00:07:08,080
I set the format
of this object Behavior.

100
00:07:08,600 --> 00:07:12,400
Then I create an instance
of Model class here.

101
00:07:14,520 --> 00:07:16,360
It's an object named Model.

102
00:07:17,200 --> 00:07:20,080
Here is the important line in this code.

103
00:07:20,760 --> 00:07:23,920
I'll change the class
of this object Model

104
00:07:24,080 --> 00:07:28,920
to become a class of the object
passed as a parameter, named Behavior.

105
00:07:29,200 --> 00:07:34,400
I break the link
and make it an instance of this class.

106
00:07:34,800 --> 00:07:37,400
This is a subclass of Model class.

107
00:07:38,800 --> 00:07:43,400
Now I can compile
a new method in this class.

108
00:07:43,600 --> 00:07:47,400
I compile with the method foo,
which returns 2.

109
00:07:48,840 --> 00:07:51,840
I'm doing this in the object Behavior.

110
00:07:53,560 --> 00:07:55,280
As we can see here,

111
00:07:55,560 --> 00:07:59,840
if I send the message foo
to the object Model over here,

112
00:08:01,000 --> 00:08:02,160
like this,

113
00:08:02,760 --> 00:08:04,160
it will return 2.

114
00:08:04,640 --> 00:08:06,720
This follows the lookup method.

115
00:08:07,400 --> 00:08:09,040
I send the foo message.

116
00:08:09,200 --> 00:08:14,600
The object Model searches for the method
in its class, the object Behavior,

117
00:08:14,800 --> 00:08:17,360
and successfully finds the method.

118
00:08:17,760 --> 00:08:19,160
It works perfectly.

119
00:08:19,920 --> 00:08:24,080
But if I create a new instance
of Model class,

120
00:08:25,200 --> 00:08:26,200
like this,

121
00:08:26,560 --> 00:08:28,360
and I send the message foo,

122
00:08:29,360 --> 00:08:33,360
an error is indicated
by MessageNotUnderstood.

123
00:08:33,640 --> 00:08:35,800
Because if I apply ToLookUp,

124
00:08:36,080 --> 00:08:39,080
I look in the object's class,
Model class,

125
00:08:39,320 --> 00:08:43,920
but I don't find the foo method
in its dictionary or its superclasses.

126
00:08:45,040 --> 00:08:51,040
This advanced mechanism
allows us to endow a specific instance

127
00:08:51,520 --> 00:08:54,040
of Model class with a behavior.

128
00:08:54,200 --> 00:08:57,840
Let's apply this to Set class
to make it clearer.

129
00:08:58,040 --> 00:09:01,280
I create set1, an instance of Set class.

130
00:09:01,800 --> 00:09:05,720
The Set class method dictionary
contains the method add:.

131
00:09:06,400 --> 00:09:11,520
For a specific instance of Set class,
I want to change the method add:,

132
00:09:11,720 --> 00:09:15,360
which has a specific behavior
for a specific set.

133
00:09:15,520 --> 00:09:18,400
So, I create an "anonymous" class here.

134
00:09:18,840 --> 00:09:22,920
It's a specific class that inherits
from Set class.

135
00:09:23,280 --> 00:09:25,200
Here is its inheritance.

136
00:09:25,600 --> 00:09:31,160
The object set2 is an instance
of this "anonymous" class.

137
00:09:31,720 --> 00:09:37,000
In its method dictionary,
I'll redefine the method add:

138
00:09:37,320 --> 00:09:40,640
by giving it a particular behavior.

139
00:09:40,920 --> 00:09:45,800
Now, if I send the message add:
to the object set2,

140
00:09:46,080 --> 00:09:48,400
this method will be selected,

141
00:09:48,800 --> 00:09:52,320
and it will have a specific,
different behavior

142
00:09:53,600 --> 00:09:58,040
from the method add: here
if we had sent the message to this set.

143
00:09:58,280 --> 00:10:03,360
So, we have two sets that react
differently to the message add:.

144
00:10:03,680 --> 00:10:07,080
Here is the code
to conduct this exercise.

145
00:10:07,400 --> 00:10:11,280
Just like before, I create a class

146
00:10:11,640 --> 00:10:13,800
as an instance of Behavior class.

147
00:10:14,080 --> 00:10:16,840
I set the superclass at Set class.

148
00:10:17,400 --> 00:10:18,640
I set the format.

149
00:10:18,840 --> 00:10:23,600
I compile the method add:
in this anonymous class.

150
00:10:24,080 --> 00:10:29,360
I'm redefining the method add:
that is defined in Set class.

151
00:10:30,080 --> 00:10:36,080
I use "Transcript show" to display
the execution of the method add:.

152
00:10:36,400 --> 00:10:40,680
Then I call "super" to execute
the method add: in Set class.

153
00:10:41,360 --> 00:10:45,720
Now we'll test this code
by creating a first set.

154
00:10:45,920 --> 00:10:48,600
I have Set class here.

155
00:10:50,280 --> 00:10:54,280
I create the first instance
of this class, named Set.

156
00:10:55,080 --> 00:10:57,040
I send it the message add:.

157
00:10:58,920 --> 00:11:03,760
I send add: 1, which uses
the method add: from Set class.

158
00:11:05,240 --> 00:11:08,720
If I ask for Set class here,
I'll get Set.

159
00:11:09,400 --> 00:11:13,160
But now I'll execute this primitive
you see here.

160
00:11:13,600 --> 00:11:16,200
I ask the object Set to change classes

161
00:11:16,400 --> 00:11:21,160
and to use Behavior class from earlier,
which is a subclass

162
00:11:22,080 --> 00:11:23,760
of Set class.

163
00:11:24,360 --> 00:11:28,400
So, it changes and becomes
an instance of Set class,

164
00:11:28,680 --> 00:11:32,000
which has a new version
of the method add:.

165
00:11:32,280 --> 00:11:37,920
Now, if I send the message
add: 2 to this object,

166
00:11:38,360 --> 00:11:43,280
it will select the method add:
from the object Behavior,

167
00:11:43,560 --> 00:11:45,720
and it will execute this code.

168
00:11:46,280 --> 00:11:48,920
We can check in the Transcript

169
00:11:49,760 --> 00:11:53,280
if the method has been executed.

170
00:11:53,640 --> 00:11:57,400
It will eventually be executed,

171
00:11:57,640 --> 00:12:02,040
since we also use "super"
for the method add: from Set class.

172
00:12:02,840 --> 00:12:07,840
This allows us to spy
on instances selected in Set,

173
00:12:08,080 --> 00:12:09,560
using this line here.

174
00:12:11,200 --> 00:12:12,400
To conclude,

175
00:12:12,600 --> 00:12:19,200
all these reflective operations
allow us to create very innovative tools.

176
00:12:19,440 --> 00:12:23,840
We can test out
and implement new features

177
00:12:24,080 --> 00:12:29,400
thanks to these reflective primitives,
which promote language extensibility.

178
00:12:30,200 --> 00:12:34,080
But there's a golden rule
when using reflection.

179
00:12:34,320 --> 00:12:38,800
You must not use it inappropriately
in domain code.

180
00:12:39,040 --> 00:12:44,720
We limit the use
of reflective codes in domain code.

181
00:12:45,080 --> 00:12:49,200
Reflection can violate
the encapsulation of objects.

182
00:12:49,840 --> 00:12:51,000
It can really...

183
00:12:51,440 --> 00:12:54,640
It can overstep
object programming rules,

184
00:12:54,840 --> 00:12:58,520
and is therefore reserved
for constructing tools.