Objective Modula-2

Objective Modula-2 (or ObjM2) is an extension to Modula-2 which follows the Objective-C object model and retains the bracketed Smalltalk message passing syntax introduced in Objective-C. Like Objective-C, Objective Modula-2 is a reflective, object oriented programming language with both static and dynamic typing.

It is intended as a safer alternative to Objective-C for Cocoa and GNUstep software development. It retains most of Modula-2's features, most importantly data encapsulation with nested modules, explicit import and export lists and strict type checking. Objective Modula-2 can therefore be considered a much safer programming language than is Objective-C, yet it has all the capabilities of Objective-C. Classes written in Objective Modula-2 can be used within Objective-C and vice versa.

Language basics

Objective Modula-2 is a "thin" layer on top of Modula-2. It is a superset of the Modula-2 base language. Objective Modula-2 borrows its syntax from both Modula-2 and Objective-C. Most of the syntax, including conventional function calls, is inherited from Modula-2, while the syntax for object-oriented features, including message-passing, is borrowed from Objective-C, which itself derived this syntax from Smalltalk.

In addition to Modula-2 and Objective-C/Smalltalk derived features, Objective Modula-2 has several other features such as Modula-3 style aliased imports, C++ style single line comments, C style postfix increment and decrement operators, a binary function procedure, similar to C's ternary operator but without the ugly syntax, a built-in base type UNICHAR for unicode characters, a built-in type BCD for binary coded decimals and C style string literals with backslash escaped character code notation. Furthermore, the unsafe and highly criticised feature of variant records found in Pascal and Modula-2 has been omitted in Objective Modula-2 because it is outdated in the context of its object model. For backwards compatibility, variant records are flattened into non-variant equivalents.

Messages

The added syntax is for built-in support of the Objective-C object model, a flavour of Object-oriented programming which is based on sending messages to objects, itself based on the object model of Smalltalk. This is distinct from the programming model of Simula, which is used by among other programming languages. This distinction is semantically important. The main difference is that in Objective Modula-2, instead of calling a method, one sends a message.

An object called obj whose class has a method doSomething implemented is said to respond to the message doSomething. If we wish to send a doSomething message to obj, we write
;

Dynamic typing

A major difference to statically typed languages such as C++ and Java is that in Objective Modula-2 it is possible to send messages to objects that do not respond to them.

This is because the object oriented part of Objective Modula-2 is dynamically typed, just like Objective-C. This means that we can send a message to an object which does not have a method specified in its interface to respond to that message. This may seem like a bad idea, but in fact this allows for a great level of flexibility - in Objective Modula-2 an object can "capture" this message, and depending on the object, it can pass the message on to a different object which can respond to the message correctly and appropriately, or pass the message on yet again. In Objective-C parlance this is called "delegation" (see below), also referred to as message forwarding. An error handler can be used in case the message cannot be forwarded. However if the object does not forward the message, nor handle the error, nor respond to it, a runtime error occurs.

An example of a dynamically typed object in Objective Modula-2 is shown below:

VAR
anObject : OBJECT;

The type OBJECT in Objective Modula-2 is the equivalent of type id in Objective-C.

Like other dynamically typed languages, there is the potential problem of an endless stream of run-time errors that come from sending the wrong message to the wrong object. However, Objective Modula-2 allows the programmer to optionally specify the class of an object, and in such cases the compiler will treat the object as statically typed.

An example of a statically typed object in Objective Modula-2 is shown below:

VAR
aString : NSString;

Unlike Objective-C, all classes are pointer types, they need not explicitly be referenced with "POINTER TO".

Interfaces and implementations
Objective Modula-2 requires the interface and implementation of a class to be in separate modules, which can either be nested inside conventional Modula-2 library modules or standalone as separate compilation units. For this purpose two additional module types, a class interface module and a class implementation module were added to the language in addition to Modula-2's library definition and library implementation modules. Class modules can be bundled into library modules to create class clusters or class libraries, similar to the concept of packages in Java.

Interface
The interface of a class is defined in a class interface module.

An example of a class interface module defining a class called FooBar as a descendant of superclass NSObject is shown below:

INTERFACE MODULE FooBar : NSObject;

(* instance variables - by default access mode is private *)
INSTANCE VAR
foo : Foo;
bar : Bar;

(* constructor and initialiser *)
CLASS METHOD newWithFoo: (foo : Foo)
andBar: (bar : Bar) : OBJECT;

(* accessor for foo *)
INSTANCE METHOD foo : Foo;

(* mutator for foo *)
INSTANCE METHOD setFoo: (foo : Foo);

END FooBar.

Implementation
While the class interface module only declares instance variables and prototypes of the class' methods, the implementation of methods is placed in the class' implementation module.

An example of a class implementation module for the class FooBar is shown below:


IMPLEMENTATION MODULE FooBar;

(* constructor and initialiser *)
CLASS METHOD newWithFoo: (foo : Foo)
andBar: (bar : Bar) : OBJECT;
VAR
thisInstance : FooBar;

BEGIN
thisInstance := ;
thisInstance^.foo := foo;
thisInstance^.bar := bar;
RETURN thisInstance;
END;

(* accessor for foo *)
INSTANCE METHOD foo : Foo;
BEGIN
RETURN SELF^.foo;
END;

(* mutator for foo *)
INSTANCE METHOD setFoo: (foo : Foo);
BEGIN
SELF^.foo := foo;
END;

END FooBar.


Methods are written in a different way than Modula-2 procedures. For example, a procedure in both Modula-2 and Objective Modula-2 follows this general form:


PROCEDURE ProcedureName (parameter : FormalType) : ReturnedType;
VAR
(* local variables *)
BEGIN
(* instructions *)
RETURN result;
END;


However, the syntax for procedure headers cannot be used for methods because of the way in which the Smalltalk derived Objective-C object model and its message passing works. Therefore, additional syntax for declaring class and instance methods has been added to the language as shown in the FooBar class implementation example.

This new syntax allows to define methods which follow the Smalltalk derived infix notation for sending messages. An example of how the methods in the FooBar class are used is shown below:


MODULE UseFoobar;

IMPORT FooBar;

VAR
foobar : FooBar;
someFoo: Foo;
someBar: Bar;

BEGIN
(* some code to set someFoo and someBar *)

(* allocate and initialise a new instance of FooBar *)
foobar := ;

(* sending a foo message to foobar *)
someFoo := ;

(* sending a setFoo: message to foobar *)
;
END UseFoobar.


Categories

The Objective-C object model defines an instrument to extend an existing class with additional methods. In Objective-C parlance this is called a category. The methods within a category are added to a class at runtime. Thus, categories permit the programmer to add methods to an existing class without the need to recompile that class or even have access to its source code. For example, if the system you are supplied with does not contain a spell checker in its String implementation, you can add it without modifying the String source code.

Methods within categories become indistinguishable from the methods in a class when the program is run. A category has full access to all of the instance variables within the class, including private variables.

Categories provide an elegant solution to the fragile base class problem for methods.

If you declare a method in a category with the same method signature as an existing method in a class, the category's method is adopted. Thus categories can not only add methods to a class, but also replace existing methods. This feature can be used to fix bugs in other classes by rewriting their methods, or to cause a global change to a class's behavior within a program. If two categories have methods with the same method signature, it is undefined which category's method is adopted.

To allow the declaration and implementation of categories, additional syntax has been added in Objective Modula-2. An example of a class interface module which declares a category called AdditionsToNSString targeting the NSString class is shown below:

INTERFACE MODULE AdditionsToNSString TARGETS NSString;

(* declare a new method to be added to the target class *)
INSTANCE METHOD stringByCollapsingWhitespace : NSString;

END AdditionsToNSString.

The corresponding class implementation module to implement a category does not differ from any other class implementation module. An example of an implementation module for the category AdditionsToNSString is shown below:

IMPLEMENTATION MODULE AdditionsToNSString TARGETS NSString;

INSTANCE METHOD stringByCollapsingWhitespace : NSString;
(* code to implement the method *)
END;

END AdditionsToNSString.

Protocols

The Objective-C object model defines an instrument for multiple inheritance of specification (but not implementation). In Objective-C parlance this is called a protocol. There are two types of protocols: ad-hoc protocols, called informal protocols, and compiler enforced protocols called formal protocols.

An informal protocol is a list of methods that a class may implement. It is specified in the documentation, since it has no presence in the language. Informal protocols often include optional methods, where implementing the method can change the behavior of a class. For example, a text field class might have a delegate that should implement an informal protocol with an optional autocomplete method. The text field discovers whether the delegate implements that method (via reflection), and if so, calls it to support autocomplete. The methods suggested by an informal protocol are often implemented using categories.

A formal protocol is a collection of method declarations that any given class may adopt by implementing the methods declared by the protocol. A class which adopts a protocol must implement all methods declared by that protocol.

To allow the declaration of formal protocols, additional syntax has been added in Objective Modula-2. An example of a protocol interface module which declares a formal protocol called Foobaring is shown below:

PROTOCOL INTERFACE MODULE Foobaring;

(* method declarations *)

END Foobaring.

To allow class modules to be declared to adopt formal protocols, further syntax has been added to Objective Modula-2. An example of a class interface module declaring a class Blob which adopts the Foobaring protocol is shown below:

INTERFACE MODULE Blob ADOPTS Foobaring;

(* instance variables *)

(* method declarations *)

END Blob.

The corresponding class implementation module to implement a class which adopts one or more formal protocol does not differ from any other class implementation module. An example of an implementation module for the class Blob is shown below:

IMPLEMENTATION MODULE Blob;

(* method implementations - including those declared by the Foobaring protocol *)

END Blob.

Class Libraries

Objective Modula-2 allows classes to be bundled into class libraries or class clusters by placing the class modules inside a library module. The class modules inside a library module may be either complete module declarations and implementations or they may be references to external classes.

An example of a library definition module representing a class cluster is shown below:

DEFINITION MODULE Blobs;

EXPORT Blob, MutableBlob, AttributedBlob, MutableAttributedBlob;

(* the base class of this class library *)
INTERFACE MODULE Blob : NSObject;
// instance variables
// method declarations
END Blob.

(* the mutable variant of the base class *)
INTERFACE MODULE MutableBlob : Blob;
// instance variables
// method declarations
END MutableBlob.

(* the attributed variant of the base class *)
INTERFACE MODULE AttributedBlob : Blob;
// instance variables
// method declarations
END AttributedBlob.

(* the mutable variant of the attributed variant *)
INTERFACE MODULE MutableAttributedBlob : AttributedBlob;
// instance variables
// method declarations
END MutableAttributedBlob.

END Blobs.

An example of the corresponding implementation module of the class cluster is shown below:

IMPLEMENTATION MODULE Blobs;

(* the base class of this class library *)
IMPLEMENTATION MODULE Blob;
// method implementations
END Blob.

(* the mutable variant of the base class *)
IMPLEMENTATION MODULE MutableBlob;
// method implementations
END MutableBlob.

(* the attributed variant of the base class *)
IMPLEMENTATION MODULE AttributedBlob;
// method implementations
END AttributedBlob.

(* the mutable variant of the attributed variant *)
IMPLEMENTATION MODULE MutableAttributedBlob;
// method implementations
END MutableAttributedBlob.

END Blobs.

Both class interface modules and class implementation modules of member classes of a class library can be external to the library module which bundles them. A class interface or implementation which is external is referenced using the compiler directive "EXTERNAL". External classes may be written in Objective-C or Objective Modula-2. An example of such a class library is shown below:

DEFINITION MODULE MixedBag;

EXPORT MyOwnBag, MyBrothersBag, SomeoneElsesBag;

INTERFACE MODULE MyOwnBag : NSObject;
// instance variables
// method declarations
END MyInternalClass.

INTERFACE MODULE MyBrothersBag; <*EXTERNAL=ObjM2*>

INTERFACE MODULE SomeoneElsesBag; <*EXTERNAL=ObjC*>

END MixedBag.

In order to allow sharing of instance variables between classes in a library while at the same time restricting the visibility of such a variable outside of the class library, an additional access mode for instance variable has been added in Objective Modula-2 which is not available in Objective-C. An example of an instance variable with library or module-level access is shown below:

DEFINITION MODULE ClassLib;

INTERFACE MODULE ClassA : NSObject;
INSTANCE VAR
PUBLIC TO NEIGHBORS;
sharedVar : Boo;

(* method declarations *)
END ClassA.

INTERFACE MODULE ClassB : NSObject;
// declarations
END ClassB.

INTERFACE MODULE ClassC : NSObject;
// declarations
END ClassC.

END ClassLib.

In the above example, instance variable "sharedVar" of class "ClassA" is declared "PUBLIC TO NEIGHBORS" which means it is visible from within other classes that are members of library ClassLib, in this case classes ClassB and ClassC, but it is invisible anywhere else. Note however, that Objective-C does not have any equivalent access mode. When a class which restricts visibility of an instance variable to neighbour classes is used from within an Objective-C class, that variable is treated as if declared with access mode "private" which means the Objective-C class does not have access to it. Other access modes in Objective Modula-2 are "PUBLIC TO ALL", which is equivalent to @public in Objective-C, "PUBLIC TO SUBCLASSES", which is equivalent to @protected in Objective-C and "PRIVATE" which is equivalent to @private in Objective-C.

Further Additions to the Language

Further additions to the Objective Modula-2 language are planned, most notably class variables, name spaces and automatic garbage collection.

Class Variables

Class variables will be supported through additional syntax which has already been entered into the language specification, but the semantics have yet to be finalised. This will be done in a way that guarantees full compatibility with the Objective-C runtime. An example of a class variable declaration is shown below:

INTERFACE MODULE BooBah : NSObject;

CLASS VAR
thisIsAClassVariable : Boo;

Name Spaces

Name spaces are supported by utilising the data encapsulation features of modules and aliased imports, but how Objective-C will be able to address qualified Objective Modula-2 classes has yet to be finalised.

Automatic Garbage Collection
It is intended to support automatic garbage collection through adding methods and classes, similar to the way autorelease pools are implemented in Objective-C. This will allow the programmer to choose a memory management scheme on a per object basis. Objects can be manually managed, autoreleased or garbage collected simply by sending a message. An example is shown below:

VAR
garbageCollectedString : NSString = gc];
referenceCountedString : NSString = retain];
autoreleasedString : NSString = autorelease];

Note that Apple Computer is working on automatic garbage collection for Cocoa and depending on whether this will be released and when it will be released, further whether GNUstep will adopt the model, Objective Modula-2 may simply use the then built-in garbage collection scheme instead of providing its own.
 
< Prev   Next >