Hello Fabrizio Thanks for your questions. Sorry it's taken so long to reply. I was off-line for most of the weekend. This gave me plenty of time to compose the reply so I guess I should offer a second apology for its length.
(Some might wonder why I bring up museum pieces like Oberon and HyperTalk on what is after all the *Java* posse. What can I say? I'm a generalist at heart. In our business, ideas seem to resurface periodically under new names because the problems we deal with resurface periodically in new guises. I think there are insights to be had by looking back at previous generations tackled these issues.) # HyperCard Ben Smith-Mannschott wrote: > Generally, one module would implement the Model and define some > kind of UpdateMessage. Another module would impelement a > view. Each view instance would inspect all UpdateMessages that > passed by to see if they pretained to the particular model > instance it was displaying. Fabrizio Giudici wrote: > Again, I don't understand somethinng - what made a Model different > than a View, if everything was in a hierarchy? You're assuming HyperCard distinguishes between model and view. It doesn't. The view is the model. What you see is what you get. For serious. A typical way of storing data that the user was not expected to see or manipulate directly was in a text field which was set to 'hidden'. And when I say "text field" I'm talking about a GUI control. Pretty slick^H^H^H^H^H sick, no? I love my source control and my repeatable builds and I don't think I'd like to go back to HyperCard where programming meant performing successive mutations directly on a binary-blob-of-a-document-that-IS-your-application. On the other hand, the very directness of this approach was a real productivity win when I was still young and naive. # Oberon B Smith-Mannschott wrote: > "Sending a message" was understood very literally. Messages were > instances of some extension of a base record type. You filled them > out and sent them off at which point they were *broadcast to all > viewers in the view hierarchy*, which reacted to the ones they > were interested in possibly by forwarding them on to their > children (contained widgets) and ignored the rest. > > There was no registration and there was no dangling objects due to > forgetting to unregister listeners. Every component was was in the > visual hierarchy and was thus in on all message broadcasts. You > didn't have to do anything, except react to messages that > interested you when they came. Closing a window automatically > removed it from the view hiearchy. Fabrizio Giudici wrote: > And what about performance? This sounds _exactly_ as the original > design in AWT for Java 1.0, that was dropped in Swing for 1.1 - it > was a performance hell. Not to say it sounds as a poor design to use > a containment hierarchy as a way to deliver events (no separation of > concerns, no MVC - unless I didn't understand it correctly, that > might be of course). Was Oberon ever used in a production systems? > It's quite common to sketch a clean and simple OO design, just to > find later that it can't deal with the real world. If instead the > answer to my question is that Oberon is being used in production and > it's performant, the interesting point is discussing how it manages > to do that. ## "In Production"? Well, it was used as an operating system for student workstations at ETH/Zurich for many years. (The Ceres-1, -2 and -3 workstations were designed and built at ETH.) I also know that it was used as part of an embedded system for controlling mixing of granulates plastic production. (Presented during JMLC 2000). But let's be honest: Oberon has't seen anything like the kind of wide-spread use we're used to seeing in the Java world. ## MVC in Oberon Oberon most certainly does follow the MVC pattern. This is not a coincidence as Oberon was inspired at least in part by Niklaus Wirth's exposure to PARC's Mesa & Cedar systems which shared ideas with SmallTalk. Oberon was Wirth & Gutknecht's effort to reduce these systems to their essence. I've included, at the end of this message, two sections 5.5 and 5.6 of _The Oberon Companion_. This is as good a summary as I could find of Oberon's take on MVC. A few notes: ### 5.5 Display Space - The discussion around figure 5.4 touches on Oberon's principle of "parental control", in particular: "Each parent frame is completely responsible for its direct descendant frames and thus indirectly responsible for its indirect descendants." - Figure 5.5 illustrates that non-visual ("model gadgets") also participate in the display space DAG by virtue of being a model for one or more "visual gadgets". ### 5.6 Messages and Broadcasting - "Model-view consistency" describes the core of Oberon's MVC with an example. - "Types of broadcast" again discusses "parental control". ## Performance One might think the performance of message broadcasting would be terrible. The work required to broadcast a message should grow linearly with the complexity of the view graph. In practice, however, performance is not generally a problem. With 30 documents open (or applications running -- the distinction is not very meaningful in Oberon), I found that I could broadcast 3300 messages a second into the display space. [Dell Mini 9 (Atom @ 1.66GHz); Linux/x86 port of Oberon System 3] In practice this is plenty fast enough. I can provide a counter example as well. I wrote an implementation of SameGame once on a 90 MHz Pentium I. Initially, the model broadcast a separate update event for every change in board state. In SameGame large numbers of individual changes can result from a single move. The performance was not spectacular. At the time, I just had the model buffer and merge all the update messages resulting from a single move and then broadcast that merged update as a single message. Performance was excellent. The real performance problem in Oberon is of a different sort. Recall that there is no multitasking. There is one process. One thread. Not even coroutines. The procedure call is the indivisible unit of computation. This means that applications have to be quick about reacting to the messages. Even drawing the mouse cursor is delegated to the view over which the mouse happens to be located. Since you want fluid mouse movement, you can't hog the machine when reacting to messages. Oberon software was written with these limitations in mind, so they were rarely a problem in practice. For the user the experience was almost always one of a very repsonsive system. (Notable exception: when you downloaded software from the central file server to a Ceres-3 workstation, the entire gui would freeze for the duration of the file transfer -- thankfully the files were small.) The best solutions are ones that clearly define their goals and cut away everything that's not necessary to achieve those goals. With luck, such simplicity will later bring benefits not originally anticipated. (Misidentify your goals and things won't turn out so well.) ## Conclusion: Events/Messages Approaches like Swing rquire a lot of glue because: - You are required to *know* which senders you are interested in listening to. - You must know where to find these senders. - You are required to register for every Message x Sender combination that you might be interested in. - You must uregister yourself from all your Message x Sender subscriptions when you're closed so that you don't hang in memory forever just because you're on someone's listener list. The final point is particularly ugly because it defeats automatic resource management (garbage collection). Listeners effectively become unmanged resources for which must be explicitly closed(). This is just another form of the malloc/free problem. It is difficult, in an extensible system to determine who is responsible for disposing of such a resource and when it should occur. It's much more pleasant when objects can just take a ubiquitous message feed for granted, react to what interests them and ignore the rest. This won't be an acceptable solution in all cases. (I wouldn't advocate it over a network.) It sure is nice when it *is* a suitable approach. // Ben Smith-Mannschott ---- # Excerpts from *The Oberon Companion* *The Oberon Companion* **Copyright 1997-1998 by André Fischer and Johannes L. Marais** ## 5.5 The Display Space In earlier chapters, the display space was introduced. In essence, the display space is a data structure containing visual and non-visual objects. The visual objects, called frames, are the gadgets such as documents, Buttons, Scrollbars, etc. you see on the display. The non-visual objects are the model gadgets linked to these gadgets. We should emphasize here the abstract nature of the display space we are referring to. The display space should not be confused with the geometrical space of the display screen. To understand the display space, we have to discuss the nature of the single elements of the display space, and the nature of the connections between them. ### The type hierarchy. Before going into detail about the structure of the display space, we first investigate the type hierarchy of the visual and non-visual objects. All visual objects are extensions of the type Display.Frame. In turn, each frame is an extension of a more basic type called Objects.Object. The non-visual objects are also extensions of Objects.Object, but not of Display.Frame. ![Figure 5.2 The Object type hierarchy](Fig5.2.png) The lines of Figure 5.2 show the type extension relationship between objects. To simplify the programming of gadgets, two further base types form the basis of the visual and model gadgets. These two types, Gadgets.Frame and Gadgets.Object are extensions of Display.Frame and Objects.Object respectively. Thus when programming gadgets, we are faced with the type hierarchy depicted in Figure 5.3. ![Figure 5.3 Base system / Gadgets system relationship](Fig5.3.png) The double horizontal line of Figure 5.3 signifies a split between the base system and the Gadgets system. There is a good reason for emphasizing this split. The base system provides the mininum for implementing a framework of components. The Gadgets system "fills in" part of the functionality in this framework, that is, it adds rules and user interface conventions. Theoretically, we can imagine yet another type of user interface system built on the same base but implementing a different type of user interface framework. In fact, the textual user interface of the Oberon system is such a framework which existed before the development of the Gadgets system. This also illustrates that such a dichotomy turns out useful for guaranteeing compatibility with older applications, as both gadgets-enabled and older applications are different aspects of the same underlying object model. Before continuing with the display space structure, it is informative to show the type definitions of Objects.Object and Display.Frame, although the meaning of several of the RECORD fields is not obvious yet, and thus partially hidden: Handler = PROCEDURE (obj: Object; VAR M: ObjMsg); Object = POINTER TO ObjDesc; ObjDesc = RECORD ... some more fields ... handle: Handler (* Message handler. *) END; Frame = POINTER TO FrameDesc; FrameDesc = RECORD (Objects.ObjDesc ) next, dsc: Frame; X, Y, W, H: INTEGER END; The definition of Object reveals that each object has a message handler, which is responsible for interpreting the messages that are sent to it. Furthermore, we see that frames are type extensions of objects with the additional fields next, dsc, X, Y, W and H, which are described in the next paragraph. ### The Display space structure. Frames have a location and a size: the record fields F.X and F.Y contain the position of the frame F, and the record fields F.W and F.H its width and height. When a frame is located in the display space, it is always nested in another frame. The situation can be clarified in the following way, but for the sake of simplicity we shall confine the description to the tiled display space model used by the textual interface. The display itself is a large (imaginary) frame that covers the whole display surface. It has the location (0, 0) and size (Display.Width and Display.Height). (By the way, the origin of the Oberon display is in the bottom left corner, in contrast to many other systems.) This "root" frame is divided into two tracks, the user and the system tracks. Each track is a frame nested or contained in the root frame. The tracks are further divided into viewers, which are frames too (nested in their respective tracks). Each viewer is divided into two further frames, the menu bar frame and the main frame. The main frame might for instance contain a text editor frame. Inside this text editor frame we have the text itself, and possibly further frames signifying the visual objects that "float" in the text. These frames might contain further frames, and so on to any nesting depth. ![Figure 5.4 Example structure of the display space](Fig5.4.png) The nested nature of the display space is extremely important in the system and should be well understood. Figure 5.4 gives a diagrammatic view of the situation. Frames containing other frames as children are called container gadgets. Frames not containing any further frames are elementary gadgets. Each parent frame is completely responsible for its direct descendant frames and thus indirectly responsible for its indirect descendants. By convention, the "nested" structure of the display space is defined by the two fields dsc and next of Display.Frame. The dsc field of a container points to the first child of that container, and is the start of a list of direct descendants linked by the next field. The following code fragment shows how the children of a container F are traversed: PROCEDURE Traverse (F: Display.Frame); VAR f: Display.Frame; BEGIN f := F.dsc; WHILE f # NIL DO ... do something with f ... f := f.next END END Traverse; **Remark.** The property of parental control dictates which of these fields a frame may modify when receiving a message. A frame F is allowed to change its own F.dsc record field and the next fields of its direct descendants. But a frame should never change its own next field. This property also requires that you should never interfere with the dsc-next list of a container; although visible to the outside world, it is under complete control of the container itself. Later, we explain how external influences can be applied to containers. A further complication of the display space is the location of model gadgets. We already know that frames can possibly have a model linked to them. The visual gadgets, for example, reserve a field called obj to refer to a model gadget. As many frames can refer to the same model object, the use of these fields "close" the structure of the display space at the bottom (Figure 5.5). The general structure of the display space is that of a directed acyclic graph (DAG). In this Figure we have a Panel floating in two TextGadgets: the Panel containing a Button and a CheckBox both linked to a Boolean model. ![Figure 5.5 Display space with model objects](Fig5.5.png) In our previous explanation, we mentioned that the location of a frame F in the display space is determined by the record fields F.X and F.Y. We have to specify exactly what this means in the context of the display space. By convention, F.X and F.Y are the relative coordinates of a frame in its parent (i.e. container) frame. As the Figure 5.6 illustrates, the X and Y fields of a frame measure the offset of its bottom-left corner relative to the top-left corner of its parent frame. Since the Oberon display origin is in the left bottom corner of the display, the Y offset of a gadget is always a negative number. This setup provides the best efficiency when calculating the coordinates of a gadget. ![Figure 5.6 Frame coordinate system](Fig5.6.png) We should mention that a parent frame clips away those parts of its children which lie outside the rectangle of the parent. The relative coordinates of a frame in a container allow us to move that container and all its descendants directly by modifying only the relative coordinates of the parent in its own container. ## 5.6 Messages and Broadcasting Now that the structure of the display space has been presented in detail, we can discuss how objects (everything extended from Objects.Object) communicate with each other in the display space. Recall that every object in the Oberon system has a message handler, responsible for "handling" the messages sent to that object. There exists a large number of message types. For example, there are messages to request an object to make a copy of itself, to store itself to a file, to display or print itself, and so on. However, not every message is applicable to all objects. For example, model gadgets, that is, non-visual objects, do not understand a "display yourself" message. Messages are divided into classes. For the moment, we mention two important ones: object messages and frame messages. Object messages are those messages that all objects must respond to. This class consists of a very small collection of messages like "copy yourself", "store yourself" and so on. Frame messages are those messages that frames respond to. That class includes ones like "display yourself, "print yourself" and "move your position". Objects might not understand some of the messages sent to them. Why would we send a message to an object if it does not understand it anyway? The answer lies in the display space. Let us take the example of multiple text documents showing the same text (evoked in Example5). We already know that when we change the contents of a text (using module Texts), each text document displaying it is magically updated. Behind the scenes this is solved by a special message protocol between the text document (a view) and the text object (a model). This protocol is "special" in that only text documents and text objects are aware of it; they are "insiders", so to say. ### Model-view consistency Let us trace what happens when a character is inserted into a text or more correctly from a programming standpoint, when a text buffer is inserted into a text. The user of module Texts does this with a call to Texts.Insert. Behind the scenes, Texts.Insert has to inform all the text documents displaying the text that a change has taken place. Now, by convention, texts do not know what text document(s) they are attached to. The only possibility left open to the text is to broadcast a "text T has changed" message to all objects in the display space. Since text documents are listening to messages of the type "text T has changed" (where T is the text they are linked to), they can update themselves when this broadcast message is received. The broadcast functions in the following manner. First, the message is sent to the display root. As the root does not understand the message (because it knows nothing about texts), the only logical thing it can do is to forward the message to the tracks it contains, in the hope that these can have something to do with the message. However, the tracks are just as clueless, and are forced to forward the message to the viewers they contain. The same thing happens again, so each viewer forwards the message to its (two) sub-frames. The message thus travels through the entire display space in a depth-first way. Luckily, the text documents located in the display space understand the message, and can update the display with the character typed (which is specified in the message by indicating the part of the text that has changed). This is the general scheme Oberon uses to inform views that a model has changed. If no view is interested in the model that has changed, the message travels through the whole display space without effect. ### Types of broadcast. In reality, there are two types of broadcasts: true broadcast and directed broadcast. True broadcasts reach all frames in the display space. Directed broadcasts are addressed to a certain destination frame in the display space. This might sound a little paradoxical. Why do we need to broadcast a message into the display space if we know the frame that should receive it? Why not simply send the message directly to the intended frame (without going through the display root, tracks, viewers etc)? Although several reasons exist (one of them related to the Oberon display model), only one reason will be mentioned here. As messages travel in the display space from the root frame to track, to viewer, and so on, at any point a container frame can make a decision if it wants to handle, ignore, change or forward a message. Thus a frame can influence the messages its descendants "see". This is again the all important property of parental control. Should a parent frame not control the message a child frame sees, the child might "misbehave". Parental control might force a child frame to move itself only in a restricted way in a container; or prevent a child frame from deleting itself. ### Terminating a broadcast. Under certain circumstances, it is necessary to terminate a broadcast early. This is typically the case when it is known that no further frame could have an interest in the message. Thus, Oberon provides a way to invalidate a message. An invalidated message is not forwarded by containers, thus terminating the broadcast abruptly. ---- END of Excerpt. The Oberon Companion Copyright 1997-1998 by André Fischer and Johannes L. Marais ---- # Some Additional Background on Oberon But Oberon really is very different from something like Linux or Windows. It's even far simpler than the classic SmallTalk and Cedar/Mesa Systems from Xerox Parc. (The Mesa/Cedar work at Xerox PARC was an influence in Wirth in his design of Oberon.) Anyone with a Unix background would be hard-pressed to even acknowledge Oberon as an *operating system*, but the fact is that it performed well at it's primary task: a simple, cheap single-user system for programming in small, clean, garbage collected, statically typed language. It also is a pretty good environment for writing and for simple graphics. - In an Oberon system, there is only a single process with a single thread. - This thread runs the procedure Oberon.Loop(), which broadcasts mouse, keyboard and other events to all windows. - Sending a message is nothing more than a normal procedure call in which the message record itself is passed *by reference* to the called procedure. (The message itself is allocated on the stack, not the heap.) - The handler procedure (in MVC this is the "controller") of each window (Display.Frame, actually) reacts to events it's interested in, generally by mutating the model it's displaying in some way. - This generally causes the model to broadcast an update message, which viewers displaying that model will react to by updating their display. - When these procedure calls have all returned, control is back in Loop() - Loop periodically calls the garbage collector and calls background tasks, giving them a chance to do a little work and return. - Views are responsible for forwarding (or not) events to their subviews. (In Oberon this is the 'principle of parental control' and is an important element in the design of the system.) Thanks to Oberon's simplicity it was later ported to run on top of a wide variety of more conventional operating systems. (I've used it on top of Ultrix (MIPS), Solaris (SPARC), MacOS (68020+ and PPC), Mac OS X (Intel) and Windows (3.1, NT, 2000, XP). I've also run it as the native OS on a ThinkPad T20 and I have it a Linux hosted port on my Netbook as I write this. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "The Java Posse" group. To post to this group, send email to javaposse@googlegroups.com To unsubscribe from this group, send email to javaposse+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/javaposse?hl=en -~----------~----~----~----~------~----~------~--~---
<<attachment: Fig5.2.png>>
<<attachment: Fig5.3.png>>
<<attachment: Fig5.4.png>>
<<attachment: Fig5.5.png>>
<<attachment: Fig5.6.png>>