lambda, autodispatching msgs & stuff
- To: misc <MISC>
- Subject: lambda, autodispatching msgs & stuff
- From: Eugen Leitl <ui22204@xxxxxxxxxxxxxxxxxxxxxxx>
- Date: Mon, 12 Jun 1995 20:48:12 +0200 (MET DST)
Lambda, Autodispatching messages, microloops & stuff.
(Sorry, I intended this post to be a pure LAMBDA plaedoyer, but
once again I got carried away..)
Object oriented programming (OOP) needs efficient means of
encoding and sending messages. A message can be either a
_literal_ or a _reference_. A literal message stands for itself,
a reference is a pointer to a message structure somewhere in the
memory.
In register machines, literal messages occupy several registers.
Usually the first register contains the type of the message.
In stack machines a message should occupy a stack frame.
Stack picture:
top
+--------------+ <<<< TOS
| message 1 |
+--------------+
| |
| message 2 |
| |
+--------------+
| .... |
+--------------+
bottom
Sending a message to an object is equivalent to a according
procedure call with certain parameters. Let us assume the
existance of the LAMBDA instruction, which causes the top of the
stack element (TOS) to be considered as an instruction and
immediately executed (transferred to the instruction register and
immediate triggering of execution).
Note that this code has no address in main store (ephemeral
one-time pad code) (that is unless top stack elements also
appear in main memory somewhere ;)
In register architectures, an address register may contain a
pointer to the right object method, then e.g. JSR (A0) (for
MC68xxx) is a way to dispatch it.
If the message occupies several (at least one) elements, the
first of them being the opcode of CALL xyz (xyz being the
address of the appropriate object method to do the according
action and then drop the message frame, leaving stack swept
clean), then the execution of LAMBDA is an efficient means to
send a message to an object. Since the object which builds the
message structure on stack knows both the structure syntax to to
which object it is to go, it can construct the message on stack
by hand, saying "LAMBDA" and hey presto! the message has been
dispatched.
E.g. for dispatching an I/O (mouse, keyboard, 6DOF tracker,
etc.) event we'd need about this structure:
A four-entry stack frame for a mouse event.
Offs. Entry
0 CALL gfx.mouseEventHandler
-1 MouseX (integer, coordinate)
-2 MouseY (integer, coordinate)
-3 EventType (integer, e.g. leftmousebutton, rightmousebutton,
midmousebutton, doubleclick, tripleclick, etc.)
EventType, e.g.:
+------- leftmousebutton
| +----- midmousebutton
| | +--- rightmousebutton
| | | +- other modifiers (shift, alt, altgr, ctl, capsLock, etc).
| | | | +-+-- event code
| | | | | |
0 0 0 u v w x y z x x x x a b
0 0 single click
0 1 double click
1 0 triple click
1 1 whatever
If we maintain a coarse object pointer map (array), assigning
e.g. 4x4 or 8x8 pixel blocks to each object, we can shift each
coordinate right by 2 or 3 bits thus reducing resolution, then
compute a pointer (e.g. by shifting y left and pasting them with
OR, indexing the right object from slot, calling the appropriate
method (e.g. adding known offset upon object base). All this
does the CALL gfx.mouseEventHandler, substituting own CALL to a
new CALL, then saying LAMBDA. This restricted type of LAMBDA can
be emulated pushing an address upon return stack and executing
";".
Note that objects should maintain pointer map by themselves,
since only they knew what kind of buttons, sliders and hot spots
they have. An object atop should save (run-length encoded)
pointers it is about to overlap, restoring them when it has to
go. (But autodispatching method quadtrees are better, since they
allow variable resolution till down to pixel level)
Usually, the input stream is directed only to the one active
object (e.g. highligted window) on screen. There should be many
of them. Alternatively, pipelines, trees and generic graphs
should be allowed. For this, an autoforwarding message is
needed. It would create copies of itself and CCing them to
several objects.
I/O--+-- analog
+-- video
+-- mass storage
+-- keyboard
+-- mouse
+-- network
+-- etc.
An generic I/O packet would CC the I/O message packet stream to
any objects caring to listen (typically, quite few).
Moreover, if LAMBDA has a reserved bit in instruction opcode and
the same bit is set in the TOS instruction, then execution of
LAMBDA causes infinite looping of the packed instruction (unless
TOS is being modified by that instructions). If we also assume
the existance of DROP instruction bit in the word, having higher
precedence, than lambda, then a sequence of instructions on
stack will be interpreted. This allows construction of ephemeral
methods (having no according core image).
There might be uses for this, but it looks somewhat esoteric,
I must admit.
Microloops. I don't know what they are, but I suppose there is
an opcode causing the next (or this?) word to be iterated at
maximum speed until a breaking condition is achieved, e.g. carry
or zero. Tiny loops can be very useful, but is there a means to
iterate a CALL, I wonder?