ruby-x.github.io/_posts/2014-07-17-framing.md
2016-02-25 19:10:56 -08:00

77 lines
5.2 KiB
Markdown

---
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 getType, 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 own 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
that the caller creates, and one that the receiver creates.
### 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.
(Postscript: Later introduced the Message object which gets created by the caller, and the Frame is what is created
by the callee)
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 smalltalk 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. Types on the other hand are like
slots, and keeping each Type 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.