The base idea behind Tweak is simple: Combine the best of Morphic with
the best of MVC. Morphic is a wonderful architecture as far as direct
manipulation is involved but it's a terrible architecture to build
reusable systems. Morphic simply doesn't have any abstractions and
that makes it very hard to build re-usable and flexible components.
BTW, it's not *impossible* to build reusable components it's just very
hard because the architecture itself doesn't help with it (it's like
writing secure code in C - yes it is possible to do it but it is very
hard). MVC, on the other hand, has some excellent properties as far as
abstraction is concerned. Because MVC is a "viewing architecture" it
encourages a better separation of concerns between the (domain) model
and the (graphical) view. Unfortunately, that's where MVC stops. It
doesn't allow you to use the same principles for building views itself
- once you get to the views things get messy since there is no
abstraction any more (e.g., it's not "turtles all the way down").
Tweak approaches this problem by combining the best of the two. It is
as directly accessible as Morphic and it provides a viewing
architecture similar to MVC. It achieves that by having one "primary
view" that we call an object's "costume" which is responsible for
handling all of the graphical requests sent to the object. That's what
makes it possible for a user to think of "just using an object"
whereas, in reality, you are actually always interacting with a pair
of player (model) and costume (view). And contrary to MVC you don't
have to worry about creating views for every object - you can start
out straightforwardly just like in Morphic, but when the time comes
there is an architecture that will allow you to build generalizations
from the concrete object. Another key idea in Tweak is that of
asynchronous event handling. Unfortunately I can't say I invented that
(though at the time where I came up with the idea I wasn't aware of
anybody else doing it) but it turns out that this is what is now
typically referred to as "event-loop concurrency". The idea here is
that all responses to events are asynchronous messages, e.g., are
executed some time *after* the event has been signaled. The reason
this is important is that by using asynchronous events you do not
expose internally inconsistent state to a listener. When you use
synchronous events (callbacks) you end up with the problem that the
listener (inadvertently or not) may request temporarily inconsistent
state or otherwise violates the invariants of the computation (like
raising an exception). A good (or rather bad) example is the system
notification mechanism in Squeak - it allows listeners to interfere
*during* the compilation process with unclear results what might
happen if there is any problem. In Tweak this simply cannot happen -
you get to execute your code only when the computation that signaled
the event is completed. There are actually many other reasons why
asynchronous events and event-loop concurrency generally are a good
idea (check it out at
http://www.erights.org/elib/concurrency/event-loop.html). I also think
that we've made some major usability advances by using method
annotations for method triggers (e.g., events triggering methods).
They look like here:
onMouseDown
"Handle a mouseDown event"
<on: mouseDown>
onButtonClick
"Handle the button's click event"
<on: click in: button>
and are displayed with icons in the latest versions of the
Tweak-enabled browser. Being able to see what event triggers a method
is a major advantage to the way things are done today. Tweak also
allows a little more "centralized control" for making simple graphical
objects. What this means is that I always envied the fact that other
systems (VisualBasic for example) get away with a single place to do
all their stuff as long as they don't get too complex. For example, in
VB you start out with a simple form that you design and then you write
some event responses for it. For the simple things you never leave
that form, it's exactly like programming in a procedural language
"inside the object" (yes, VB uses objects these days). The reason I
like this is because it avoids needless context switching, it's one of
these simple things that really ought to be simple. Compare this with
Morphic - at the least you have to write some initialization code
(aMorph when: #mouseDown send: #onMouseDown to: self) in a separate
method and often this won't work because many Morph's implement the
event responses improperly (even some of the Morphic tutorials teach
broken techniques by avoiding the appropriate "super" invokations).
And of course, if you want to change the initialization you need to
destroy the old and create a new object which feels very much like a
"compile, link, run" cycle to me. In Tweak, you use an event with the
<on:in:> annotation, which cannot be improperly overwritten and which
is recognized so your objects on the screen will react to the changed
annotation in real-time. Using events in this way avoids having to
poke around in other objects and enables us to have a relatively
well-understood centralized component to deal with the integration
aspects of your various UI elements.