Hello. In this sequence we'll be looking at Reflection,
the capacity for Introspection in Pharo and why it's useful.
A reflective system,
reflection is divided into 2 major families,
Introspection
is a program's ability to observe its own state,
Intercession is a program's ability to modify itself.
To modify its own state or interpretation.
Reification is a concept that consists
of making explicit (objects) things that are normally implicit.
For example, the execution stack
in Pharo is explicit, but can be got as a classic object.
More classically, a class in Pharo is a totally classic object.
In other languages, classes aren't objects.
A reflective system, as I said,
has its own representation of itself.
It's capable of representing itself,
and it can act on this representation to modify itself,
and when it modifies itself it changes its state and representation.
We call it a "causal connection"
between its representation and its state.
If we change the state,
the system representation changes as well as the state of the system.
Why is this interesting? It's interesting because we'll use
this introspection and intercession
to look inside objects.
I'm defining a collection, which I make an "OrderedCollection"
then I'll use the Pharo Inspector, which is a tool,
which can look inside this object.
It's an instance object of the OrderedCollection class,
as we see here, it has instance variables,
"first index", "last index",
we have the values of this object's instance variables
so 1, 12 and then an array of 12 elements, OK?
We might wonder how this Inspector tool
is able to look inside objects.
How can it see the internal state of objects?
It uses introspection methods to look inside the objects,
There are lots of them, defined as "objects".
So "instVarAt" allows us to see
an instance invariable according to its number.
I'll see instance variable number 1 of this object.
I can modify instance variable number 1 of this object by setting a new value,
or I can access an instance variable by its name,
or change it by its name, "instVarNamed put". OK?
Here are some examples. Typically we create a point,
and then we do... the point is 10@3
instVarNamed: 'x'.
I'll get the value of the instance variable called 'x' of this point,
which gives me 10.
Then "instVarNamed: 'x' put:33"
I've changed the value of the instance variable 'x' of this point.
It's gone from 10 to 33.
I've been able to change the inner state of an object,
by using introspection and intercession,
particularly intercession, "instVarNamed put". OK?
The main point is that we've violated encapsulation.
An external object has modified this object, without being internal,
so it violates encapsulation but it's extremely useful
when building tools and during development.
It's not to be used in the normal code of an application,
but it's extremely powerful for building generic tools,
typically code inspectors.
I'll give you another example of introspection, the class method,
for getting the class of an object. It's defined in "Object>>class".
I ask this string its class, it gives me the class string,
this point what is its class, the class point,
"Smalltalk class", I can ask the class of the class class.
etcetera, then I add class class...
Basically, I can query the system
by sending the message "class" to objects to discover their class.
There are many methods for querying the system.
Here, I take "OrderedCollection" and send it lots of query messages.
I'll get all of its superclasses,
all of its selectors, the name of its instance variables,
all of the selectors, the name of its instance variables,
all of its subclasses, etc...
And all of its lines of code.
All of this allows us to build top level tools,
such as the navigation system here.
This navigation system lets us show or browse the system.
For example, I can see all the classes
that implement the method "#,".
Here we've a window that will open.
We'll see all the implementors of #,
so the class "AbstractFileReference" implements the method "#,".
I've a list of all the classes implemented by this method.
Another example, we'd like to implement
a menu or a button.
By clicking on it, we want to send a message to the object behind it,
according to the button's name, for example.
How do I turn a string into a message to send to an object?
I've an intercession method for that. "Perform" defined under "object".
I pass it a symbol, the name of a message to execute,
and it will send this message to the object in question.
I've a 2nd kind of message, "perform with".
I can give the name of the symbol, the name of the method to execute,
and then pass a list of arguments.
An example, if I do "5 factorial"
sending a classic message, and send the reflective message,
its "5 perform # factorial" that's a symbol which means,
"Object 5, please execute or receive the message factorial".
The normal lookup is applied and these two forms are the same.
Here's another example.
Here we have a code inspector
"Ordered collection", we can see inside the class "Ordered Collection".
This class contains attributes,
instance variables, for example "methodDict".
In "methodDict" we see that the class "OrderedCollection"
comes from "Behaviour" so it has a "methodDict' here,
an instance of "MethodDictionary" containing "CompiledMethod".
So we can see this method dictionary contains
a compiled method here, etc...
another compiled method... Lots of compiled methods.
We'll be able to ask each of these compiled methods
for their source code. If I do "self getSource"
I'll get the source code of the compiled method.
But we can go further.
A compiled method can be asked to execute itself directly
with the message, "valueWithReceiver:arguments".
But watch out! If I do that, there's no lookup.
Seeing as I already have a compiled method,
it executes itself directly without a message.
Here I'll ask the integer class to get its compiled method "factorial",
which I get from the class compiled method.
I send it the message, "valueWithReceiver:arguments".
I pass it the arguments, the receiver will be 5,
the arguments will be (), because it's a unary message,
and we'll get the result.
It triggers execution of the compiled method without lookup.
So to summarize, reflection is extremely powerful.
We've seen it's something that allows us to introspect
the whole system because it represents it
in itself as an object,
but also to modify the state of the system.
It lets us build tools in a generic way in all objects.
So you can really talk to objects
with a protocol that's structurally the same for all objects.
But watch out! It violates encapsulation.
It isn't used in operational code, but for tool building.
It facilitates the writing of code inspectors as we saw,
and you can see how it's implemented in Pharo.