Type Systems in Objective-C and C++

Objective-C offers a few advantages compared to programs written in pure C or C++. For example, with Objective-C you are have access to a comprehensive library that can handle most program-ming tasks on desktop or mobile applications.

On the other hand, if you’re used to C++ style of programming it does take some time to get used to Objective-C. It is necessary to realize, for example, that Objective-C requires a different way of thinking about software development when compared to other languages. For one, in Objective-C you have to get used to make programming decisions that will be performed at run time.

But I would say that most of that time is spent on good surprises. After all, Objective-C follows more closely the path traced by the OOP paradigm, while C++ is fond of the many compromises for the sake of pure performance. After using the language for a while it may even be hard to go back to the C++ way of doing things — with all its nasty problems and the huge amount of work involved with exception handling, for example.

And the good news is that, although Objective-C is the language used by Apple, it is also a standard and available through GCC in most modern platforms. Therefore, even if you’re developing for Windows you could still use Objective-C in new projects. Of course you will have to do some fighting the system if your program is in C++. This is the main reason why some people with large codebases avoid this route, but it might be a good idea if you’re starting a new project from scratch.

Relaxed Type System

Across the many features provides by Objective-C, what stands out in the first place is that it provides a nice departure from strong static compilation, the hallmark of programming languages such as C++ and Java. Static compilation has some advantages, but its problem is that it requires the programmer to determine a lot of de-tails even before the program can be compiled into an executable. For example, a C++ programmer has to come up with a class hierarchy or a set of templates that represent the software. Once this is done, they have to stick with the consequences of these decisions.

On the other side, Objective-C allows programmers to create code with less formal requirement from the beginning. For example, classes can just extend NSObject after the fact, using mechanisms such as extension protocols. In fact, Apple has consistently done this with classes such as NSString, which is extended to handle more responsibility as new frameworks are loaded.

About the Author

Carlos Oliveira is the author of Objective-C Programmers Reference.

Related Books

Here are some other books on this topic:

Programming in Objective-C

Objective-C Programming

Dynamic Features in Objective-C

Programmers that use the C and C++ languages have become used to the facility with which they can access low-level features such as memory management. The raw speed of the language is another point that makes it very hard to use other languages. On the other hand, most programming environments are nowadays organized according to object-oriented principles. It definitely makes sense to have a language capable of enable some of the features of OOP in an organized way.

With this goal in mind, Objective-C has a sane way to introduce object orientation principles to the C world. Unlike C++, which sometimes tries to extend the C model to places it shouldn’t be, Ob-jective-C just adds a new language on top of the original C. By the way, that’s why Objective-C can be used simultaneously with both with C and C++ (if you really need it).

Distinctive Features of Objective-C

First of all, unlike in C++, the object-oriented part of Objective-C is dynamically typed. You can still use types to get auto comple-tion and compilation warns when you called the wrong method, but in reality you could just use the generic id type everywhere.

The real type of an object is determined at execution through the run-time system. This way, you can send any message to any object, and it will respond based on what it knows about the message. That is why it is so easy to use duck-type on Objective-C: if you want to act as a specific object, just respond to the messages it is expecting.

The run-time system is very well thought out. If you use only standard C you get the same speed of normal C programs. If you use objects, then you will depend on the run time system as described above, but that happen only when you want or need. In Objective-C there are no delusions that you can do proper object oriented programming without a run-time system, as in C++. You will get help from the type system when needed, but if you don’t want help, the language just gets out of the way!

Because of the dynamic nature of the run time system, one can easily use designs that are simpler then in other languages. For example, objective-C libraries use a lot of delegation. The reason is that it is really easy to use. Instead of declaring a new type to inherit from another (something you required to do a lot in Java, for example), you can just supply an object that implements the required methods. The type of the supplied object is not important – any type will do. This is why model-view-controller really works in Objective-C. The controller can be the delegate for UI objects as well as model objects. There is no need for the overhead of multiple objects deriving from others just to supply a small feature.

Isolating Dependencies in C++ Code

When working in C++, one of the main problems is the complexity of interfaces. The constant use of header files in the language make it difficult to avoid the inflation of translation unit sizes – a single file can include dozens of headers, which can do the same recursively. As a result, even small source files can take a long time to compile.

The issue becomes even more pronounced when you consider templates. The fact that they need to be textually included when invoked in a source file has consequences for the size of the translation units. In the end they just add even more to the amount of work the compiler needs to complete for each translation unit.

There are some techniques, however, that can be valuable in overcoming these issues. One particular technique that I use frequently is avoiding direct dependencies on external libraries in my source files. This technique may be hard to use in some situations, but for smaller libraries it works really well.

Minimizing Dependencies

The idea is that you don’t need to include directly the header file of a third-party library in you code. Instead, you can create a single source file that includes the library’s header file – and then create you own classes or functions that export the functionality to the rest of the application.

For example, when using a compression library, instead of adding the header file from the third party vendor, I just create a new pair of source file and a header file:

  • compress.cpp and
  • compress.h

The first file includes the external header. The last one provides a simple interface that I will use in the rest of the source code. This has a number of advantages:

  • The dependency is centralized. If, in the future I need to use another library, I will just need o change one source file. Everything else will compile correctly because I control the code.
  • The interface is easy to use. Since I am the creator of the simple interface in the header file,  I will add only the functionality that matters, and nothing else.
  • The interface is small. As you are including the external header file only once, this will reduce your total compilation time. Your local interface will have only the small number of elements that you really need.

Creating simple interfaces can make your life much easier, and reduce maintenance risks. It is a win-win scenario for developers, since this can reduce compilation times, and minimize future integration costs.