Sign in Join
Wiki copytemporary

FPC PasCocoa/Differences: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: FPC PasCocoa/Differences

OldNewLine
1+FPC's [[FPC PasCocoa|Objective-Pascal]] dialect was introduced to enable seamless interfacing with Objective-C code, in particular on macOS. Due to inherent differences between the C and Pascal philosophies, this language mode will have some seemingly strange behaviour regardless of whether your main background is in Objective-C or in Object Pascal.
2+
3+This page describes the conceptual differences between Objective-Pascal and on the one hand Objective-C, and on the other hand Object Pascal.
4+
5+## Differences with Object Pascal
6+
7+### No constructors
8+
9+- **Description**: The Objective-C language has no notion of a formal *constructor*. Hence, the *constructor* keyword is not supported in an *objcclass*.
10+- **What to do**: Construction of class instances in Objective-C usually happens explicitly in two stages: first the *alloc* class message is sent to the class type that you want to instantiate, and next you send an *initXXX* instance message to its result. This *initXXX* (with *XXX* dependent on the class type) message is called an *initializer*, and will initialise in the various fields, or may in theory even return a completely different object of a different type.
11+- **Warning**: By convention, *initXXX* methods free the allocated memory and return *nil* if the initialisation failed for some reason. This means that if you allocate and initialise an instance using two different statements, you have to assign the result of the *initXXX* method to your instance variable. And you always have to check for *nil* after calling an *initXXX* method before using the result if you are not certain that initialisation will always succeed!
12+- **Example**:
13+
14+``` pascal
15+{$modeswitch objectivec1}
16+var
17+ obj: NSObject;
18+begin
19+ // 1. Initialisation in two steps. First allocate the memory.
20+ obj:=NSObject.alloc;
21+ // Next, initialise. Warning: do not just use "obj.init", since in theory it could
22+ // return nil, or even a completely different object!
23+ obj:=obj.init;
24+ obj.release;
25+
26+ // 2. Alternative one-liner.
27+ obj:=NSObject.alloc.init;
28+ obj.release;
29+end.
30+```
31+
32+- **More information**:
33+ - <https://web.archive.org/web/20101206131250/http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html>
34+ - <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html>
35+ - <https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/ObjectCreation.html>
36+ - <https://web.archive.org/web/20121013134748/http://MacDeveloperTips.com/objective-c/objective-c-initializers.html>
37+ - <https://web.archive.org/web/20160308011452/http://macdevelopertips.com/objective-c/objective-c-memory-management.html>
38+
39+### No destructors
40+
41+- **Description**: The Objective-C language has no notion of a formal *destructor*. Hence, the *destructor* keyword is not supported in an *objcclass*.
42+- **What to do**: By convention, the *dealloc* instance method is used like a destructor in Objective-C. You can override this method to perform any kind of cleanup.
43+- **Warning**: Never call *dealloc* manually. Instead, call *release* if you no longer need the instance **and** if you are responsible for releasing the instance (see the links below for more information about memory management basics of Objective-C/Cocoa). Instances under Objective-C are reference counted, and the *release* method will only call the *dealloc* method when the reference count reaches 0. Additionally, when using garbage collected Objective-C (not yet supported by FPC), the *finalize* instance method is called rather than the *dealloc* method.
44+- **More information**:
45+ - <http://macdevelopertips.com/objective-c/objective-c-memory-management.html>
46+ - <http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/GarbageCollection/Articles/gcInapplicablePatterns.html#//apple_ref/doc/uid/TP40006762-SW4>
47+
48+### No unique root class
49+
50+- **Description**: In Object Pascal, if you do not specify a parent class, a newly defined class will automatically inherit from *TObject*. While in NeXTStep/Apple/GNUStep's Objective-C frameworks *NSObject* fulfills a similar role, there are also other root classes (such as *NSProxy*). Since there is no unique root class in the Objective-C language, this means that if you do not specify a parent class, you will define a new root class.
51+- **What to do**: Generally, you will want new classes to inherit from *NSObject* if they do not have to inherit from any other class.
52+
53+## Differences with Objective-C
54+
55+### Marking methods as *override*
56+
57+- **Description**: In Object Pascal, if you want to override an inherited method then you have to add the *override* keyword to the declaration in the child class. Without *override*, the inherited method will be hidden in the syntactic scope of the child class, but when casting the child class to the parent type and calling that method, the parent's implementation will still be executed.
58+   In Objective-C all dispatching is name-based, and hence a method with the same selector in a child class will always override a parent method with the same name (unlike in Object Pascal, it is not possible to hide an inherited method, nor to start a new inheritance tree).
59+
60+   Objective-Pascal however also requires *override* to be specified when overriding inherited Objective-C methods for consistency with Object Pascal. If *override* is absent, the compiler will give an error. This can also help catch bugs, as explained in [this thread](http://lists.apple.com/archives/Xcode-users/2009/Aug/msg00251.html) and [this bug report filed with Apple](http://openradar.appspot.com/7215146). There is one exception though: for *external* classes, *override* is not required because such declarations are often produced using automated parsers, and requiring them to add *override* in the right places could needlessly complicate them. Not adding *override* in such situations will however still cause the compiler to show a hint.
61+- **What to do**: Always add *override;* at the end of method declarations that override inherited methods.
62+
63+### Class instances are implicit pointers
64+
65+- **Description**: In (Delphi-style) Object Pascal, all class instance variables are implicit pointers, and they are also implicitly dereferenced. In Objective-C, class instances are explicitly declared as being "a pointer to a class instance", e.g. *NSObject *obj;* and need to be explicitly dereferenced when accessing instance variables (although this seldom happens, since most of the time accessors or properties are used). We have chosen to follow the Object Pascal way for Objective-Pascal to make it more familiar for people coming from Object Pascal, and because (given the identifier naming constraints outlined below) using a non-dereferenced form of Objective-C class would hardly ever be wanted in Pascal.
66+- **What to do**: Do not use any explicit indirection when dealing with Objective-Pascal class instances.
67+
68+### Protocol method signatures in class declarations
69+
70+- **Description**: When an Objective-C class implements (conforms to) a protocol, the protocol method signatures must not be repeated in the class declaration. In Object Pascal, when a class implements an interface (~ protocol), the method signatures of the interface do have to be repeated in the class definition. The primary reason for this duplication is that in Object Pascal, it is possible to specify that an interface method is implemented using a function with a different name (since dispatching is based on VMT address rather than on name, this is no problem). For consistency with Object Pascal, Objective-Pascal also requires repeating the protocol method declarations in *objcclass*es that conform to these protocols.
71+- **What to do**: copy/paste the protocol method declarations to the *objcclass* declaration. Repeating the *message* modifiers is optional, as the compiler will take them from the *objcprotocol* declaration if they are not specified in the *objcclass* declaration.
72+
73+### Duplicate identifiers
74+
75+- **Description**: Pascal allows an identifier to appear only once per scope, and treats a class declaration as a single scope. This means that all instance variables, class methods, instance methods and properties must have distinct names. In Objective-C, each of those categories has its own namespace and there is no problem with having an instance method, class method and instance variable all named *foo* in a single class. Similarly, a class and a protocol can also have the same name (such as the *NSObject* class and protocol). Also keep in mind that identifiers are case-insensitive in Pascal.
76+- **What to do**: On the Pascal-side, all such identifiers must be made unique. In case of methods, these can easily be mapped to the real names used in the corresponding in Objective-C code due to the fact that the selector has to be specified explicitly anyway. We will probably add the ability to specify mappings for instance variables. The real name of an Objective-C class or protocol can be specified by specifying a name along with the *external* modifier at the end of the type declaration.
77+- **Example**:
78+
79+``` pascal
80+type
81+ NSObjectProtocol = objcprotocol external name 'NSObject' // specify the real name of this protocol
82+ // "_class" instead of "class" on the Pascal side, because "class" is a language keyword
83+ function _class: pobjc_class; message name 'class';
84+ end;
85+
86+ NSObject = objcclass external (NSObjectProtocol) // name specification is optional since NSObject is the real name
87+ function _class: pobjc_class; // no need to specify the selector again, it's copied by the compiler from the protocol definition
88+ // "classClass" (or something else) instead of "_class" because otherwise there are
89+ // two methods with the same name in the NSObject class.
90+ class function classClass: pobjc_class; message 'class';
91+ end;
92+```
93+
94+### Using class types as first class entities
95+
96+- **Description**: In Objective-C, it is possible to use a class name directly when sending messages to it (e.g., *\[NSObject alloc\]*), but when an argument is of a class type then the *class* message must be sent to it (e.g., *\[annotation isKindOfClass: \[Building class\]\]* rather than *\[annotation isKindOfClass: Building\]*). In Object Pascal, class types can be used directly in such situations (e.g., *instance.inheritsfrom(myclasstype)*). We have opted to also make class types directly usable in Objective-Pascal, because the reason that this is not possible in Objective-C seems to be mostly a [parser limitation](http://lists.apple.com/archives/Objc-language/2009/Sep/msg00016.html) rather than a conscious design decision.
97+- **What to do**: You can use *typename.classClass* and *typename* interchangeably in Objective-Pascal. The *classClass* name is due to *class* being a reserved word in Pascal, and *_class* being used for the instance method *class*. That can be seen as another argument in favour of relaxing the Objective-C behaviour.
98+
99+### Sending class messages to instances
100+
101+- **Description**: In Objective-C, class messages must be sent to classes and instance messages to instances. In part, this is required due to the fact that instance and class methods can have the same selector (or alternatively, you can view this as the feature responsible for enabling class and instance methods to have same-named selectors). In Pascal, since every identifier that is part of a class definition (field, instance method, class method, property) must have a unique name, it is possible to call class methods directly using an instance. Since the same identifier scoping rules apply to Objective-Pascal, we have chosen to also enable this feature for that dialect.
102+- **What to do**: You can use *instance._class.classmethod* and *instance.classmethod* interchangeably. See the previous point for the reason why the *class* method is called *_class* in Objective-Pascal.
103+
104+### Instances that conform to protocols
105+
106+- **Description**: In Objective-C, declaring a variable of a generic class type that conforms to one or more protocols happens using *id\<protocol1,protocol2\>*. In Object Pascal, a variable can only be declared to implement a single interface (conform to one protocol), even though individual classes can implement many interfaces just like in Objective-C. The Pascal declaration is simply *interface_typename*. For now, we have limited Objective-Pascal to the same behaviour, i.e., to declare a variable of a generic class type that conforms to the *NSCopying* protocol, use *var obj: NSCopying;*. The main reason is that it's not clear what the Pascal syntax for a variable conforming to multiple protocols should look like.
107+- **What to do**: For now, you will need to typecast your variables to different protocol types if you want call messages belonging to different protocols. Alternatively, you can declare a new protocol type that inherits from all of the required protocols, and then use this protocol as the type for your variable. This may be fixed in the future if a suitable syntax is found to specify this in the variable declaration itself.
108+
109+### Sending messages to *id*
110+
111+- **Description**: In Objective-C, it is possible to send any message to [[FPC PasCocoa|id-typed]] variables, even messages whose selector is not prototyped in the current scope. One reason is probably that this is similar to how C works (in C, you can also call functions for which no declaration is visible), and another is that the selector can be deduced unambiguously by the compiler from the invocation. In Objective-Pascal, only messages that are declared as part of an objcclass or objccategory in the current scope can be sent to *id*-typed variables. This is both due to Pascal conventions (declare before use), and because in Objective-Pascal the compiler cannot automatically deduce the selector name from the method name.
112+- **What to do**: Declare a (possibly dummy) *external* category with the methods that you wish to call before using them. External category declarations will never result in any code being generated that requires the actual existence of this category somewhere, it merely tells the compiler that it should presume that those methods exist for the extended class.
113+
114+### Class extensions
115+
116+- **Description**: Class extensions are basically anonymous categories that are defined in .m rather than in .h files, with the difference that the compiler requires the methods of class extensions to be implemented in the current source file. The reason is that in Objective-C, it is not required to define whether a category is external. As a result, if a category is not implemented in the current source file, the compiler assumes that it is external and implemented somewhere else. If that is not the case and the implementation in the current source file was simply forgotten, then this will result in run time errors. In Objective-Pascal, an *objccategory* that is not declared as being external must be implemented in the current source file, so this problem does not occur here.
117+- **What to do**: You can use regular (non-external) categories defined in the implementation of a unit instead of class extensions, as the effect will be the same.
118+- **More Information**:
119+ - <http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW2>
120+
121+---
122+*From the Free Pascal wiki, page "FPC PasCocoa/Differences", as it stood on 2021-03-11 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
123+Category: Objective Pascal
124+Category: Objective-C
125+Category: macOS

Back to history