Bogo Giertler and Alec Oot
What is Objective-C?
Objective-C is a powerful, reflective, object-oriented programming language that is a strict superset of classic C, extending it with Smalltalk-derived messaging style. In works from early 1980s, it appeared first in 1986, when Brad Cox published his seminal Object-Oriented Programming, An Evolutionary Approach, which addressed the problem of true reusability of code and provided the main description of the language. De facto, the reason for which Objective-C was created, was the fact that Smalltalk - while able to address the most of engineering issues related to OOP - required to be run in the virtual machine. All Smalltalk development tools had to be run within the virtual machine as well. While some of the most complex systems in the world were developed in Smalltalk, the environment required huge amounts of memory and processing power to run efficiently. Therefore, simply extending already popular C with some of Smalltalk functionality seemed to be the best option.
As in 1988, the C++ (official C with classes) was far from being standardized and widely used, the company found by then laid-off Steve Jobs, NeXT decided to license Objective-C from StepStone (the Cox company) and soon thereafter released its own Objective-C compiler and set of libraries used to create the NeXTstep user interface. As NeXT software development tools and the OpenStep API were widely acclaimed, the GNU project decided to create a free clone of NeXTstep, known as GNUstep and extend the functionality of GNU C Compiler (gcc) with the Objective-C libraries and runtimes.
Upon acquiring NeXT by Apple Inc., Apple decided to use OpenStep and NeXTstep as a foundation for its new operating system, Mac OS X. Therefore Objective-C was used for most development, Cocoa API was derived from OpenStep, and NeXTstep tools, Project Builder (later redone and renamed Xcode) and Interface Builder were bundled with OS X for native development.
Nowadays, most of Objective-C development happens in-house, with Apple making strategic decisions on modifying and extending the language functionality. While gcc compiler happily works with Objective-C code, the fact Objective-C is virtually only used for iPhone and Mac OS X programming, makes it closely intertwined with the Foundation and Cocoa frameworks, therefore making it truly usable only on OS X platform.
The most recent release of the language is Objective-C 2.0, that was announced together with Mac OS X 10.5 Leopard in 2006. Numerous fixes were announced together with Mac OS X 10.6 Snow Leopard in 2009. However, these changes were not included yet in the GNU runtime, and it is not known whether they will be implemented or available in the same way they are in Apple's implementation. Furthermore, certain functions of desktop Objective-C are unavailable on the mobile Objective-C (for iPhone
Identifier naming, variable declarations and identifier scoping
Since Objective-C, as a strict superset, is fully compatible with C, all basic rules of variable declaration are carried over from the original language. This means, that Objective-C has four primitive data types - int, float, double, and char. The language supports also five C qualifiers - long, long long, short, unsigned, and signed. It also allows the programmer to declare certain variables as static. However, for the sake of formal compatibility, Objective-C introduces also a primitive type known as id, which is basically a container for an object of any type, a type that enables Objective-C to be fully polymorphic and dynamically binding.
Furthermore, in Objective-C any number, single character, or character string is known as a constant. It is an important concept, as it defines the true nature of an Objective-C variable as a storage of constants and allows for defining a variable as constant from within the variable value. (by appending certain chars at the end of it - it is however beyond the scope of this introduction, and we suggest referring to Programming in Objective-C 2.0 for more information on this functionality) It is therefore impossible for any program to modify it character strings other then by preprocessor automatic string concatenation (i.e. @"this" @"is" @"a" @"string" is converted by the compiler into @"this is a string")
The C primitives are further expanded by additional _Complex, _Imaginary (part of complex.h header) and _Bool types. The _Bool exists as a separate type, but _Complex has to exist as a union of a data type and _Imaginary (as will be presented in an example). Automatic conversion does not occur between these two. creal and cimag functions from the complex.h header can be later used to extract the real and imaginary parts respectively.
Objective-C also allows for all ANSI C data structures, unions, type definitions, etc. However, many of these has already better (or more suitably to the language) implemented, Smalltalk-derived solutions.
The variable declaration form follows what is known from C++:
Objective-C is at the same time a static, dynamic and weakly typed. Its primitives are static types, while the dynamic typing occurs with classes and data passed there. The data is weakly typed to allow for easier dynamic typing, as Objective-C handles automatically both the incoming messages and allows for dynamic conversions without users input.
If any dynamic type is used, it most probably is part of the Foundation or Cocoa libraries. As such, its name will be preceded by NS (a homage to NeXTstep, the platform from where Cocoa stems). Most of the classes in Cocoa, and in general, are an extension of the most generic object type NSObject. The reason for NSObject existence is to the programmer with easy and generic way of answering the system calls (i.e. freeing). Using NSObject as a root class to inherit from, allows for usage of any possible updates to NSObject to come during language evolution.
The power of Objective-C comes from its method of managing the classes. While the first class call might take up to 3 times as much, as the C++ class call would (since everything regarding classes in Objective-C is dynamic), the later results are cached, what allows at least a 50% increase in subsequent class calls then in C++. Classes are declared and implemented in two files, .m and .h, being parallel to C's .c and .h. The following example implements a fraction class, with its basic methods.
While Objective-C is based on C (therefore giving a fairly free hand to programmer in respect to naming), the principles of naming were derived during the language usage by NeXT and Apple engineers. It is by this tradition, that the function names are written in the camel notation (thisIsTheName) and classes have capitalized name (Fraction).
Objective-C 2.0 was updated to support Unicode, therefore, at least theoretically, a UTF-16 enabled source might contain character constants and variable names written in other encoding pages then ASCII.
Certain names for variables are not allowed, as they have specific meaning within Objective-C (keywords). These words are words like for, goto, int. Also _
Compiler directives in Objective-C are to be explicitly preceded by the @ sign. This is used to denote classes or objects, so for example:
Class methods are marked by + sign, instances methods by - sign. This paradigm is kept throughout the implementation section as well.
Idea of the variable scope is exactly the same one as of C. The most local symbol table is searched first, and then step-by-step, the tables in preceding scopes, until the outermost (global) is hit. The occlusion and variable hiding are all allowed techniques in Objective-C. The variables can be defined as constants, statics and globals, depending on programmers choice.
If the variable passed to a class is of the same name, as class' internal variable, the keyword self. is used to clarify what variable we are referring to at the moment. (self being the classes own)
Scopes for classes variables split into three ways - @private, @protected, and @public. Variables declared as @private are available only to the class itself. None of its subclasses can access them. @protected is default mode, in which instance methods in the class, instance methods in subclasses, and instance methods in category extensions to the class can reference the variable. @public allows for all of @protected functionality, plus allows a direct referral by the means of the arrow (instance->variable). Apple discourages the usage of public, as it defies the notion of data encapsulation that is principal to the object oriented programming.
Using previously defined ...
Due to Objective-C nature, the most basic binary search function could be implemented in the exactly same manner one would to it in ANSI C. However, using the classes and messages, we might better present the language itself (what might be an overkill for binary search - oh, well).
The code should be understandable from get-go. De facto, we wrapped a very typical C code with Objective-C classes and methods. Objective-C actually contains appropriate library features (like dictionaries and lists), that could be managed from within the program specifically, without the need for pointer arithmetic, etc. However, as can be seen, it is entirely possible to wrap C code for proper usage in Objective-C.
The state of a program provides information on the current values of the different variables that are being stored. By developing a language that follows a Action: state --> state model, it becomes much easier to define exactly what will happen to the program when any given call or operation is made.
I have designed a simple program class that has self.state which is the programs state and it keeps track of all of the variables that are needed.
I have redone this simulator so that a state is returned by each operation. This allows you to see the state of the program as it moves along. Here is the output of my simulator
File I/O and Exception Handling
Language SupportThe language contains a built-in support for both input and output. Therefore, the program below solely, without any import statements, will provide exception-free input of integer into a variable and print it out. It uses Cocoa-derived NSLog for printing out to the log device (that can be equally well a file, and a screen), but uses C scanf for obtaining letters from Terminal. As far as my knowledge goes, printf, would be also an appropriate way of printing values to the screen, and Cocoa does not have a separate input class, as Cocoa/Foundation tools mostly relay on Graphical User Interfaces that handle user input differently.
The output for above code will be (if input 1 when prompted):
However, while all of this looks very fine, it has to be noted, that definitions of this functions are part of the Foundation and during the compilation, the compiler will throw a warning, that in C would mean, that an exception is to be expected on run-time.
The output file runs fine however. This might be due to the language preprocessor, that imports appropriate libraries for runtime. I cannot check this against documentation however. Therefore, to not risk incompatibilities between implementations, importing the Foundation library is recommended in the way as follows (note, that Objective-C uses import instead of C _include):
File InterpretationFile support in Objective-C is handled in twofold way. One is derived directly from C (deprecated), the other one relies on the NSFileManager/NSFileHandle classes in Foundation framework. NSFileManager allows a full access to the filesystem and carrying out the following operations:
- Create a new file
- Read from an existing file
- Write data to a file
- Rename a file
- Remove (delete) a file
- Test for the existence of a file
- Determine the size of a file as well as other attributes
- Make a copy of a file
- Test two files to see whether their contents are equal
While NSFileHandle allows to:
- Open a file for reading, writing, or updating (reading and writing)
- Seek to a specified position within a file
- Read or write a specified number of bytes from and to a file
Many operations are defined directly from within particular Foundation libraries regarding variables. For example, the code for printing out file's contents to the screen is:
As we see here, no operation with file handlers are required. Instead we might just want to select a file using FileManager and store its path in a variable like fName.
This convolutes slightly the usage of language, as in the longer run, it requires one to create and remember numerous class methods for handling the input, if a large flexibility is required. However, certain ways of circumventing this can be applied (i.e. reading the file into a string and then parsing it with parsers built-in Objective-C).
For binary files (or, basically, any files), Objective-C supplies class known as NSData, that is a storage method for various files read from hard drive. On 32-bit systems NSData variable can be 2 GB large at max, on 64-bit systems it is 8 EB.
User InputAs aforementioned, Objective-C allows for interactive data input from the user using scanf, as well as Graphical User Interface in more advanced applications.
Objective-C supports two ways of throwing and catching exceptions. (of course) A C way, and an Objective-C way (of course). The C way is deprecated, and Apple calls for using the classes to throw exceptions (which can be observed by the keywords preceeded by @ sign), so they can be caught by the specialized debugging software called Instruments. (of course).
To throw an exception you must instantiate an object with the appropriate information, such as the exception name and the reason it was thrown. This is done in the following way, using typical long function calls. The NSException class can be, of course, extended by inheritance into ones own class, i.e. used in later example CustomException)
Throwing an exception follows the familiar Python/Ruby style with trying, catches and final clauses:
- Code that can potentially throw an exception is enclosed in a @try block.
- A @catch() block contains exception-handling logic for exceptions thrown in a @try block. You can have multiple @catch() blocks to catch different types of exception.
- A @finally block contains code that must be executed whether an exception is thrown or not.
You use the @throw directive to throw an exception, which is essentially an Objective-C object. You typically use an NSException object, but are not required to.
Multiple types of exceptions can be caught using the sequences of catches:
2. For each of your languages, create some example programs that demonstrate error and exception handling. Some things to consider in your examples and writeup include the following.
- Does your language have built-in support for exception handling? If so, what are the controls structures and how do they work?
- Are there conventions for how functions report errors? If so, what are they?
- What are common errors in your language, and what do they mean? What went wrong?
Functions and Memory Management
Syntax of a function definition
- Original function definition follows the exact scheme that is implemented in every C program. However, this style is frowned upon and deprecated for most of the uses - classes-methods are recommended as a usage for anything remotely resembling data manipulation.
- The syntax of class method was derived from Smalltalk, with certain C influences. There is no type checking when arguments are copied to parameters.
- Here is a simple example, reusing a snippet of code written for the binary search. As mentioned before, the header of definition is of -/+ (type) name scheme, where - is instance method, and + is class method.
- According to Apple, the vast majority of objects available in Objective-C is being passed by reference. However, if passing by copy is required in certain circumstances, this can be invoked by preceding the variable type with keyword bycopy.
Syntax of a function call
- What differs Objective-C from most of the Simula/ALGOL descendants (like C and C++) is the way the calls to the objects are carried out. A standard syntax for calling a function is
- Since very often the object itself is returned as a part of the method, it allows for nesting of multiple calls, as in the exemplary initialization of the class (the init class method comes from the root class of NSObject through inheritance). This also allows for including many method calls as expressions into the code - the same applies to assignments as well. Which is roughly:
- Numerous calls to methods can be chained together, in a way of:
- An interesting feature in Objective-C, is that if an incompatible value or invalid method call will be passed into the class instance from outside, (e.g. calling the method with wrong variable or inexistent method), it will be ignored. This is used throughout Foundation, in AwakeFromNIB class call (executed after opening the new GUI on screen, as GUIs are packed into NIB files in Cocoa). By default, this call has no significance to most of the classes.
- Also, similarly to Java (Obj-C was a strong influence on its development), multiple methods with the same names can be created and used for calls. Selection of proper one is done based on the types and number of variables coming in.
- Depending on the function under consideration, side-effect might or might not occur. Certain methods will create its separate dictionaries that will be discarded at the end of execution, therefore not affecting directly the state in the longer run. For example, NSLog does not have influence on the state (i.e. no side effects), while assignment statement for strings does, especially since in Objective-C it involves discarding the previous string and replacing it with the new object.
- As the language is pass by reference (mostly), editing the passed objects will often cause the change in state.
- Based on chapter 10 of Noonan/Tucker, the Function could be denotationally represented as
Objective-C also provides the programmer with tools to do garbage collection. To turn on the garbage collector in X-Code you can set a flag in the GCC compiler options or you can add the
When this flag is set, Objective-C will keep track of all 'reachable' objects. An Object is said to be reachable if it can be accessed via a pointer. Memory that had been allocated for storage but no is not 'reachable' will be marked as 'free' when the garbage collector checks references. This will allow this space to be used to store new information.
Garbage collection will run automatically but it can be manually initialized by creating a NSGarbageCollector Object and executing its 'collectIfNeeded' method. Here is an example:
Code handles memory on its own will compile correctly with garbage collection enabled and will actually completely ignore all calls to 'autorelase', 'release' or 'dealloc', leaving these responsibilities to the GC.
Garbage collection is a very nice tool to help programmers avoid memory leaks and helps the programmer take their focus away from memory management. Garbage collection is not available for the iPhone yet.