Learning Objective-J

Objective-J is a new programming language based on Objective-C. It is a superset of JavaScript, which means that any valid JavaScript code is also valid Objective-J code. Anyone familiar with JavaScript and traditional object oriented programming concepts should have no difficulty learning Objective-J. Familiarity with Objective-C will be helpful, but it is not required.

Classes

Objective-J has two types of objects, native JS objects and Objective-J objects. Native JS objects are exactly what they sound like, the objects native to JavaScript. Objective-J objects are a special type of native object added by Objective-J. These new objects are based on classes and traditional inheritance, like C++ or Java, instead of the prototype model.

Creating a class in Objective-J is simple. Here's an example of a Person class that contains one member variable, name:

@implementation Person : CPObject { CPString name; } @end

The beginning of a class is always the keyword @implementation, followed by the class name. The third term, after the colon, is the class you want to subclass. In this case, we're subclassing CPObject, which is the root object for most classes. You don't need a superclass, but most of the time you will want one.

After the declaration, a block enclosed with brackets is used to define all your member variables. Each variable is declared on its own line with a type and variable name, and a semicolon. Technically the type is optional, but its highly recommended. Declaring your member variables is important, because any variable used elsewhere in your class that isn't declared will automatically become a global variable.

To end a class declaration, add they keyword @end.

Methods

Just as with objects, native JavaScript functions work unchanged in Objective-J. In addition to native functions, Objective-J adds methods which are part of the new class system. Let's add a set of accessor methods to our Person class:

- (void)setName:(CPString)aName { name = aName; } - (CPString)name { return name; }

These lines go anywhere after the initial @implementation block and before the @end keyword. This syntax should be familiar to anyone who's programmed a C style language before, including JavaScript. The only interesting thing is the method declaration.

Each method signature starts with either a dash (-) or a plus (+). Dashes are used for instance methods, which are methods you can call on instance variables. Both of our methods above are instance methods, which makes sense because they set and retrieve instance variables of our Person objects.

Following the dash/plus is a return type, in parentheses. Nothing special about this. Finally, we declare the method name. In Objective-J, method parameters are interspersed within the method name. Our two methods above are name, and setName:. Note the colon after setName; it indicated that a paramter follows.

When methods have more than one parameter, each parameter is separated by a colon. In the declaration of such a method, parameters are split by a label, followed by a colon, the type, and the parameter name:

- (void)setJobTitle:(CPString)aJobTitle company:(CPString)aCompany

In Objective-J, method name's are split across all of the arguments to a method. These are not technically named arguments. The method above is named setJobTitle:company:. This is achieved by concatenating the first part of the method with all the subsequent labels, in order.

The parameters to a method must be passed in order, and all of the parameters are required. To call such a multiple parameter method, we pass our data after each label:

[myPerson setJobTitle: "Founder" company: "280 North"];

As you can see, each colon is followed by the input that will be mapped to that parameter name. That sequence of label, colon, input is repeated for each parameter.

You may be wondering why it matters what the actual name of the method is. One pattern you'll find in Objective-J and Cappuccino going forward is the idea of passing a method as an argument to another method. This is used commonly in delegation and in the event system. Since method's aren't first class objects in the same way as JavaScript, we use a special notation to refer to them, @selector. If I wanted to pass the previous method as an argument to another method, I would use the following code:

[fooObject setCallbackSelector: @selector(setJobTitle:company:)];

As you can see, the method name is passed to @selector complete with its colons and parameter labels.

Using Objects & Classes

Now that we've covered the basics Objective-J objects and classes, let's see how you use them. This block of code creates a new Person object, and sets the name:

var myPerson = [[Person alloc] init]; [myPerson setName: "John"];

Method calls in Objective-J are called messages, and you send an object a message using bracket notation like this: [object message]. I mentioned earlier that some methods are class methods, which are meant to be called on a class itself -- alloc is one of these methods. Every class in Objective-J has a special class method called alloc, which returns a new instance of that class.

In the example above, we're calling the alloc method on the Person class, which returns a Person instance. Then, we call the init method on that instance. Both alloc and init return a reference to the object, which we can assign our variable myPerson. Just like alloc, every class inherits the init method from CPObject. Some classes specify their own custom init method, like CPView, which uses the following signature:

- (id)initWithFrame:(CGRect)aFrame

Every subclass should be sure to call its parent class init method. Here's a custom init method for our Person class which takes the name directly:

- (id)initWithName:(CPString)aName { self = [super init]; name = aName; return self; }

First we call our superclass init method, which returns a reference to the newly created instance. We have to assign this reference to the self variable. Then we can do our class specific task of assigning aName to name, and finally, we return self so that calling code will have a reference to the newly initialized object.

Self is the Objective-J equivelant to this. Just as JavaScript's this references the JavaScript object, self references the Objective-J object. Unlike JavaScript, you don't need self.foo to refer to the foo instance variable, you can just use foo.

Many classes in Cappuccino offer a slightly different model for creating objects, which can be more convenient. Instead of calling alloc and init, these classes implement their own class method to return new objects. Note that in class methods, self refers to the class since no instance exists.

+ (id)personWithName:(CPString)aName { return [[self alloc] initWithName: aName]; }

Which would be called like this:

var joe = [Person personWithName:"Joe"];

Importing Code

One commonly desired technique missing from JavaScript is the ability to import code in the same way that languages like Java or C allow. To that affect, we've added the @import statement to Objective-J.

@import <Foundation/CPObject.j> @import <AppKit/CPView.j> @import "MyClass.j"

There are two types of import statements. The angle brackets indicate framework code, while the quotation marks indicate local project code. Framework imports use the built in search path mechanism to search for the desired file in any of the defined locations. Project imports only look in the current working directory.

Memory Management

JavaScript is garbage collected, and so is Objective-J, so you won't see any calls to retain or release in Objective-J code. Many common leaks caused by DOM manipulation are taken care of by the Cappuccino frameworks.

Categories

Categories allow you to add methods to a class without needing to create a new subclass, or worry about the implementaiton details of the original class. The new method (or methods) become part of all instances of the class once the category is loaded.

This is useful in many different scenarios, for example adding methods to built-in classes. If you wanted all your CPString objects to have a method that would return the reverse string, you could define a category like this:

@import <Foundation/CPString.j> @implementation CPString (Reversing) - (CPString)reverse { var reversedString = "", index = [self length]; while(index--) reversedString += [self characterAtIndex: index]; return reversedString; } @end

Now you can call reverse on any string to get the reversed string.

var myString = "abcdefg"; alert([myString reverse]); //alerts "gfedcba"

The syntax for the category is @implementation, followed by the class you're adding to, followed by the name of your category in parentheses. Any methods added before the @end keyword will be part of the category.

It's interesting to note some of the techniques used in the implementation of the reverse method above. For example, reversedString is declared just like any typical JavaScript string. This is thanks to a technology called toll-free bridging which allows any JavaScript object like an array or a string to act both as a JavaScript object and a Cappuccino object at the same time. It responds to CPString methods like length and characterAtIndex:, and it can be modified with traditional JavaScript operators like (+).

Scope

Most of the time, Objective-J has the same scoping rules as JavaScript. Variables not specifically declared with var become globals, while var'd variables have function/method level scope. The two changes to these rules are instance variables and "statics".

Instances variables are declared in the @implementation block, as seen earlier in the tutorial. When you use those variables within your class, they have object level scope -- they are not global, they belong to each instance object. If you forget to declare one of your instance variables, however, then it is treated as a global variable like any other JavaScript code.

"Statics" are something introduced in Objective-J. When you declare a variable with the var keyword outside a function or method implementation, these variables (sometimes called statics) have file level scope. They can only be accessed by other code within the same file. This can be useful for implementing many shared object techniques without needing to resort to global variables.

Wrapping Up

This concludes our basic overview of Objective-J. The language is a simple and straightforward addition to JavaScript, and most developers shouldn't have any trouble becoming familiar with it.

If you'd like to see the complete code listing from the tutorial, you can download it all in a single file: Person.j.

Download

Cappuccino and Objective-J are licensed under the LPGL. For more information, see our licensing page.

Copyright © 2008 - 280 North, Inc. Cappuccino and Objective-J are registered Trademarks of 280 North. Logo by Sofa.