TweetFollow Us on Twitter

Object Pascal
Volume Number:2
Issue Number:12
Column Tag:Pascal Procedures

Introduction to Object Pascal

By Ken Doyle, Apple Computer, Inc.

Introduction

If you have been reading about MacApp, you may be wondering if you have to have the Macintosh Programmer's Workshop (MPW) and if MacApp programs must be written in Object Pascal. The answer is yes, for now. For those of you who like some of the other Pascal compilers out there, or prefer to program in another language such as C, you are currently out of luck. The reason is two-fold. Most languages for the Macintosh do not support the object-oriented concepts upon which MacApp so heavily relies, and even if they do, they don't use the same run-time scheme that Object Pascal does.

In this article I will first present a description of the syntax of Object Pascal and comment on some of the semantics involved in using the syntax. I will discuss the various degrees of compatibility that another language or compiler needs to achieve in order to make use of MacApp and what steps are necessary in meeting that goal. In particular, the exact format of the generated code and the run-time routines that deal with that code will be shown. I will talk a bit about how we added objects to MPW's Assembly language. Finally I present a scheme for optimizing what we've already learned.

Object Pascal

Object Pascal is an extension to the Pascal language that was developed at Apple in consultation with Niklaus Wirth, the inventor of Pascal. It is descended from an earlier attempt at an object-oriented version of Pascal called Clascal, which was available on the Lisa computer. MacApp itself is descended from the Lisa Toolkit, an application framework for creating Lisa applications. The Lisa Toolkit was written in Clascal.

There are actually very few syntactic additions to Pascal in Object Pascal. A new data type is added, the object. An object is very much like a record in that it can have multiple data fields of arbitrary types. In addition, you can specify a list of procedures and functions, referred to as methods, for a particular object type. These methods define the actions that an object of this type can perform. For example, you could define a Shape object type as follows:

 type 
 Shape = object
 bounds:Rect;
 color: Pattern;
 procedure Draw;
 procedure Erase;
 procedure Rotate(angle: integer);
 procedure Move(delta: Point);
 function Area: integer;
 end;

Furthermore, you can define an object type that inherits the fields and methods of another object type. The new type can define additional fields and methods and can choose to selectively override methods that it has inherited.

 type
 Circle = object(Shape)
 radius: integer;
 procedure Draw; override;
 function Area: integer; override;
 procedure SetRadius(newRadius: integer);
 end;

 var aCircle: Circle;

An object type is often referred to as a class. In the above example, Circle is a subclass of Shape. Shape is the superclass of Circle. A class (object type) can have many subclasses (descendants), but only one superclass (immediate ancestor). When speaking of the relationships conceptually , I will more often use the class terminology. When speaking in terms of Pascal data types I use the object type terms.

Objects are created by calling the Pascal built-in procedure New on a variable of an object type. You say New(aCircle) to create an instance of the object type Circle. The New procedure, when used with an object type variable allocates sufficient storage on the heap for the object and sets the value of the variable to be a handle (pointer to a pointer) to that data. The double arrow normally required for handle dereferencing is done automatically by the compiler, so fields are accessed directly, eg: aCircle.bounds, NOT aCircle^^.bounds. Likewise, to invoke a method you use the same notation: aCircle.Draw invokes the Draw method of the Circle object type, presumably drawing itself on some display. Since all object type variables are actually handles to the data, an assignment such as shape1 := shape2 causes shape1 to point to the same data as shape2.

The fields of an object can themselves be references to other objects. For example you could have a nextShape field in the Shape definition if you wanted to have a linked list of shapes. Object Pascal allows you to specify the type of a field to be a reference to an object type not yet declared. In this manner, you can have circular references of object types to one another. If the compiler encounters an undeclared type identifier, it assumes it is an object type that will be declared later. If the type is not declared later, an error will be reported. The size of the not yet declared object is unimportant since the reference to it is always just a four byte handle.

The depth to which an object type can inherit is unlimited. You could define a descendant of Circle and another descendant of that type and so on. Each succeeding descendant inherits all of the fields and methods of all of its ancestors.

Figure 1.

Object Pascal requires that the object type definitions be at the highest level in a unit or program, always as a type declaration. For a unit this can be either in the interface or the implementation part. The body or actual code for the methods appears in the procedure and function part of the unit or program. If the body of a declared method does not appear in the file, the compiler issues a "method not implemented" error. The body of a method is just like that of any procedure or function:

 procedure Shape.Erase;
 begin
 EraseRect(bounds);
 end;

 procedure Circle.Draw;
 begin
 FillOval(bounds, color);
 FrameOval(bounds);
 end;

There are several things to note in these two examples. The name of the method is given as TypeName.MethodName to distinguish which method is being defined. When inside a method, there is always an implicit parameter called SELF. SELF refers to the object that invoked the method. The fields of the object could be accessed as SELF.bounds or SELF.color, however the compiler provides an implicit "with SELF do" block around the method making the field names directly accessible. Similarly, you could invoke another method from within a method by saying SELF.OtherMethod but again just OtherMethod is sufficient. This obviates the need for SELF other than when one wishes to pass the object itself to another routine, eg: AddMeToList(SELF). For the statement aCircle.Draw, since aCircle is of type Circle, the Circle.Draw method would be called rather than the Shape.Draw method. In addition, if the aCircle.Erase is called, since Circle did not override the Erase method, the Shape.Erase method would be invoked. This is fairly straightforward. Slightly less obvious behavior occurs if the following code is executed:

 var aShape: Shape;
  aCircle: Circle;

 New(aCircle);
 aCircle.bounds := someRect;
 aCircle.color := white;
 aCircle.radius := 60;
 aShape := aCircle;
 aShape.Draw;

When aShape.Draw is executed, which method is called: Shape.Draw or Circle.Draw? Even though aShape is declared as a Shape, the assignment to aCircle causes it to be a Circle object and thus Circle.Draw would be the method called. This is accomplished by means of a two byte type identifier at the beginning of every object (see Figure 1). This raises some important points. The assignment aShape := aCircle is "safe" because any fields or methods accessed for a Shape object will be valid for a Circle object. But the reverse assignment aCircle := aShape is not safe since the additional fields or methods in Circle will not necessarily be understood by a Shape object. For example, if we later tried to invoke aCircle.SetRadius it would not be understood had aShape been a regular Shape object. (In fact, the aShape variable could have referred to an entirely different descendant of Shape, say Triangle, which also would not understand any Circle-specific methods calls or field accesses.) The compiler issues an error message if such an assignment is attempted. If you are absolutely sure that in this case the Shape variable is guaranteed to be pointing to a Circle object, you can use coercion to override the compiler: aCircle := Circle(aShape). Even then, at run time, if range checking is turned on, the assignment will be checked to make sure it is valid.

The point to remember from this is that even though a variable is declared to be of a particular object type, at run time, its actual type may be that type or any descendant of that type. It is by this means that one could have a list if "shapes" that could each be told to "draw", where the actual types are a mixed collection of circles, squares, triangles, and so forth. As a result, the determination of which actual method to call must be made at run time. This is accomplished using a "method dispatch routine" that looks at the two byte type field of the object and uses tables of method locations to direct the call to the proper method. Method dispatching will be discussed in more detail later.

A final syntactic addition to Pascal is the inherited keyword. If you have overridden a method to add some code specific to your object type but still want to use the code in the overridden method, you would use the word inherited followed by the method name:

 procedure MyController.ProcessKeystroke(ch: char);
 begin
 if ch = 'X' then
 DoSomethingSpecial
 else
 inherited ProcessKeystroke(ch);
 end;
 

Assuming Controller was the immediate ancestor of MyController, the inherited call would be a call to Controller.ProcessKeystroke (given that the method exists). In the case of inherited, the proper method to call can always be determined at compile time -- there is no need for a run time method dispatch. The call is always to the closest ancestor that implemented the method. Realize that this does not necessarily mean the immediate ancestor. If the immediate ancestor did not implement the method but an ancestor further up in the hierarchy did, the call would be to that method. By using the inherited keyword rather than explicitly naming an ancestor (superclass) object type, you are insulated from possible future changes that might insert or delete an implementation of the method in an ancestor or superclass. The compiler will issue an error message if inherited is used in a method that was not inherited from an ancestor object type.

Object Pascal also provides the built-in function Member. You can use Member to test if a particular object is in a certain class. For example you could say:

 if Member(aShape, Circle) then
 numCircles := numCircles+1;

 

Member returns true if the object's type is the same type or a descendant of the object type being tested. In the example above, numCircles would be bumped for ordinary circles and any specialized subclasses of Circle, but not for Squares, Triangles, or ordinary Shapes. The use of the Member function is somewhat contrary to the principles of object-oriented programming (you're not supposed to peek at your own type) so its use is generally discouraged except in unusual circumstances.

Since all object references are stored as handles to the object data on the heap, there are a couple of Pascal constructs that are unsafe to use on fields of an object. One is the use of a field as a VAR parameter in a procedure call. The Pascal compiler pushes the address of a VAR parameter on the stack. If the heap were to compact while processing the procedure, the address of the field of the object could become invalid. Another situation where the compiler computes an absolute address is if you use the with statement on an object field that is a record type, eg: "with aCircle.bounds do". If some statement in the with block caused a compaction, the computed address could become invalid. The compiler issues warnings when such a usage is detected. If you are sure the procedure or with statement will not compact the heap, you can precede the statement with the {$H-} compiler option. This tells the compiler not to issue the warning. You should follow the statement with {$H+} to turn heap warnings back on.

Levels of Compatibility

If you are a compiler writer who wants to use MacApp, there are a variety of levels of compatibility you can strive to achieve. The degree of compatibility can fall into the conceptual, the source file, or the object file level. (Note: The term object is used in two completely different contexts in this article. One use is with object-oriented phrases such as object type or an object on the heap. The second use is when speaking of the object file format, which is the term used for the structure of a file generated by a compiler.) To be conceptually compatible, the language must support the object-oriented concepts of object type definitions, inheritance, and method calls. Source file compatibility is a special case that only applies to Pascal compilers. The Pascal compiler would have to support all of the extensions to Pascal that the Macintosh Workshop Pascal supports, which in addition to the object-oriented extensions, includes such features as separately compiled units, expressions in constant declarations, and numerous compile time options such as conditional compilation. Finally, languages that are object file compatible would use the same object file format, namely that defined in the appendix of the MPW reference manual, and furthermore would support the specific method calling conventions and method table formats that Object Pascal generates.

If a language supports the object-oriented concepts of Object Pascal and if the programming structures of the language resemble the structures of Pascal, it should be fairly simple to write a program to do an automatic translation of MacApp into the desired language. For known constructs that are not automatically translatable, the program would flag that code for hand translation. The compiler writer could then distribute either the translated source or the compiled object form of MacApp, subject, of course, to whatever legal mumbo jumbo is required from Apple to redistribute MacApp. For compilers that do not use the MPW object file format, some variation of this will be the only alternative for those who want to use MacApp.

Pascal compilers that add the extensions of Macintosh Workshop Pascal can directly compile the MacApp sources themselves. If your compiler supports most but not all of the extensions, you may be able to modify the MacApp source files to not use the unsupported features. The object-oriented extensions would, of course, have to be supported.

Compilers that generate code using the MPW object file format and use the Object Pascal method table and method calling schemes will be able to link directly with compiled MacApp files. They will be able to link with Object Pascal building block files such as the Text and Dialog Box units.

Currently, most compilers do not support the MPW object file format. Hence, the only option available is that of translating MacApp into their particular language (which may be a trivial or null translation in the case of Object Pascal compatible compilers). If you as a compiler writer are not religiously (or pragmatically) devoted to your particular object file format, I would encourage you to consider using that of MPW. In any event, the discussion of our particular method table organization and method dispatching scheme that follows should be useful if you are considering adding object-oriented features to your language, even if you decide to implement your language in a completely different way.

Object File Format

As mentioned before, Apple's Object Pascal compiler generates files using the MPW object file format. The structure of the file consists of a collection of varying length records. There are eleven different kinds of records. The important ones for our purposes are the module, contents, and reference records. The module record specifies a new code or data module. Each procedure or function is represented by a code module. It is generally followed by one or more reference and/or contents records. The reference records specify what external modules are referenced from the current module. The contents records contain the actual code of the routine. The linker uses the reference and module records to patch branches and other instructions that have external references.

The Class Info Proc

When an object type is defined, a phony code module is generated. This code module is known as the "Class Info Proc". It contains information on who the ancestor is, what the size of an object of this type will be, and how many methods are implemented by this type. This is followed by the actual method table. This module is never actually called. It is placed in a special segment named %_MethTables with all other class info proc's. This segment also contains a very short routine called %_RTS1. The code for it is simply an RTS instruction. At application startup, %RTS1 is called, which loads the segment with all of the method tables.

The Method Call

Before I talk about the format of the method table itself, we need to understand how a method call works. Consider the following method call:

 aShape.Move(dist);

Method calls in Object Pascal naturally use Pascal calling conventions. First the parameters are pushed onto the stack (in the order they appear in the procedure declaration), then a JSR (Jump to Subroutine) call is made. Recall that in a method, there is always the implicit parameter SELF. This is pushed onto the stack after the actual parameters of the method. The object code for the method call above will look somewhat like this:

 MOVE.L dist,-(SP)
 MOVE.L aShape,-(SP)
 JSR    ??

Where does the JSR jump to? Since the actual method to call is dependent on the run time type of aShape, we cannot put a direct JSR to Shape.Move. At run time, aShape could be a Circle, Square, or some descendent not even known when this code was compiled. We need to go through a dispatch mechanism that examines the object to determine its type and then call the appropriate method based on that type. But so far, looking at the code above, we haven't even indicated what method we want to call. Most object-oriented languages use the selector technique to indicate to the dispatching routine what method is being called. A selector is some unique identifier for a particular method name. Often the selector is simply the name of the method itself. This, however can be expensive in terms of space required. Furthermore, Object Pascal allows methods in unrelated branches of the object hierarchy to have the same name with completely different parameter lists. The compiler treats these as totally separate method definitions. Simply using the method name for the selector would be ambiguous.

The Selector Proc

The question remains: how do we generate a unique selector for each method name? We let the linker do it! The linker, in resolving cross segment references, patches JSR's by having them branch into a jump table that then jumps to the correct routine. When segments are unloaded and reloaded in memory, the jump table entries are updated appropriately. The jump table is stored near an address pointed to by register A5. All JSR's into the jump table are of the form JSR x(A5) where x is some offset into the jump table. It is this offset x that the linker generates that we use as the method selector. As each new method name is encountered during the compilation of an object type definition, a very short procedure is generated. This procedure is referred to as the "selector proc". Its name is of the form TypeName$MethodName, such as Shape$Move. Note that the selector proc is not generated for method overrides, only when the method definition is first encountered. Methods by the same name in an unrelated branch of the hierarchy would have a selector proc, for example Employee$Move. The contents of the selector proc is simply a JSR to the actual method dispatching routine, called %_Method.

It is to the appropriate selector proc that all method calls are directed. The JSR instruction above would therefore be JSR Shape$Move. All selector procs are placed in another special segment, "%_SelProcs". All references to it are guaranteed to be through the jump table. The critical significance of this is that when the JSR is patched by the linker, the two-byte offset into the jump table is unique for that method name. The method dispatch routine examines those bytes and matches them against values stored in the method tables to determine what method is being called. Which brings us back to the format of the method tables.

Method Table Format

As mentioned above the method table for a particular object type appears at the end of the class info proc. The table is simply a list of pairs of references, one pair for each method implemented by this type. The first reference in each pair is to the selector proc and the second is to the actual method implementation. Each of these references are guaranteed to be across segments. Normally, when the linker is resolving a cross segment reference, it not only patches the offset bytes of the instruction, it also sets the bits in the instruction itself to make it A5 relative. For the method tables, there are no JSR's, just offsets that need to be patched. Fortunately there is a special bit (the A5-relative flag) in the reference record to tell the linker not to attempt to edit the word before the offset location.

Objects on the Heap and the New Routine

Objects are created using the New procedure. The compiler detects whether the parameter is an object type variable. It calls a quite different procedure than the normal New for pointer types. This procedure, %_OBNEW, allocates the data on the application heap. (Normal pointer New calls get data allocated on a special Pascal Heap.) %_OBNEW must also set the two byte class identifier field for the object. Like almost every other two byte field we've seen so far, this is an A5 offset into the jump table. This time the reference is to the class info proc of the class of the parameter to New. The actual calling sequence for New(aCircle) is:

 PEA    aCircle
 PEA    Circle's Class Info Proc + 2
 MOVE.W #size of instance,-(SP)
 JSR    %_OBNEW

The "+ 2" for the class info proc is somewhat of a hack. The jump table entry for the class info proc is JMP x where x is the address of the class info proc. We don't want to execute the code there, we just want to look at the information in it. By bumping the pointer by two we are in effect creating a handle to the class info proc, where the master pointer is the address stored after the JMP instruction in the jump table. %_OBNEW calls a routine %_SetClassIndex that subtracts A5 from this "handle" and stuffs the result into the two byte type identifier field. When a method is called, %_Method adds A5 back to the two byte field of the object, thus reconstructing the handle to the class info proc.

Figure 2.

The Method Dispatch Routine

In Figures 2 and 3 we see how a typical method call works. As we saw before, the parameters of the method, if any, are pushed onto the stack followed by the handle to the object itself. We then do a JSR to the selector proc, in this case Shape$Rotate. Shape$Rotate, like all selector procs, is simply a JSR to %_Method, the dispatch routine. In the method dispatch routine we first grab the handle to the object from the stack. We then extract the class identifier bytes from the object header. Adding A5 to these bytes gives us a handle to Circle's class info proc. The method "selector" is the two offset bytes after the JSR instruction to the selector proc. We search through the method table in the class info proc for a match to this selector. Since Rotate is not overridden in Circle, we do not find a match in this table. We then find the class info proc of the superclass, namely that of Shape. We go through the same search for the method selector and this time we do find a match for Rotate. We then jump to the proper routine, Shape.Rotate.

Figure 3.

Type Checking

Previously I mentioned that if you use type coercion to do an assignment of one object type variable to another, a run time check would be generated. The check is to see if the type of the object being assigned is the same type or a descendant type of the variable on the left side of the assignment. This is the same check that is made when you call the Member function. The routine that does this is called %_OBCHK. It takes two parameters, a handle to the object and a pointer to the jump table entry of the class info proc for the class whose membership is being tested. %_OBCHK returns the object handle if the test succeeds and nil if it fails. It calls the routine boolean routine %_InObj to do the actual test.

The information presented thus far should be sufficient for someone to implement object-oriented features in their language. The following discussion of "Object Assembler" is an example of how we took another "language" and generated the same method table formats and so forth to create an object file compatible alternative to programming exclusively in Object Pascal.

Object Assembler

Despite the many advantages of using a higher level language, we wanted to be able to escape to assembly language when necessary to efficiently code-time critical parts of an application. Using the powerful macro language available with the MPW 68000 Assembler, I was able to write a set of macros that allows one to define a class, implement and call methods, and create new objects, all in 68000 assembly language.

For example, the Shape and Circle definitions we saw in Pascal would look like:

 ObjectDefShape,,\
 (bounds,8),\
 (color,2), \
   METHODS, \
 (Draw),\
 (Erase), \
 (Rotate),\
 (Move),\
 (Area)

 ObjectDefCircle,Shape,   \
 (radius,2),\
   METHODS, \
 (Draw,OVERRIDE),\
 (Area,OVERRIDE),\
 (SetRadius)

(The '\' character is required by the Assembler when continuing a line)

The ObjectDef macro actually generates the class info proc and selector procs as specified earlier. It also sets up data structures for allowing field accesses and method calls later in the code. A method is defined as follows:

 Erase: ProcMethOf Shape
 LINK   #0,A6
 MoveSelf A0
 MOVE.L (A0),A0
 PEA    bounds(A0)
 _EraseRect
 UNLK   A6
 MOVE.L (SP),(SP)+
 RTS
 EndMethod

The ProcMethOf macro (and the FuncMethOf macro) invoke another macro, ObjectWith, that allows field references like bounds(A0) to work properly. MoveSelf is a simple macro that gets SELF off of the stack. It assumes that you started the method with a LINK A6. The routine above loads SELF into A0, dereferences it, and pushes the bounds field onto the stack so that EraseRect can be called. After the Unlink, the stack is fixed up by stuffing the return address on top of the single parameter, SELF, and the method returns.

Method calls are made using the MethCall macro:

 MoveSelf -(SP)
 MethCall Draw,Shape

MethCall generates a JSR to the proper Selector proc for Draw. If the call was made from inside of a method of Shape or a subclass of Shape, the parameter Shape could have been omitted. The other important macros are Inherited and NewObject:

 MoveSelf -(SP)
 InheritedDraw

 NewObject10(A6),Circle

Inherited behaves as in Object Pascal. NewObject requires a memory reference parameter and a type name. The handle of the new object is stored into the memory location specified by the parameter.

A full description of the macros available is contained in both the MPW Assembler Manual and the MacApp Reference Guide. Since these macros generate the same code that Object Pascal does, any code written in "Object Assembly" language can be linked with MacApp object files. In fact, specific methods in Object Pascal can be declared external and coded in assembly language using the macros. In addition, the assembled files can be run through the Optimizer described in the next section.

The Optimizer and the New Run Time Environment

In running sample applications written in MacApp, the performance has been quite good, despite the fact that every method call must go through the method dispatch mechanism before being executed. However, we realized that some significant optimizations were possible once the entire object type hierarchy was known. We have developed an optimizer program that processes the object files just before they are linked. It builds an internal representation of the entire object type hierarchy and proceeds to analyze it for potential optimizations.

Treatment of Monomorphic Methods

The most significant savings arises from being able to identify those methods that are implemented in only one object type, in other words, methods that are never overridden. Since these "monomorphic" methods have only one implementation, there is no need for a call to them to go through method dispatching. The Optimizer reroutes calls to these methods to jump directly to the method. Recall that originally the call was to a "selector proc" that in turn called the method dispatch routine. Not only does this increase the speed dramatically for these method calls but the space required is reduced. There no longer needs to be a selector proc nor the jump table entry that pointed to it. Also the entry in the method table for that method can be eliminated.

We have found that approximately 75% of the methods defined in MacApp applications are monomorphic. These include many internal methods of the MacApp classes themselves. For any "leaf" object type, one that has no descendants, any new method it defines will be monomorphic.

Transposition of the Method Tables for Polymorphic Methods

For the remaining "polymorphic" methods, those methods that are implemented by more than one class, the now reduced method tables are transposed. That is, where before each method table was a list of the methods implemented by a particular class, now each table is a list of classes that implement a particular method. This results in more tables of shorter length. Previously the method tables were stored in the class info procs. Now the tables are stored in the selector procs. In fact, they are stored immediately after the JSR instruction that jumps to the method dispatch routine. Thus the address of the method table is on the top of the stack when the dispatch routine is entered.

The form of this new method table is a list of two byte pairs. The first element in the pair is a class number that is generated by the optimizer. The second element is a reference to the actual implementation of the method, which the linker has patched with an A5 offset into the jump table. (This element is unchanged from the previous method table format.) The class number of a particular class is always greater than that of its superclass. The entries in the method table are sorted in descending order of class number. By numbering the classes in this way and keeping a separate table of superclasses, the method dispatch routine can properly search the method table. A Class number is always an even positive integer, making accesses to the superclass table simpler. A handle to the superclass table is stored in a low memory location.

The New Object Header

In the optimized run time environment objects have a different two byte class identifier than before. The A5 offset to the jump table entry of the class info proc is replaced by the class number that was generated by the optimizer. The class info proc no longer contains the method tables or a reference to the superclass. In fact it has just a single two byte entry, namely the class number. The calling sequence to %_OBNEW is the same as before, but the Optimizer actually redirects the %_SetClassIndex call in %_OBNEW to instead call %_OptSetCI. %_OptSetCI gets the class number from the class info proc and stuffs it into the object header.

The New Method Dispatch Routine

The new method table format requires a new method dispatching scheme. In fact, this is the scheme used by the method dispatch routine in the 128K ROM. The routine is also available in the libraries for 64K ROM machines.

A somewhat complicated algorithm is used to check only those methods that belong to the hierarchy of the object processing the method. For example, following the example in Figures 4 and 5, if aShape.Rotate was called and aShape was currently a Circle object the search would proceed as follows. First check to see if the most recent search was for a Circle by checking the cache at the beginning of the table. If we get a match, we jump immediately to the method (via the cached jump table offset). If we don't get a match, then check each entry in the table until we do get a match OR we arrive at a class number that is less than the current number. Since the current number is 8, we will skip the 10 (square.rotate) and stop at 6 (triangle.rotate). If we match, we jump to the method. It isn't a match, so now we look up Circle's superclass in the superclass table. The superclass is 4 (shape), and we proceed as before searching for a match or a number less than the current number (now 4). The next entry is a 4 so we match. Before jumping to the method, we stuff the original class number 8 in the class number cache and the jump table offset for shape.rotate in the method cache. If the next call to Rotate is for a circle object we'll get an immediate hit in the cache.

Figure 4.

The Optimizer also redirects the %_InObj routine to %_OptInObj. This is the boolean function that tests object membership in a particular class. The new routine uses the class number of the object and the superclass table to test the object.

Figure 5.

Future Optimizations

Other optimizations are possible when the entire class hierarchy is known. Say a variable aCircle is declared to be of type Circle and furthermore that there is no descendant of Circle defined. Then any method call that aCircle makes can be resolved before run time. This is because any object type variable can only reference an object whose type is the declared class or a descendant of that class. Since Circle has no descendants we know that aCircle must be a Circle object. Therefore we know that if Draw is invoked, we should call Circle.Draw and if Erase is invoked we call Shape.Erase (since Circle did not implement Erase) and so on. This is a little more difficult to implement and has not yet been put into the Optimizer.

Supporting the MacApp Debugger

One of the most appealing features of MacApp is its powerful debugger. The debugger is independent of the object-orientedness of MacApp. When an application is compiled with debugging flags turned on, the MacApp debugger is installed in a separate window on the screen. At any time while running the application you can go into the debugger and look at the stack or see a recent history of procedure calls. You can examine objects on the heap and even set up intentional error conditions such as nil object handles. You can set break points at specific methods and you can step through the code a method at a time. There are many other useful features.

To support the debugger, the Object Pascal compiler inserts a call to a special routine called BP at the beginning of every routine. It also inserts a call to EP at the end of every routine and a call to EX for Exits or GOTO's that jump out of a routine. In addition, the name of each routine is appended after the code of the routine. BP, EP, and EX are implemented in the UTrace unit that comes with MacApp. If you want to support the MacApp debugger, you should look at how it works and see if you can tailor it to your particular language.

The C+- Language

We at Apple are anxious to see more compilers support object-oriented concepts and be able to make use of the several man-years of effort that went into developing MacApp. In particular we recognize the popularity of the C language and the proliferation of C compilers available on the Macintosh. Since the C compiler that comes with MPW was done by a third party and they were under considerable time pressure to deliver as it was, we were not able to get object-oriented features put into it.

In the meantime, however, we have come up with a recommended specification for an object-oriented C. It is based on the C++ language from Bell Labs. It is essentially a subset of C++ that includes just those features necessary to support MacApp. We call this language C+-. The specification is available as a technical report from the Apple Library. Of course, if you want to support the full C++ specification, you will still be compatible with C+-.

How to Get Help

If you do decide to use some of the information presented in this article in order to be able to use MacApp, contact Harvey Alcabes at Apple. Harvey is the Product Manager for MacApp and is coordinating third party efforts to add objects to their languages. He can advise you on any licensing requirements for distributing translated versions of MacApp and so forth.

References

Object Pascal Report, by Larry Tesler; Feb 22, 1985, published in Structured Language World, Volume 9, No 3.

The MacApp Programmers Reference Guide

C+- Specification, by Larry Tesler; May 26, 1986

Apple Technical Report #2

Object-Oriented Programming for the Macintosh, by Kurt Schmucker; 1986; Published by Hayden Press

 
AAPL
$524.75
Apple Inc.
-6.95
MSFT
$39.69
Microsoft Corpora
-0.30
GOOG
$526.94
Google Inc.
-7.87

MacTech Search:
Community Search:

Software Updates via MacUpdate

MacFamilyTree 7.1.6 - Create and explore...
MacFamilyTree gives genealogy a facelift: it's modern, interactive, incredibly fast, and easy to use. We're convinced that generations of chroniclers would have loved to trade in their genealogy... Read more
EtreCheck 1.9.9 - For troubleshooting yo...
EtreCheck is a simple little app to display the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support... Read more
TeamViewer 9.0.28116 - Establish remote...
TeamViewer gives you remote control of any computer or Mac over the Internet within seconds, or can be used for online meetings. Find out why more than 200 million users trust TeamViewer! Free for... Read more
Viber 4.1.0 - Send messages and make cal...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device,... Read more
Apple iOS 7.1.1 - The latest version of...
The latest version of iOS can be downloaded through iTunes. Apple iOS 7 brings an all-new design and all-new features. Simplicity Simplicity is often equated with minimalism. Yet true simplicity is... Read more
1Password 4.3 - Powerful password manage...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Lens Blur 1.3.0 - True out-of-focus boke...
Let Lens Blur transform your existing photo into true SLR-quality out-of-focus bokeh effect! Everyone needs a gorgeous personalized background for a social profile, blog, Web/UI design, presentation... Read more
VMware Fusion 6.0.3 - Run Windows apps a...
VMware Fusion allows you to create a Virtual Machine on your Mac and run Windows (including Windows 8.1) and Windows software on your Mac. Run your favorite Windows applications alongside Mac... Read more
BitTorrent Sync 1.3.93 - Sync files secu...
BitTorrent Sync allows you to sync unlimited files between your own devices, or share a folder with friends and family to automatically sync anything. File transfers are encrypted. Your information... Read more
Tweetbot 1.5.1 - Popular iOS twitter cli...
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more

Latest Forum Discussions

See All

Leo's Fortune (Games)
Leo's Fortune 1.0.2 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.2 (iTunes) Description: Leo’s Fortune is a platform adventure game where you hunt down the cunning and mysterious thief that stole your gold.... | Read more »
iOOTP Baseball 2014 Edition Review
iOOTP Baseball 2014 Edition Review By Carter Dotson on April 23rd, 2014 Our Rating: :: SOLID CONTRACTUniversal App - Designed for iPhone and iPad The long-running baseball simulator returns to mobile with a much-improved entry in... | Read more »
148Apps Live on Twitch: Soccer Rally 2 w...
Soccer Rally 2 from IceFlame Games officially releases on Thursday, bringing perhaps the most realistic car soccer action to the App Store since the original released. David Deacon of IceFlame Games will join us on our Twitch channel to talk about... | Read more »
NightCap Pro Review
NightCap Pro Review By Jennifer Allen on April 23rd, 2014 Our Rating: :: NIGHT TIME SNAPPINGUniversal App - Designed for iPhone and iPad Taking photos in low light conditions has always been tricky, but NightCap Pro has just made... | Read more »
Plague Inc. has Mutated Yet Again – We’r...
Plague Inc. has Mutated Yet Again – We’re All Doomed Even More than Usual Posted by Rob Rich on April 23rd, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Intake from Cipher Prime Coming to iPad...
Cipher Prime’s Inake is coming to iPad on May 1, as exclusively revealed yesterday on our Twitch channel. | Read more »
Gusto Email App Review
Gusto Email App Review By Jennifer Allen on April 23rd, 2014 Our Rating: :: POWERFUL SEARCHINGiPhone App - Designed for the iPhone, compatible with the iPad Focusing on making it easy to browse files and photos attached to your... | Read more »
New Update Adds Two More Cars to Fishlab...
New Update Adds Two More Cars to Fishlabs’ Sports Car Challenge 2 Posted by Rob Rich on April 23rd, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
What’s Up with Readdle? – The Verge Exam...
What’s Up with Readdle? | Read more »
Knight Saves Queen Review
Knight Saves Queen Review By Jennifer Allen on April 23rd, 2014 Our Rating: :: PUZZLING MASH UPUniversal App - Designed for iPhone and iPad Mixing up puzzle elements with Chess-based sensibilities is a fun move for this simplistic... | Read more »

Price Scanner via MacPrices.net

iPad Sales “Lull” A Reality Correction Of Unm...
I have lots of time for Jean-Louis Gassée, the former Apple Computer executive (1981 to 1990) who succeeded Steve Jobs as head of Macintosh development when the latter was dismissed in 1985. Mr.... Read more
Apple Makes OS X Betas Available To All – Wit...
Apple’s OS X Beta Seed Program, which lets you install the latest pre-release builds, try it out, and submit your feedback, is now open to anyone who wants to sign on rather than to developers and... Read more
Apple Releases iOS 7.1.1 Update
The latest iOS 7.1.1 update contains improvements, bug fixes and security updates, including: • Further improvements to Touch ID fingerprint recognition • Fixes a bug that could impact keyboard... Read more
Logitech Announces Thinner, Lighter, More Fle...
Logitech has announced an update to its Ultrathin for iPad Air, iPad mini and iPad mini with Retina display, improving the flexibility and design of its award-winning predecessor with an even thinner... Read more
Logitech Introduces Hinge, Big Bang and Turna...
Logitech has announced expansion of its tablet product line with three new cases – the Logitech Hinge, the Logitech Big Bang and the Logitech Turnaround – each for the iPad Air, iPad mini and iPad... Read more
WaterField’s Rough Rider Leather Messenger Ba...
WaterField Designs have announced the new 15-inch size of their popular Rough Rider leather messenger bag, a vintage-looking bag that combines Old West charm and ruggedness with distinctly modern... Read more
New Mac Pro on sale, save $100 on the 4-Core...
J&R has the new 4-Core Mac Pro in stock today and on sale for $2899 including free shipping plus NY sales tax only. Their price is $100 off MSRP, and it’s the lowest price available for this... Read more
Apple refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished 2013 iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. - 27″ 3.4GHz iMac – $1699... Read more
Updated iPad Price Trackers
We’ve updated our iPad Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers. Using a mobile device? We’ve also updated... Read more
Everything You Wanted To Know And Probably Mo...
Macworld UK’s Lou Hattersley takes a look inside Apple’s A7 System On Chip (SoC) , noting that its processor module is much more powerful than other smartphone chipsets. He notes that the A7 was a... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Inc. Research Data Specialist - Appl...
…of Worldwide Market Research & Intelligence. The team is responsible for conducting Apple branded consumer market research. It is also responsible for analyzing data Read more
*Apple* Automotive Parts Department position...
Apple Automotive is one of the fastest growing dealer…and it shows. Consider making the switch to the Apple Automotive Group today! At Apple Automotive, we Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.