add post about frames
This commit is contained in:
parent
b6c1e380e1
commit
5eddfec928
74
_posts/2014-07-17-framing.md
Normal file
74
_posts/2014-07-17-framing.md
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
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
|
||||
that the caller creates, and one that the callee 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.
|
||||
|
||||
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.
|
Loading…
Reference in New Issue
Block a user