2014-07-15 22:20:14 +02:00
|
|
|
---
|
|
|
|
layout: news
|
|
|
|
author: Torsten
|
|
|
|
---
|
|
|
|
|
|
|
|
In a picture, or when taking a picture, the frame is very important. It sets whatever is in the picture into context.
|
|
|
|
|
|
|
|
So it is a bit strange that having a **frame** had the same sort of effect for me in programming. I made the frame explicit,
|
|
|
|
as an object, with functions and data, and immidiately the whole message sending became a whole lot clearer.
|
|
|
|
|
|
|
|
You read about frames in calling conventions, or otherwise when talking about the machine stack. It is the area a function
|
|
|
|
uses for storing data, be it arguments, locals or temporary data. Often a frame pointer will be used to establish a frames
|
|
|
|
dynamic size and things like that. But since it's all so implicit and handled by code very few programmers ever see it was
|
|
|
|
all a bit muddled for me.
|
|
|
|
|
|
|
|
My frame has: return and exceptional return address, self, arguments, locals, temps
|
|
|
|
|
|
|
|
and methods to: create a frame, get a value to or from a slot or args/locals/tmps , return or raise
|
|
|
|
|
|
|
|
### The divide, compile and runtime
|
|
|
|
|
|
|
|
I saw [Tom's video on free compilers](http://codon.com/compilers-for-free) and read the underlying book on
|
|
|
|
[Partial Evaluation](http://www.itu.dk/people/sestoft/pebook/jonesgomardsestoft-a4.pdf) a bit, and it helped to make the
|
|
|
|
distinctions clearer. As did the Layers and Passes post. And the explicit Frame.
|
|
|
|
|
|
|
|
The explicit frame established the vm explicitly too, or much better. All actions of the vm happen in terms of the frame.
|
|
|
|
Sending is creating a new one, loading it, finding the method and branching there. Getting and setting variables is just
|
|
|
|
indexing into the frame at the right index and so on. Instance variables are a send to self, and on it goes.
|
|
|
|
|
|
|
|
The great distinction is at the end quite simple, it is compile-time or run-time. And the passes idea helps in that i start
|
|
|
|
with most simple implementation against my vm. Then i have a data structure and can keep expanding it to "implement" more
|
|
|
|
detail. Or i can analyse it to save redundancies, ie optimize. But the point is in both cases i can just think about
|
|
|
|
data structures and what to do with them.
|
|
|
|
|
|
|
|
And what i can do with my data (which is off course partially instruction sequences, but that's beside the point) really
|
|
|
|
always depends on the great question: compile time vs run-time. What is constant, can i do immediately. Otherwise leave
|
|
|
|
for later. Simple.
|
|
|
|
|
|
|
|
An example, attribute accessor: a simple send. I build a frame, set the self. Now a fully dynamic implementation would
|
|
|
|
leave it at that. But i can check if i know the type, if it's not reference (ie integer) we can raise immediately. Also the
|
|
|
|
a reference tags the class for when that is known at compile time. If so i can determine the layout at compile time and
|
|
|
|
inline the get's implementation. If not i could cache, but that's for later.
|
|
|
|
|
|
|
|
As a furhter example on this, when one function has two calls on the same object, the layout must only be retrieved once.
|
|
|
|
ie in the sequences getLayout, determine method, call, the first step can be ommitted for the second call as a layout is
|
|
|
|
constant.
|
|
|
|
|
|
|
|
And as a final bonus of all this clarity, i immediately spotted the inconcistency in my oen design: The frame i designed
|
|
|
|
holds local variables, but the caller needs to create it. The caller can not possibly know the number of local variables
|
|
|
|
as that is decided by the invoked method, which is only known at run-time. So we clearly need a two level thing here, one
|
2014-07-16 23:54:36 +02:00
|
|
|
that the caller creates, and one that the receiver creates.
|
2014-07-15 22:20:14 +02:00
|
|
|
|
|
|
|
### Messaging and slots
|
|
|
|
|
|
|
|
It is interesting to relate what emerges to concepts learned over the years:
|
|
|
|
|
|
|
|
There is this idea of message passing, as opposed to function calling. Everyone i know has learned an imperative
|
|
|
|
language as the first language and so message passing is a bit like vegetarian food, all right for some. But off course there
|
|
|
|
is a distinct difference in dynamic languages as one does not know the actual method invoked beforehand. Also exceptions
|
|
|
|
make the return trickier and default values even the argument passing which then have to be augmented by the receiver.
|
|
|
|
|
|
|
|
One main difficulty i had in with the message passing idea has always been what the message is.
|
|
|
|
But now i have the frame, i know exactly what it is: it is the frame, nothing more nothing less.
|
|
|
|
|
|
|
|
Another interesting observation is the (hopefully) golden path this design goes between smalltalk and self. In
|
|
|
|
smalltalk (like ruby and...) all objects have a class. But some of the researchers went on to do
|
|
|
|
[Self](http://en.wikipedia.org/wiki/Self_(programming_language)), which has no classes only
|
|
|
|
objects. This was supposed to make things easier and faster. Slots were a bit like instance variables, but there were no
|
|
|
|
classes to rule them.
|
|
|
|
|
|
|
|
Now in ruby, any object can have any variables anyway, but they incur a dynamic lookup. Layouts on the other hand are like
|
|
|
|
slots, and keeping each Layout constant (while an object can change layouts) makes it possible to have completely
|
|
|
|
dynamic behaviour (smalltalk/ruby) **and** use a slot-like (self) system with constant lookup speed. Admittatley the
|
|
|
|
constantcy only affects cache hits, but as most systems are not dynamic most of the time, that is almost always.
|