[Fwd: Re: Prism Rationale, Part 1]
Wed, 06 Jan 1999 19:46:17 -0700
The following message is one of several that was accidently sent
directly between myself and David Jeske instead of to the mailing list.
I don't know if you'll find it useful, but here it is:
-------- Original Message --------
Subject: Re: Prism Rationale, Part 1
Date: Tue, 5 Jan 1999 11:08:44 -0800
From: David Jeske <email@example.com>
To: Jim Little <firstname.lastname@example.org>
On Tue, Jan 05, 1999 at 02:07:55AM -0700, Jim Little wrote:
> Although AOP and Prism are similar from the outside, the approach they
> take on the inside is very different. Prism focuses very strongly on
> enabling the user to create his own domain abstractions via the
> "reflection domain". AOP, on the other hand, has (I think) a fixed set
> of "aspect languages" which the Aspect Weaver(tm) is aware of. Prism
> also uses a semantic approach to programming, while AOP uses a more
> traditional syntactic approach.
Actually, the way I understand it AOP intends that you would make a
domain specific 'aspect language' to describe a particular
optimization aspect. Then the aspect weaver will compile together your
'functional' code (written in whatever) and your 'aspect' (written in
your domain specific aspect language). However, in implementation, the
aspect weaver has to know alot about both, and is a much more
monolithic piece of software. I think you may be able to get many of
the benefits of AOP from Prism by understanding the example about
different paradigms _within_ a domain which I tried to explain
before. I'll clarify it below.
> Looking back at what you said, I think I completely misunderstood you.
Yeah, you did, I'll clarify below.
> > In higher-level languages like smalltalk/self they homogonized
> > all actions into 'method calls/message sends'. However, then the
> > different paradigms are different protocols/collections of
> > methods. For example, do you use an array index type access pattern
> > (i.e. a->itemAt(1);) or do you use a linked-list access pattern?
> > It's often the case that you have a body of code which uses one access
> > pattern, but you'd like to store the data in another (usually
> > superior) access pattern because you want to add some functionality.
> Even though I'm not sure what you're saying here, I'll take this
> opportunity to go off on a tangent. :) Even though the object-oriented
> paradigm is very nice -- simple, complete, powerful -- it still doesn't
> do everything well. For example, in writing the Prism Compiler, I used
> Smalltalk's Model-View-Controller pattern... aka "Observer" in GOF's
> _Design Patterns_ book.
Okay. In the above example I'm not trying to say that OOP does
everything well, I'm just trying to illustrate a point using OOP. A
given domain has mappings from syntactic operations into some system
abstraction. I'll try to explain the point from the beginning:
In C to access an array, you might use any of:
array access a
pointer math *(a+1)
function call get_element(a,1);
Your choice of one or the other will affect your flexibility and
performance int he future because within the C domain, the
consequences of a given request are fixed. For example, if you use the
array access there is no way for you to later bind that code to call a
function when you access the array. In order to do that, you need to
be able to change the binding of the domain abstraction.
In a pure-syntax OO language, there are no different syntax, because
all of the above operations would be done the same way, with a method
call. However, there might be different method protocols which perform
the same or similar operations:
linear array a->itemAt(1);
linked list a->head();
hash table a->itemWithKey(1);
In OO languages however, it's at least possible to put a 'conversion'
object in the middle. So, for example, if I had a body of code which
was using a linear array, and I decided I really needed to store the
data in a hash table, I could still let that code access the data via
the linear array methods, but they would really be talking to a hash
table. Then some other body of code could talk directly to the hash
table to get the additional functionality it needed.
Use of this model with OO languages has two problems.
(1) compact and specific syntax is easier to understand and keep bug
free. For example, which is more coherent:
[[[a itemAt:1] mul: [b itemAt:2]] div: [c itemAt:3]] // obj-c
a * b / c; // traditional array access syntax
(2) most of today's compilation and run-time methodologies exact a
big performance penalty for 'converting' between different
For example, if I did write the 'conversion' object I talka bout
every access to the array which happened through it would be an extra
set of method calls slower.
I believe that just as you've identified the importance of being able
to define new domain abstractions which are specific to a problem,
it's important to be able to remap between different pieces of a
domain abstraction with little or no cost.
In other words, we want to be able to define compact syntax, as I
demonstrate in (1) above, but we also want to be able to rebind what
that compact syntax is doing within a given block of code, so that we
can 'weave' in an improvement to the whole block of code by changing
the domain abstraction instead of changing the code itself.
I also want the compiler/run-time technology to allow optimization to
be independent of syntax, and even abstraction levels. If I slip a
'domain conversion' in the middle somewhere, the compiler/run-time
should be capable of inlining the two levels together. For example, if
I had chosen to use the function call abstraction to access the array,
but the only thing happening in the function was an array access, the
resulting code should be the same as if I had written the syntax as an
array access, _even if the function exists in some external library_.
> emulating event-oriented programming with objects? As I was programming
> that code, I couldn't but thinking it would be a lot more convenient if
> I could just create an event-oriented domain abstraction in which I
> would say "when X changes, tell Y" or even "Y depends on X." Without
> all that observer/listener code I had to keep writing over and over in
> each class.
Agreed. I'm able to do these kinds of things to some degree with a
little language called 'Lua' because the language is filled with
'meta-mechanisms'. When an operation occurs (like a variable access or
set, function call, etc) you can bind in a new operation which
occurs. So in the above case, I could make a 'domain extention' where
a variable access will fire an event, and then I just apply that
domain extension to every variable which I'd like to send an event.
> Your original statement about system abstraction and domain abstraction
> is very true. System abstraction means viewing a chunk of code as one
> instruction. Domain abstraction means factoring out repeated chunks of
> code. I think any time we look at a program and see that every function
> (or class, or whatever) repeats the same pattern of identical or
> nearly-identical lines of code, there we have a candidate for domain
Good, I'm glad that made sense to someone else. I find that at work we
end up wacking domain abstraction ontop of our C code. Every 'function
declaration' is actually done with a macro. We have a few different
things which occur because of a function declaration, and they are all
explained in the macro definition. As a result, our code no longer
repeats this pattern.
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + email@example.com