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.94
Apple Inc.
+5.93
MSFT
$40.01
Microsoft Corpora
-0.39
GOOG
$536.10
Google Inc.
-20.44

MacTech Search:
Community Search:

Software Updates via MacUpdate

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
Mac DVDRipper Pro 4.1.7 - Copy, backup,...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
PDFpenPro 6.2 - Advanced PDF toolkit for...
PDFpenPro allows users to edit PDF's easily. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Create... Read more
PDFpen 6.2 - Edit and annotate PDFs with...
PDFpen allows users to easily edit PDF's. Add text, images and signatures. Fill out PDF forms. Merge or split PDF documents. Reorder and delete pages. Even correct text and edit graphics! Features... Read more
Monolingual 1.5.9 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. It requires a 64-bit capable Intel-based Mac and at least... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Starcraft II: Wings of Liberty 1.1.1.180...
Download the patch by launching the Starcraft II game and downloading it through the Battle.net connection within the app. Starcraft II: Wings of Liberty is a strategy game played in real-time. You... Read more
Sibelius 7.5.0 - Music notation solution...
Sibelius is the world's best-selling music notation software for Mac. It is as intuitive to use as a pen, yet so powerful that it does most things in less than the blink of an eye. The demo includes... Read more
Typinator 5.9 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
MYStuff Pro 2.0.16 - Create inventories...
MYStuff Pro is the most flexible way to create detail-rich inventories for your home or small business. Add items to MYStuff by dragging and dropping existing information, uploading new images, or... Read more

Latest Forum Discussions

See All

Have a Special Dead Trigger 2 Easter Bas...
Have a Special Dead Trigger 2 Easter Basket Full of Goodies, Courtesy of Madfinger Games Posted by Rob Rich on April 18th, 2014 [ permalink ] Dead Trigger 2 | Read more »
Zynga Launches Brand New Farmville Exper...
Zynga Launches Brand New Farmville Experience with Farmville 2: Country Escape Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
David. Review
David. Review By Cata Modorcea on April 18th, 2014 Our Rating: :: MINIMALISTIC IN A DIFFERENT WAYUniversal App - Designed for iPhone and iPad David is a minimalistic game wrapped inside of a soothing atmosphere in which the hero... | Read more »
Eyefi Unveils New Eyefi Cloud Service Th...
Eyefi Unveils New Eyefi Cloud Service That Allows Users to Share Media Across Personal Devices Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
Tales from the Dragon Mountain: The Lair...
Tales from the Dragon Mountain: The Lair Review By Jennifer Allen on April 18th, 2014 Our Rating: :: STEADY ADVENTURINGiPad Only App - Designed for the iPad Treading a safe path, Tales from the Dragon Mountain: The Lair is a... | Read more »
Yahoo Updates Flickr App with Advanced E...
Yahoo Updates Flickr App with Advanced Editing Features and More Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
My Incredible Body - A Kid's App to...
My Incredible Body - A Kid's App to Learn about the Human Body 1.1.00 Device: iOS Universal Category: Education Price: $2.99, Version: 1.1.00 (iTunes) Description: Wouldn’t it be cool to look inside yourself and see what was going on... | Read more »
Trials Frontier Review
Trials Frontier Review By Carter Dotson on April 18th, 2014 Our Rating: :: A ROUGH LANDINGUniversal App - Designed for iPhone and iPad Trials Frontier finally brings the famed stunt racing franchise to mobile, but how much does its... | Read more »
Evernote Business Notebook by Moleskin I...
Evernote Business Notebook by Moleskin Introduced – Support Available in Evernote for iOS Posted by Tre Lawrence on April 18th, 2014 [ permalink ] | Read more »
Sparkle Unleashed Review
Sparkle Unleashed Review By Jennifer Allen on April 18th, 2014 Our Rating: :: CLASSY MARBLE FLINGINGUniversal App - Designed for iPhone and iPad It’s a concept we’ve seen before, but Sparkle Unleashed is a solidly enjoyable orb... | Read more »

Price Scanner via MacPrices.net

iMacs on sale for up to $160 off MSRP this we...
Best Buy has iMacs on sale for up to $160 off MSRP for a limited time. Choose free home shipping or free instant local store pickup (if available). Prices are valid for online orders only, in-store... Read more
iPad Airs on sale this weekend for up to $100...
Best Buy has WiFi iPad Airs on sale for $50 off MSRP and WiFi + Cellular iPad Airs on sale for $100 off MSRP on their online store for a limited time, with prices now starting at $449. Choose free... Read more
Apple restocks refurbished Mac minis starting...
The Apple Store has restocked Apple Certified Refurbished Mac minis for up to $150 off the cost of new models. Apple’s one-year warranty is included with each mini, and shipping is free: - 2.5GHz Mac... Read more
Hyundai Brings Apple CarPlay To The 2015 Sona...
Hyundai Motor America has announced it will bring Apple CarPlay functionality to the 2015 Sonata. CarPlay is pitched as a smarter, safer and easier way to use iPhone in the car and gives iPhone users... Read more
Updated iPads Coming Sooner Than We Had Thoug...
MacRumors, cites KGI securities analyst Ming Chi Kuo, well-respected as an Apple product prognisticator, saying that Apple will introduce an upgraded iPad Air and iPad mini in 2014/Q3, meaning the... Read more
Toshiba Unveils New High And Low End Laptop M...
Toshiba has announced new laptop models covering both the high-end and low-end of the notebook computer spectrum. Toshiba 4K Ultra HD Laptop Toshiba’s new Satellite P55t features one of the world’s... Read more
Save up to $270 with Apple refurbished 13-inc...
The Apple Store has Apple Certified Refurbished October 2013 13″ Retina MacBook Pros available starting at $1099, with models up to $270 off MSRP. Apple’s one-year warranty is standard, and shipping... Read more
Apple now offering refurbished iPad mini with...
The Apple Store has Certified Refurbished 2nd generation iPad minis with Retina Displays now available starting at $339. Apple’s one-year warranty is included with each model, and shipping is free.... Read more
Microsoft Blinks – Drops Microsoft Office 365...
Microsoft has dropped the annual subscription fee for Microsoft Office 365 Personal – which is needed in order to create and edit documents in Microsoft Office for iPad. However, Apple’s iOS and OS X... Read more
New AVG Vault Apps for iOS and Android Help K...
AVG Technologies N.V. an online security company for 177 million active users, has announced the launch of its latest mobile application, AVG Vault. The free app introduces an innovative user... Read more

Jobs Board

*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
*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* Retail - Manager - Holyoke - Apple I...
Job Summary Keeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, you’re a master of them all. In the store’s fast-paced, Read more
*Apple* Retail - Manager - Apple (United Sta...
Job SummaryKeeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, you're a master of them all. In the store's fast-paced, dynamic 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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.