Talk:FPC PasCocoa

From Free Pascal wiki

There is interest in expanding support in FPC for coding applications for the Macintosh platform which can incorporate the Cocoa framework. Some work has already been accomplished in this area and some other discussions have begun weighing potential compiler support. This wiki page is an attempt to summarize the discussions and issues surrounding the support and implementation concerns. The intent is to maintain this page as an up to date reference for open and resolved issues so avoid repetitive questions and having to wade through previous mailing list posts.

If you are able to absolutely clarify or add to anything written on this page, please go ahead and make any corrections or additions directly on this page. If you are unsure of anything, please post your thoughts or questions to the MacPascal mailing list or add them to the "Discussion" page for this article. If you think something is missing in this page, go ahead and add it as an underlined/red question and notify the mailing list of it and hopefully someone or yourself will supply the appropriate answer (deleting the question from the page in the process.) If this seems to be too many guidelines, they are only meant to keep some semblance of order and not meant to get in the way of getting things done :) If anyone can improve the process or format of this page, feel free to voice your constructive opinion :)

Everyone is welcome to participate. Thank you for your interest and support of this project.


to subscribe to the MacPascal mailing list : http://lists.sonic.net/mailman/listinfo/mac-pascal

to post a message to the mailing list  : Mac-Pascal@listman.sonic.net


Goals

Can someone summarize the goals of what is (and is not) being discussed currently?

  • Compiler support to make it easier and more transparent for declaring and implementing an FPC Class to map to an Objective C Class. (2.0 Bindings)
  • A new RTL interface unit containing a number of basic/useful Objective C Classes (which would expand as effort permits) ***
  • Interface Builder Support - NOT?
  • Objective C 1.0 bindings - NOT?

Yes, objc 1.0 should be supported. First of all, because 10.4 (and lower) version of Mac OS X is still used. After all, there should be not problem with supporting both 1.0 and 2.0. It's also good experience for next runtime version (if any). Infact, binding should be ready for all possible Objective-C usage. There's atleast one Windows objective-C application - Safari. So if Cocoa API is to be popular, it's great that FPC has "native" support for obj-c. - Dmitry.

  • *** [[Are we talking about just implementing single calls or are we shooting for semi full framework support so one can use Cocoa event and window handling? From reading further on, it looks like we are just worrying about the programmer implementing one function at a time as needed?]]

Any more goals?

  • Will there ever be nice syntax like in ObjC (ie. [recipient message])?

Current PasCocoa Implementation

Currently PasCocoa is supported as ObjFPC wrapper classes. You can learn more about it at this page PasCocoa


How does anything decided or implemented here affect the existing PasCocoa with Objective C 1.0 binding work? There seems to be a lot of good information there - what things there apply here or vice versa?

Using wrapper classes is generally difficult because it demands the programmer have some knowledge about the wrappers' implementation. For example, it must be remembered, that a wrapper object needs to be created to use Objective C object . If object's "id" reference is not passed as a Handle to the wrapper's constructor, it should be assigned in some other way, otherwise, wrappers will fail to execute properly.

Are there other specific issues which can be mentioned?

For example, exact implementation of super-class messaging (inheritance) is not yet solved (how to forward a message to sub-class, in a developer-friendly way. Object interface can become slugish. Also a care must be taken not to mess up with Wrapper virtual methods and Obj-c Super class messaging). This issue will probably never appear if obj-c is supported by the compiler. - Dmitry

If the compiler can take care of some or all of the translation and mapping issues, implementing Objective C Classes/objects is much easier to implement. If the Objective C runtime API is available and interfaced to, it is possible for any language to work with objective-c classes and objects.

Proposed Compiler Syntax

Class declaration

To declare an FPC Class for an external objective-c class, the keyword "ObjCClass" would be introduced. Why not just call it an ObjectivePascal class, since it's not C anymore? Objective-C classes must be declared individually (as any other Pascal type in the interface section of the unit) Unless a new RTL unit is created? For example:

 type
   YourClassName =  ObjCClass [(ObjCSuperClassName [, ProtocolName, ProtocolName])] 
     [variables declarations]
     [method declarations]
   end; [external [name 'externalname'];]

ObjCClass - defines an Objective C class type declaration

ObjCSuperClassName - identifies an optional Objective-C parent (or super) class for the class. If the superclass name is not specified, a new so-called "root class" is defined, which does not inherit from any other class. Note that this is different from Object Pascal, whereby all classes at least inherit from TObject. Most Objective-C classes inherit from NSObject, but this has to be explicitly specified.

external - Objective-C class declaration. This is necessary to distinguish a class that's implemented in an external, non FPC supplied framework or library (Cocoa in this case) from regular Objective-C classes implemented using "Objective Pascal" in an FPC unit . It is similar to declaring procedures or functions as external, and hence apart from the declaration specifying that the class is externally implemented and provides the declared methods, no other code is required on the FPC side.


another declaration suggestion:

 type
   YourClassName = objcclass (ObjcSuperClassName, ProtocolName, ProtocolName ...)
   [external, name:'externalname']
     // variables
     // methods
   end;

Method declaration

In general, Objective C methods are declared the same way regular pascal class methods are declared. The only? exception is that each Objective C Class method must also have an additional messaging name specified. Example:


 AnotherObject = ObjCClass(NSObject)
   procedure aMethodName ( params: Integer); message 'aMethodName:';   
 end;


each ObjCClass method name is followed by keyword message, and the message keyword is followed by a string constant that matches an existing Objective C method name. So, this means, you will only be able to use a subset of all the possible methods available from the actual underlying Objective C Class = those specific methods you specifically declare? More to the point, if you are making ObjectivePascal classes from scratch, instead of simply defining external method bindings, this should be optional.

If the method name is preceeded with keyword class, it signifies that the method is an ObjCClass method (marked as preceeding "+" at objective-c), rather than instance method (marked as preceeding "-") Need an example of this syntax. Not sure what you are saying here or how this is different than the above declaration [[I think he means it will be a class (template) method, instead of an object (instance) method. - in other words, you can use it on the class itself without first defining a variable and calling the class constructor - but should be done in a way that is keyword compatible with normal Delphi-like ObjectPascal.]]


'Note: it's common for an objective-c method name/identifier to begin with a lower case letter. It is recommended that PasCocoa objects declared in an FPC program follow the same convention.This should really only be recommended for things that will be shared with Coaca, not objective pascal

To Do List:

a) how should one declare a constant NSString/CFString in Pascal (the @"somestring" from Objective-C)

I wonder if compiler can detect the actual usage of string constant. For example, if a string constant used twice, for two different string types, compiler detects this and stores 2 constant strings (Wide and Ansi version).

 const
   HelloWorld = 'Hello world';
 
 procedure ParamWide(const w: WideString);
 procedure ParamAnsi(const a: AnsiString);
 
 ...
   ParamWide(HelloWorld); // there's not conversion, like AnsiToWide.
   ParamAnsi(HelloWorld); 

So, can compiler detect if constant is used as NSString? and generate the proper code code if required, without using any additional keyword, i.e objcstr('Hello world') or NSStr('Hello world')? - Dmitry


b) ideas on how to deal with categories. As Gale Paeper mentioned in a mail a couple of years ago on this list:

Since class categories and protocol usages are only selectively defined and used based on the application's use of particular Cocoa frameworks, one needs to be able to restrict the declarations the compiler sees to only those declarations applicable to used frameworks. If one doesn't have a means to restrict the seen declarations, one will need to provide in some form implementing methods for every single protocol and category methods that exits in the complete Cocoa framework, I think, whether one needs to or not. (Without restricted declaration views, I also think you'll be building a class runtime support data structures which will have erroneous results in runtime test for class protocol and category support tests.) In order to provide restricted declaration views, one needs to be able to extend class type category and protocol method declarations and implementations in units other than the unit containing the base declaration for a class.

Since an all inclusive MacOSAll type of unit won't provide restricted declaration views, I think looking into providing FPC support for non-scoping uses clauses with uses propagation to support umbrella framework style units would be worthwhile. If one doesn't have uses propagation support and one needs restricted declaration views, the uses clause unit list can get pretty long. While there's nothing inherently wrong with long unit lists in uses clauses, it is quite a hassle that quite a few folks don't want to have to deal with.


c) Please add your particular issues / questions here.

Porting Objective C & Cocoa to FPC

maybe a paragraph or two on how Objective C declares classes,objects and methods. And how that Objective C declaration would map to an FPC Class.

Then maybe a paragraph on the Cocoa framework and an example of a typical Cocoa class in Obj C. ?

Then some links to ObjC/Cocoa information for first time users: Need someone who knows their way around the Apple (and other) Cocoa documentation. suggestions welcome :)

http://developer.apple.com/documentation/Cocoa/ObjectiveCLanguage-date.html

http://developer.apple.com/referencelibrary/API_Fundamentals/Cocoa-fund-date.html

http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/WhatIsCocoa/chapter_2_section_1.html#//apple_ref/doc/uid/TP40002974-CH3

Then specific implementation for programmers (these particular entries snipped from the MacPascal mailing list

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html

Everyone going into Cocoa pogramming would be well served reading this guide. The Cocoa class reference is in great majority of cases silent about what you are expected to do with regards to object ownership with instances that you obtain from the system, since authors expected us to read and understand above document. Only exceptions are documented. Sorry about sounding obnoxious, but on cocoa-dev mailing list there are at least 2 threads every month about crashes or leaks, because people didn't read, or have just skimped this guide. nice reading, - Gorazd

and

For all that are working with Cocoa it is mandatory to review:

http://www.stepwise.com/Articles/Technical/2001-03-11.01.html

http://www.stepwise.com/Articles/Technical/HoldMe.html

Despite it is written in 2001, it is still a relevant document describing memory management rules and owneship of objects that are valid unless you use Objective-C garbage collection. -Gorazd

Objective-C Language Summary

This section is based on Objective-C 2.0 Programming Language, Appendix A Language Syntax.

page: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_950_section_1.html

A complete proposal for PasCocoa compiler syntax. - Dmitry

Language Summary

Objective-C adds a small number of constructs to the C language and defines a handful of conventions for effectively interacting with the runtime system. This appendix lists all the additions to the language but doesn’t go into great detail. For more information, see the other chapters in this document.

Messages

Objective-C: Message expressions are enclosed in square brackets:

 [receiver message]

PasCocoa: Message expressions consists of receiver separated with messaged method by dot:

 Reciever.MessagedMethod
 inherited MessagedMethod // for super classes

The receiver can be:

  • A variable or expression that evaluates to an object (including the variable self)
  • A class name (indicating the class object)

* super (indicating an alternative search for the method implementation) PasCocoa uses inherited instead

The message is the name of a method plus any arguments passed to it.

upd: --Skalogryz 23:14, 9 July 2009 (CEST) Objective-C synax also allows to send 'custom' messages to the instance or class. These messages might not be declared in headers.

 id   something;
 [something  setHello:1 World:2]

the actuall method send is 'Hello:World:'. Since Pascal syntax does not support paramname-paramvalue syntax, an obj-c macro function should be used, i.e.

 // passing method name. 
 // copmiler replaces the method name with proper selector 
 // on compiler-time
 objSendMsg(something, 'setHellow:World:', [1,2]);

-or-

 s  : SEL;
 ...
 // by passing selector 
 objSendMsg(something, s', [1,2]);
 ...


objSendMsg is a macro function, that wraps objc_msgSend, objc_msgSend_stret, objc_msgSend_fpret functions.

Defined Types

The principal types used in Objective-C are defined in objc/objc.h. They are:

Obj-C Type Pas Type Definition
id objc.id / objcid An object (a pointer to its data structure).
Class objc.class / objcclass A class object (a pointer to the class data structure).
SEL objc.SEL/SEL A selector, a compiler-assigned code that identifies a method name
IMP IMP/Pointer A pointer to a method implementation that returns an id.
BOOL Boolean A Boolean value, either YES (true) or NO (false. Note that the type of BOOL is char.

id can be used to type any kind of object, class, or instance. In addition, class names can be used as type names to statically type instances of a class. A statically typed instance is declared to be a pointer to its class or to any class it inherits from.

The objc.h header file also defines these useful terms:

Obj-C Term Pas Term Definition
nil nil A null object pointer, (id)0.
Nil nil A null class pointer, (Class)0.
NO false A boolean false value, (BOOL)0.
YES true A boolean true value, (BOOL)1.

Preprocessor Directives

The preprocessor understands these special notations:

Notation Pas Cocoa replacment Definition
#import N/A or uses Imports a header file. This directive is identical to #include, except that it doesn’t include the same file more than once.
// // Begins a comment that continues to the end of the line.

Compiler Directives

Directives to the compiler begin with “@”. The following directives are used to declare and define classes, categories, and protocols:

Directive Pas Cocoa replacment Definition
@interface objcclass / objcclass of Begins the declaration of a class or category interface.
@implementation N/A (unit implementation section) Begins the definition of a class or category.
@protocol objcprotocol (protocol/objcinterface?) Begins the declaration of a formal protocol
@end end; Ends the declaration/definition of a class, category, or protocol


The following mutually exclusive directives specify the visibility of instance variables:

Directive Pas Cocoa replacment Definition
@private private Limits the scope of an instance variable to the class that declares it.
@protected protected Limits instance variable scope to declaring and inheriting classes.
@public public Removes restrictions on the scope of instance variables

PasCocoa: The default is @protected ?public.


These directives support exception handling:

Directive Pas Cocoa replacment Definition
@try try Defines a block within which exceptions can be thrown.
@throw raise Throws an exception object
@catch() except Catches an exception thrown within the preceding @try block
@finally finally Defines a block of code that is executed whether exceptions were thrown or not in a preceding @try block.

PasCocoa: would be there a difference between FPC excpetions and Obj-C exceptions?


The following directives support the declared properties feature (see “Declared Properties” (page 57)):

Directive Pas Cocoa replacment Definition
@property property Begins the declaration of a declared property.
@synthesize (read/write method names are blank) Requests that, for the properties whose names follow, the compiler generate accessor methods for which there are no custom implementations
@dynamic ?N/A Instructs the compiler not to generate a warning if it cannot find implementations of accessor methods associated with the properties whose names follow

In addition, there are directives for these particular purposes:

Directive Pas Cocoa replacment Definition
@class objcclass; Declares the names of classes defined elsewhere.
@selector(method_name) objcselector(method_name) Returns the compiled selector that identifies method_name.
@protocol(protocol_name) objcprotocol(protocol_name) Returns the protocol_name protocol (an instance of the Protocol class). (@protocol is also valid without (protocol_name) for forward declarations.)
@encode(type_spec) objcencode(type_spec) Yields a character string that encodes the type structure of type_spec
@"string" ? NSSTR('string') Defines a constant NSString object in the current module and initializes the object with the specified string.
@"string1" @"string2" ...@"stringN" ??? Defines a constant NSString object in the current module. The string created is the result of concatenating the strings specified in the two directives.
@synchronized() synchronize() Defines a block of code that must be executed only by one thread at a time.

Classes

A new class is declared with the @interface directive. The interface file for its superclass must be imported:

Objective-C:

 #import "ItsSuperclass.h"
 @interface ClassName : ItsSuperclass < protocol_list >
 {
   instance variable declarations
 }
 method declarations
 @end

PasCocoa:

 ClassName = objcclass (ItsSuperClass[, ProtocolList])
 protected
   instance variable declarations
 public
   method declarations; 
 end; [external;]
 

Everything but the compiler directives and class name is optional. If the colon and superclass name are omitted, the class is declared to be a new root class. If any protocols are listed, the header files where they’re declared must also be imported. A file containing a class definition imports its own interface: Objective-C:

 #import “ClassName.h”
 @implementation ClassName
 method definitions
 @end

PasCocoa. If external keyword is omit, then method implementation must be present at the implementation section.

 implementation
 
 procedure ClassName.methodname ()
 begin 
   ...
 end;


--Skalogryz 23:21, 9 July 2009 (CEST) As Jonas Maebe noted, it's possible for obj-c classes not to have a superclass (i.e. NSObject and NSProxy are root classes). It's necessary to specify that a new obj-c class is a root class. For this "id" keyword is used:

 NewRootClassName = objcclass (id[, Protocol1, Protocol2 ... ProtocolN])

if no protocols are implemented, it's possible to omit "id" keyword.

 NewRootClassName = objcclass

This is very important, because FPC classes, are always derived from TObject class that has some methods. While declared objcclass may have none.

Categories

A category is declared in much the same way as a class. The interface file that declares the class must be imported:

Objective-C:

 #import "ClassName.h"
 @interface ClassName ( CategoryName ) < protocol list >
 method declarations
 @end

PasCocoa:

Variant 1:

 type
   CategoryName = objcclass of (ClassName [, protocol list])
     ... method declarations ...
   end; [external;]

Variant 2:

 type
   CategoryName = objcclass (ClassName [, protocol list])
     ... method declarations ...
   end; virtual; [external;]

Variant 3:

 type
   CategoryName = virtual objcclass (ClassName [, protocol list])
     ... method declarations ...
   end;  [external;]

Variant 4:

 type
   CategoryName = objccategory (ClassName [, protocol list])
     ... method declarations ...
   end; [external;]



The protocol list and method declarations are optional. If any protocols are listed, the header files where they’re declared must also be imported. Like a class definition, a file containing a category definition imports its own interface:

Objective-C:

 #import "CategoryName.h"
 @implementation ClassName ( CategoryName )
 method definitions
 @end

PasCocoa. It can be a problem, because, there might 2 Categories with the same name, but of the different class. And it's possible, that they're implemented in the single unit. So it's necessary to define what method of what category of what class is implemented:

 implementation 
   
 procedure CategoryName.MethodName(params list) of ClassName;
 begin
    ..
 end;

Formal Protocols

Objective-C:

 Formal protocols are declared using the @protocol directive:
 @protocol ProtocolName < protocol list >
 declarations of required methods
 @optional
 declarations of optional methods
 @required
 declarations of required methods
 @end

PasCocoa, every method declaration, marked with virtual is optional. All other methods are required:

 type
   ProtocolName = objcprotocol [(ProtocolList)]
     method declaration; // required method method
     method declaration; virtual; // optional method
   end;


The list of incorporated protocols and the method declarations are optional. The protocol must import the header files that declare any protocols it incorporates. The @protocol() directive specifies that following methods are optional; the @required directive directive specifies that following methods must be implemented by a class that adopts the protocol. The default is @required. You can create a forward reference to a protocol using the @protocol directive in the following manner: @protocol ProtocolName; Within source code, protocols are referred to using the similar @protocol() directive, where the parentheses enclose the protocol name. Protocol names listed within angle brackets (<...>) are used to do three different things:

  • In a protocol declaration, to incorporate other protocols (as shown earlier)
  • In a class or category declaration, to adopt the protocol (as shown in “Classes” (page 116) and “Categories” (page 116))
  • In a type specification, to limit the type to objects that conform to the protocol

Within protocol declarations, these type qualifiers support remote messaging:

Type Qualifier Pas Var qualifier Definition
oneway ??? The method is for asynchronous messages and has no valid return type
in ?const The argument passes information to the remote receiver.
out ?out The argument gets information returned by reference.
inout var The argument both passes information and gets information.
bycopy A copy of the object, not a proxy, should be passed or returned.
byref ?const A reference to the object, not a copy, should be passed or returned.

Method Declarations

The following conventions are used in method declarations:

  • A “+” "Class" precedes declarations of class methods.
  • A “-” precedes declarations of instance methods. nothing precedes instance method declaration in PasCocoa.
  • Argument and return types are declared using the C (FreePascal) syntax for type casting.
  • Arguments are declared after colons (:), for example:PasCocoa N/A
 - (void)setWidth:(int)newWidth height:(int)newHeight

Typically, a label describing the argument precedes the colon—the following example is valid but is considered bad style:

 - (void)setWidthAndHeight:(int)newWidth :(int)newHeight

Both labels and colons are considered part of the method name.

  • The default return and argument type for methods is id, not int as it is for functions. (However, the

modifier unsigned when used without a following type always means unsigned int.) PasCocoa N/A

Method Implementations

Each method implementation is passed two hidden arguments:

  • The receiving object (self).
  • The selector for the method (_cmd). //PasCocoa avaialble?

Objective-C:

Within the implementation, both self and super refer to the receiving object. super replaces self as the receiver of a message to indicate that only methods inherited by the implementation should be performed in response to the message. Methods with no other valid return typically return void are procedures.

PasCocoa: Within the implementation, both self refer the receiving object. use inherited to indicate that only methods inherited by the implementation should be performed in response to the message. Methods with no other valid return are typically procedures.


Deprecation Syntax

Syntax is provided to mark methods as deprecated:

Objective-C:

 @interface SomeClass
 -method __attribute__((deprecated));
 @end

or:

 #include <AvailabilityMacros.h>
 @interface SomeClass
 -method DEPRECATED_ATTRIBUTE; // or some other deployment-target-specific macro
 @end

PasCocoa, using keyword deprecated:

 type
   SomeClass = objcclass
     method declaration; deprecated;
   end;

This syntax is available only in Objective-C 2.0 and later. PasCocoa available for both 1.0 and 2.0 versions

Naming Conventions

The names of files that contain Objective-C source code have the .m extension. Files that declare class and category interfaces or that declare protocols have the .h extension typical of header files. Class, category, and protocol names generally begin with an uppercase letter; the names of methods and instance variables typically begin with a lowercase letter. The names of variables that hold instances usually also begin with lowercase letters. In Objective-C, identical names that serve different purposes don’t clash. Within a class, names can be freely assigned:

  • A class can declare methods with the same names as methods in other classes.
  • A class can declare instance variables with the same names as variables in other classes.
  • An instance method can have the same name as a class method.
  • A method can have the same name as an instance variable.
  • Method names beginning with “_”, a single underscore character, are reserved for use by Apple.

Likewise, protocols and categories of the same class have protected name spaces:

  • A protocol can have the same name as a class, a category, or anything else.
  • A category of one class can have the same name as a category of another class.

However, class names are in the same name space as global variables and defined types. A program can’t have a global variable with the same name as a class.