Objective-Everything Release 5.  Copyright ©1994-1998 by TipTop Software, Inc.  All Rights Reserved.

  Objective-Perl

Objective-Perl is implemented by the ObjPerl Perl module.  To import the module:

use ObjPerl; 

Objects and Messages

Perl provides its own object system.  We will use the term "Perl objects" to refer to native Perl objects, and the term "OpenStep objects" or just "objects" to refer to OpenStep (Objective-C, Objective-Tcl, Objective-Perl, etc.) objects.

In ObjPerl, OpenStep objects are represented by a special Perl object type: ObjPerl::Object.  Each OpenStep object accessible from ObjPerl has a unique ObjPerl::Object representation.

To send a message to an object use the msg_send function:

 msg_send($obj, selector, arg0, arg1, ...) 

or, use the Perl arrow message syntax:

 $obj->selector(arg0, arg1, ...) 

The following table compares ObjC, ObjTcl, and ObjPerl message syntaxes:

ObjC: obj is an id Tcl: obj is a Tcl variable ObjPerl: $obj is an ObjPerl::Object
[obj message]; $obj message $obj->message;
[obj message:a1]; $obj message: $a1 $obj->message_($a1);
[obj message:a1 arg2:a2]; $obj message: $a1 arg2: $a2 $obj->message_arg2_($a1,$a2)

Note: In ObjPerl, colon characters (:) in selector names are replaced with underscores (_).  You cannot use the Perl arrow message syntax if the selector name has any underscores (_) other than the leading underscores.  If you want to call a method which has underscores in its name, you must use the msg_send() function directly.

 $obj->doSomething()              # OK:  selector="doSomething" 
 $obj->_doSomething()             # OK:  selector="_doSomething" 
 $obj->doSomething_($a1)          # OK:  selector="doSomething:" 
 $obj->doSomething_with_($a1,$a2) # OK:  selector="doSomething:with:" 
 # To invoke "do_something:with:" 
 $obj->do_something_with_($a1,$a2)  # NOT OK!! selector="do:something:with:" 
 msg_send($obj,"do_something:with:",$a1,$a2) # OK 

Super and Ex messages

Super.  To invoke a method implemented in a specific class, or its superclass, use msg_send_super():

 msg_send_super($obj, clazz, selector, args...); 

where $obj is the target object, selector is a selector for method being invoked, clazz is a class in which a method is defined (the class must be the objects class or some superclass), and args... is the argument list.  Note that obj must be a kind of clazz, otherwise a runtime exception is raised.

For example, to invoke -aSelector:with: in  obj's superclass:

 $super_class=$obj->superclass(); 
 msg_send_super($obj,$super_class,'aSelector:with:',a1,a2); 

Alternatively, to invoke 'aSelector:with:' defined in MyClass you can use Perl-ish syntax:

 $obj->MyClass::aSelector_with_(a1,a2); 

Inside a method body, to send a message to a superclass, you can simply use super:

 super->doSomething(args...); 
 $self->SUPER::doSomething(args...); 

Ex.  To invoke a method implemented in a specific category of a class, use msg_send_ex():

 msg_send_ex($obj, clazz, idx, selector, args...) 

where $obj is the target object, selector is a selector for method being invoked, clazz and idx specify category in which the method is defined, and args... is the argument list.  Note that obj must be a kind of clazz, otherwise a runtime exception is raised.  The idx argument has the following meaning:

 msg_send_ex($obj,$obj->clazz(),-2,obj,'aMethod',args...) 

invokes aMethod implementation two category definitions "old" (or older).

In addition, inside a method body you can use ex to send 'ex' messages.  E.g.:

 ex->doSomething();  # invoke previous doSomething implementation 
 # or: 
 $self->EX::doSomething(); 

Selector mapping

If the $ObjPerl::CONFIG{'Perl_SelectorMap'} flag is 1 (default), you can use "nice" message names. Objective-C selector names are converted into nice names using the following rule: each letter following a colon character (:) is converted to upercase, and all colon characters are thrown out.

To turn the Perl_SelectorMap ON:

 $ObjPerl::CONFIG{'Perl_SelectorMap'}=1; 

Here is an example:

Selector selector map: OFF selector map: ON
doSomething $obj->doSomething; $obj->doSomething;
doSomething: $obj->doSomething_($a1); $obj->doSomething($a1);
doSomething:with: $obj->doSomething_with_($a1,$a2); $obj->doSomethingWith($a1,$a2);
_doSomething:with: $obj->_doSomething_with_($a1,$a2); $obj->_doSomethingWith($a1,$a2);

When the selector map is ON, you can still use the regular arrow message syntax.  E.g., when the selector map is ON both $obj->doSomethingWith($a1,$a2) and $obj->doSomething_with_($a1,$a2) would invoke "doSomething:with:".

Note: Although it is highly unlikely, it is possible to get ambiguous selector mappings.   For example, if both selectors "doSomething::with:" and "doSomething:with::" are known to the system, $obj->doSomethingWith($a1,$a2,$a3) can map to the either selector.  In this case, you should use the regular arrow message form, e.g.: $obj->doSomething_with__($a1,$a2,$a3).  Finally, note that no pair of selectors in all of the standard shlibs combined (ObjC, AppKit, Foundation, EOF, PDO, WOF) can result in an ambiguous mapping.

Note: If you don't have a good reason for using selector mapping, you should not use it since it incurs some runtime performance penalty.

Note: You should not use the selector mapping facility to send messages over PDO.

The nil Object

The nil function, when invoked with no arguments, returns the nil object.  The nil function with one argument:

 nil($obj) 

returns true (1) if the object is nil, false (0) if non-nil, or generates an error if $obj is not an OpenStep object.  To test if something is a valid OpenStep object use the object_is_bad function:

 object_is_bad($obj) 

This function returns true (a description) if $obj is not a valid OpenStep object, or false (0) if $obj is a valid OpenStep object.

The nil object is an exception to the rule that OpenStep objects are uniquely represented by the special Perl object type (ObjPerl::Object).  The "undefined" Perl value is also a valid nil object and as such it can be used as a message argument.  [Note, however, that you cannot send a message to undef using the arrow message syntax since undef is not a "blessed" Perl object; but you can send a message to undef if you use explicit msg_send.]

Sending a message to the nil object is defined to return nil.

Classes

To obtain a reference to an OpenStep class, use:

 class('MyObject') 

The class_lookup function will quietly return nil if the class does not exist (i.e., the class is not loaded in the runtime system).  On the other hand, the class function will attempt to autoload the class if the class is not loaded, and return the reference (an ObjPerl::Object) to the class if successful.  Otherwise, if the class cannot be autoloaded, class will generate an error.

Example: To create an instance of class NSObject:

 $obj=class('NSObject')->alloc->init->autorelease; 

or simply:

 $obj=NSObject->alloc->init->autorelease; 

Note: Just as any other OpenStep object, class objects are represented by ObjPerl::Object instances.  In addition, class objects can be simply represented by their names.

Type Conversion

When a message is sent from Perl to an ObjPerl object, all native Perl arguments are converted to the appropriate low-level ObjC types.  The value returned is converted back to the appropriate Perl value.

The following table lists the correspondence between ObjC and ObjPerl types.  Type conversion is performed for all message argument values and return values (when a message is sent from ObjPerl, and when a method implemented in ObjPerl is invoked), and for instance variable values (when instance variables are accessed from ObjPerl).

ObjC ObjPerl
Class ObjPerl::Object
id ObjPerl::Object
SEL scalar (PV)
STR scalar (PV)   (1)
char scalar (IV)
unsigned char scalar (IV)
short scalar (IV)
unsigned short scalar (IV)
int scalar (IV)
unsigned int scalar (IV)
long scalar (IV)
unsigned long scalar (IV)
float scalar (NV)
double scalar (NV)
array array reference (RV/AV)
struct array reference (RV/AV)  (2)
pointer C

Note 1: NULL strings are represented by undefined values.  To free a string (char *) instance variable, simply set it to undef:

 $self->{'aCStr'}=undef; 

Note 2: Structure and array elements correspond to Perl list elements.

Explicit object type conversion

obj EXPR[, ...] The EXPR argument is a Perl expression.  The obj function creates a NSString, NSArray, or NSDictionary. Here is an example:

Evaluating obj in the SCALAR context

 obj("Hello World!") 

This corresponds to @"Hello World!" in ObjC, i.e., NSString "Hello World!" is returned.

 obj(undef) 

Returns nil.

 obj(0) 

Returns NSNumber "0".

 obj(123) 

Returns NSNumber "123".

 obj(['a', 'b', 'c']) 
 obj('a', 'b', 'c') 

Both of these return an NSMutableArray containing NSStrings "a", "b", "c".

 obj({'a' => 'one', 'b' => 'two'}) 

Returns an NSMutableDictionary mapping NSString "a" to "one" and "b" to "two".

 obj(EXPR) If EXPR is already an object, that object is returned unchanged. 

Evaluating obj in the ARRAY context. Evaluating:

 obj($x,$y,$z) 

is equivalent to evaluating:

(scalar(obj($x)),scalar(obj($y)),scalar(obj($z)))

I.e., each argument is individually converted to an object, and a Perl list of these objects is returned.

pl $obj[, ...] This function does the opposite of the obj function: If $obj is a NSString, the function returns a corresponding Perl string.  If $obj is a NSArray, the function returns a reference to a corresponding perl array.  If $obj is a NSDisctionary, the function returns a reference to a corresponding Perl hash.  Otherwise, the function returns a descriptive string representation of $obj.

The following table lists Perl types and corresponding OpenStep types.

Perl OpenStep
scalar (number) NSNumber
scalar (other) NSString
array reference NSArray
array     NSArray
hash reference NSDictionary
hash     NSDictionary
other     error
ObjPerl::Object other (id)

Autoconversion

If the $ObjPerl::CONFIG{'Perl_AutoConvert'} is 1 (default), whenever an argument of type id is expected (e.g., in a message send), the perl type is automatically converted into an object.  I.e., the obj function is implicitly invoked.  Here is an example:

 $obj=NSObject->object; 
 $obj->isEqual_($obj);  # Works as usual 
 $obj->isEqual_('XYZ'); 
 # This is equivalent to: $obj->isEqual_(obj('XYZ')) 
 # which is equivalent to: $obj->isEqual_(class('NSString')->stringWithCString_('XYZ')); 
 $obj->isEqual_([1,2,3]); 
# This is equivalent to: $obj->isEqual_(obj([1,2,3]));
# I.e., the arg of isEqual: is an NSArray!
 $obj->isEqual_({'a' => 'x' }) 
 # This is equivalent to: $obj->isEqual_(obj({'a'=>'x'])); 
 #  I.e., the arg of isEqual: is an NSDictionary! 

Note: The obj and pl functions cannot handle recursive data structures!  For example, the following will fail:

 $a=[1,2,3]; $a->[1]=$a; obj($a); 

Similarly, the autoconversion mechanism cannot handle recursive Perl data structures.

Overloading

Perl class ObjPerl::Object, which is used to represent OpenStep objects is "overloaded" in Perl.  This allows that appropriate conversion is performed when a perl string or a numeric value is required.  In addition, binary operators == and eq are overloaded.  Here is the list of overload functions:

To-string conversion:  This conversion is automatically invoked by Perl when a string value is required.  If  $o1 is a generic OpenStep object (i.e., an ObjPerl::Object), this conversion yields a string describing the object.  E.g.:

 $o1=NSObject->object; 
 print "o1: $o1\n";  # prints:  o1: <NSObject:0x...> 

If $o1 is an NSString or an NSNumber, its value is substituted.

 $o1=NSString->stringWithCString_("Hello World!"); 
 print "o1: $o1\n";  # prints: o1: Hello World! 

To-number conversion: This conversion is automatically invoked by Perl when a number value is required.  If $o1 is a NSNumber, its value is substituted.  Otherwise, the string value of $o1 is converted to a number.

 print $o1+10.5,"\n"; 
 print $o1->doubleValue+10.5,"\n"; 

To-boolean conversion: Returns true iff $o1 is a generic non-nil OpenStep object.  For example, the following two are equivalent:

 if($o1) { ... } 
 if(!nil($o1)) { ... } 

Numeric equality test: Returns true iff $o1 and $o2 are the same object.  (I.e., this is equivalent to the "==" test in ObjC.)  If $o1 or $o2 is not ObjPerl::Object, then the regular perl numeric equality test is performed.

Equality test: Returns true iff $o1->isEqual_($o2).  If $o1 or $o2 is not ObjPerl::Object, then regular perl "eq" comparison is used.  For example, if both $o1 and $o2 are ObjPerl::Object, the following two are equivalent:

 if($o1 eq $o2) { ... } 
 if($o1->isEqual_($o2)) { ... } 

Instance Variable Access

Instance variables of an ObjPerl::Object are accessed iget/iset:

 $val=iget $obj, 'anIvar'; 
 iset $obj, 'anIvar', $val; 

Alternatively, you can access ivars using the FETCH and STORE methods:

 $val=$obj->FETCH('anIvar'); 
 $obj->STORE('anIvar',$val); 

or simply:

 $val=$obj->{'anIvar'}; 
 $obj->{'anIvar'}=$val; 

Another convenient way of accessing instance variables is by "tieing" objects to hashes.  After you tie an object to a hash, you can access instance variables of the object as elements of the hash.  The following piece of code prints all the instance variables of $self and their values:

 tie %self, ObjPerl::Object, $self; 
 foreach (keys %self) { print "$_ = ", $self{$_}, "\n"; }; 

In addition to instance variables, Objective-Everything objects can have any number of attribute values (XVARS) associated with it.  Attribute values are of type "id".

Example:

 xset $obj, 'anXv', 'Hello World!'; 
 xget $obj, 'anXv'; 

Defining Classes, Categories, and Protocols: cdef

One way to define classes, categories, and protocols is to use the cdefine command:

 cdefine(definitions) 

The definitions argument is an ObjC-style collection of class, category, and protocol definitions.

Example:

 cdefine <<'END'; 
 @protocol MyProtocol 
 -(const char *)helloWorld; 
 @end 
 @interface MyObject:NSObject <MyProtocol> 
 { 
 int anInt; 
 char *aStr; 
 id delegate; 
 } 
 -(int)integerValue; 
 -(void)setStringValue:(const char *)s; 
 -(const STR)stringValue; 
 -(void)dealloc; 
 /* Note that although -helloWorld is declared in MyProtocol, we have to 
 list it here as well.  This is because, in ObjPerl, @interface actually 
 *defines* *empty* methods (in ObjC, methods are only declared). */ 
 -(const char *)helloWorld; 
 @end 
 @interface MyObject(MoreStuff) 
 -(void)setDelegate:d; 
 -(id)delegate; 
 @end 
 END 

The @inteface inside cdefine actually defines empty methods.  This is unlike in ObjC, where @interface only declares methods.  The second step is to associate those empty-defined methods with their Objective-Perl implementation.  The methods command is used to do this:

 mbind(class,methodhash) 

The class argument specifies the class for which method implementions are being defined.  The methodhash argument is a Perl hash table reference.  The keys in the hash table are selector names with + or - prepended, depending whether the method is a class or instance method.  The hash table values are Perl subroutine references (or subroutine names) which implement method bodies.

Example:

 sub print_method_args { 
 print "self: $_[0]\n_cmd: $_[1]\nARGS: @_[2..$#_]\n"; 
 nil(); 
 }; 
 # Now, associate method implementations with selectors for class MyObject: 
 mbind MyObject, { 
 '-integerValue' => sub { 
 my($self)=shift; 
 return $self->{'anInt'}; 
 }, 
 '-setStringValue:' => sub { 
 my($self,$_cmd,$s)=@_; 
 $self->{'aStr'}=$s; 
 }, 
 '-stringValue' => sub { 
 return $_[0]->FETCH('aStr'); 
 }, 
 '-setDelegate:' => 'print_method_args',   # sub names are OK, too. 
 '-delegate' => \&print_method_args, 
 '-dealloc' => sub { 
 my($self)=$_[0]; 
 $self->{'aStr'}=undef;  # Free (char *) value 
 super->dealloc; 
 }, 
 '-helloWorld' => sub { "Hello World!" }, 
 }; 
 $o=MyObject->object; 
 $o->setStringValue_("A String"); 
 print $o->stringValue, "\n"; 
 print $o->helloWorld, "\n"; 

Note: Both -setDelegate: and -delegate invoke Perl subroutine print_method_args.

Note: The method command allows method implementations be autoloaded when needed.  For example, consider the following method being defined for class MyObject:

 methods 'MyObject', { '-someMethod' => 'SomePackage::body' }; 

Now, when an instance of MyObject receives message -someMethod, ObjPerl will invoke subroutine SomePackage::body.  If the SomePackage::body subroutine is not defined, the standard Perl autoload mechanism will attempt to load the subroutine.

Defining Classes: class

To define a class use the class command:

 class(classname,superclass,ivars) 

The ivars argument is an ObjC-style instance variable declaration.  The class command returns the newly created class object.

Note: The class command with one argument (classname) returns the class object .

Note: The class command defines a class, but it does not define any method.  Methods are defined using the category_begin/category_end and method commands.  See the next section .

Example:

 class 'MyObject', 'Object', <<'END'; 
 int anInt; 
 char *aStr; 
 id delegate; 
 END 

Defining Categories and Methods: extend

Another approach is to define methods using the extend command:

 extend(class,methodhash) 
 extend(instance,methodhash) 

Example:

 extend MyObject, { 
 '-(int)integerValue' => sub { 
 my($self)=shift; 
 return $self->{'anInt'}; 
 }, 
 '-(void)setStringValue:(const char *)s' => sub { 
my($self,$_cmd,$s)=@_;
$self->{'aStr'}=$s;
},
 ... 
 }; 

Note: "extend" is a synonym for "category".

Note: unlike the mbind command, the methodhash argument is a mapping of full method prototypes (not just method names) to subs.

Defining Categories and Methods: category_begin/end

Another approach is to define methods inside a category block.  A category block is opened by:

 category_begin(class[,plist]) 
 category_begin(instance[,plist]) 

and is closed by:

 category_end 

The plist argument is a Perl reference to a list of protocol names which are implemented by the category.

The method command is used to define methods within a category block.  The method syntax is:

 method(prototype,sub) 

where prototype is an ObjC-style method prototype, and sub is a reference to (or a name of) a Perl subroutine which implements the method body.

Example:

 category_begin 'MyObject', 'MyCategory'; 
 method '-(int)integerValue', 
 sub { 
 my($self)=shift; 
 return $self->{'anInt'}; 
 }; 
 sub print_method_args { 
 print "self: $_[0]\n_cmd: $_[1]\nARGS: @_[2..$#_]\n"; 
 0; 
 }; 
 method '-(void)setStringValue:(const char *)s;', 
 sub { 
 my($self,$_cmd,$s)=@_; 
 $self->{'aStr'}=$s; 
 }; 
 #... 
 category_end; 
 $o=MyObject->object; 
 $o->setStringValue_("A String"); 
 print $o->stringValue, "\n"; 

Note: Both -setDelegate: and -delegate invoke Perl subroutine print_method_args.

Note: The method command allows method implementations to be autoloaded when needed.  For example, consider the following method being defined for class MyObject:

 method '-someMethod', 'SomePackage::body'; 

Now, when an instance of MyObject receives message -someMethod, ObjPerl will invoke subroutine SomePackage::body.  If the SomePackage::body subroutine is not defined, the standard Perl autoload mechanism will attempt to load the subroutine.

Class Autoloading

If you reference a class which is currently not loaded (using the class command), the system will attempt to load the class.  Note: If you are using both ObjPerl with ObjTcl, the class may be autoloaded in ObjTcl, ObjC, or ObjPerl (whichever class definition is found first).

In ObjPerl, class loading is handled by the ObjPerl::LOADCLASS subroutine.  The subroutine takes one argument: class name.  The default implementation will attempt to load (require) Perl module(s) $path$classname, where $path is an element in list ObjPerl::CLASSPACKAGE (by default, this list contains: Class::, ObjPerl::Class::, and ::).  Finally, LOADCLASS will attempt to load class from file $class.objpl.

Note: ObjPerl::LOADCLASS may be invoked as a result of ObjC or ObjTcl trying to access a class which is not currently loaded.

Note: You can also autoload ObjPerl method bodies.

Perl Interpreter Class

Currently you can have only one ObjPerl interpreter.  This interpreter is available as $ObjPerl::interp variable in Perl.  Or, from another Objective-language (ObjC, ObjTcl, ...), send the +getDefaultInterp message to the TTObjPerlInterp class to obtain this interpreter object.  See TTObjPerlInterp.

ObjPerl Shells

The plain tty ObjPerl shell is implemented as a perl script:

 use ObjPerl; 
$interactor=TTInteractor->object;
$interactor->setInterp_($ObjPerl::interp);
$interactor->runModal_(1);

See Examples/sh/objperlsh.

The remote ObjPerl shell (robjperlsh) is used to access a perl interpreter in a different process space over DO. E.g., if you have an ObjPerl palette loaded into IB simply type "robjperlsh IBInterp" to connect to the perl interpreter in IB.  If you want to export a perl interpreter, here is how you do it.  The following example is a simple ObjPerl server to which you can connect from robjperlsh:

 use ObjPerl; 
 $rv=TTReceptionist->sharedInstance; 
 $rv->setConnectionName_("TestConn"); 
 $rv->setObject_forKey_($interp,"ObjPerlInterp"); 
 # If you are not running from AppKit, you have to explicitly run: 
 class("NSRunLoop")->currentRunLoop->run; 

Now, to connect to the ObjPerl interpreter:  robjperlsh TestConn

See Examples/rsh.

AppKit Support

If you want to use any of the appkit functionality, you need to load the AppKit module.

Example:

 use ObjPerl; 
 use AppKit; 
print nil($NSApp),"\n";        # prints 1 
 class('NSApplication')->sharedApplication; 
 print nil($NSApp),"\n";        # prints 0 
 # Run application main event loop and start interactor: 
 AppKit::run {interact}; 

[previous][contents][next]