Version 2 (modified by ewing, 7 years ago)

add link

Objective-C and Objective-C++

On the mailing list, a general description of Objective-C and Objective-C++ was given (following the submission of osgsimpleviewerCocoa). This archive seems to have been lost, but the explanation has proven useful for those not familiar with the language. The original post has been recovered and placed here for reference. Additional information, follow-up posts, etc. are welcome on this page.


> Hi Eric,
>
> I know little about Objective-C++/C or Cocoa, so please excuse a few
> dumb questions from C++ land.

I understand that Obj-C and especially Obj-C++ fall outside of most
people's knowledge base. I only recently picked it up myself. I'm
still learning as I go (and as I try to pick up more of Lua as well).


So here's some background info to setup some context:

Objective-C was created in the early 1980's. It is not a new language
by far. It is heavily influenced by Smalltalk.

Objective-C can be described as the closest thing you can get to
Smalltalk in a C-based language.

Objective-C is a dynamic language (dynamic typing, dynamic binding,
dynamic loading). And Objective-C has strong support for introspection
and reflection.  In many respects, it is more comparable to languages
like Python or Ruby than to C++. The presence of these features is
felt in the fact that tools like Interface Builder or universal
generic undo support can exist. It also makes language bridges
relatively easy to create. On OS X, writing complete Cocoa apps in
Python is very viable. There is also a Ruby bridge which looks like it
is coming into maturity. I personally use a small bridge for some
things called the LuaObjCBridge. It is by no means as complete or
mature as the PyObjC bridge, but at the time, the entire binding was
under 1500 lines of code which I find impressively small.

Objective-C is a single inheritance language.

Objective-C supports Protocols (Java later called their feature Interfaces).

Objective-C supports Delegates (C# has them now)

Objective-C supports Categories, which allow you to add or override
methods in a class without subclassing it.

Because of Objective-C's dynamic typing, you don't have/need templates.

Objects in Objective-C must be created on the heap. So you always use
pointers to refer to objects.

Objective-C currently uses manual or semimanual reference counting for
objects (somewhat similar to osg::ref_ptr). OS X 10.5 Leopard is
introducing Objective-C 2.0 which includes automatic garbage
collection.

Objective-C is less susceptible to the fragile base class and fragile
binary class problems than C++. I heard this is partly why Apple
bought NeXT instead of BeOS (which was C++ based). (Java solved this
problem and this is another reason Microsoft needed to pick a new
language away from C++.)

Objective-C is a 100% superset of C. So anything that is valid C is
also valid Obj-C. (Contrast to C++, which is not a 100% superset of C
which has implications when combining C and C++ code.)

Objective-C is a relatively simple language with minimal extensions to
C. If you already know C or C++, you can learn most of Obj-C in a day.

Objective-C syntax is orthogonal to C and C++. Some complain about the
weird syntax, but this is also prevents clashes which allows
Objective-C++ to work. Typically new keywords are prefixed with @. And
the messaging syntax differs from a C++ method call.

Probably the hardest thing for C/C++ programmers to get over is the
messaging syntax. Keeping in mind that message passing has some subtle
implications over a function call, but ignoring that, the translation
is as follows:
// C++ style method call (example stolen from Wikipedia)
window.addNewControl("Title", 20, 50, 100, 50, true);

// Obj-C message
[window addNewControlWithTitle:@"Title"
                    xPosition:20
                    yPosition:50
                        width:100
                       height:50
                   drawingNow:YES];

Brackets denote the message. We send the message to the object 'window'.
Objective-C uses named parameters like the above (though parameter
order matters which some would argue are not 'true' named parameters).
It's more verbose, but it's self documenting.

(FYI, the @ symbol in front of the string "Title" tells the compiler
that it is a string that has all the Unicode goodness so it
internationalizes more easily than char*. It's one of those additional
syntax things to avoid C/C++ clashing.)


So Objective-C clearly lost the language war against C++ in the 80s
and 90s. However, there has been sort of a renaissance of late. People
have finally figured out that C++ isn't the best solution for all
problems. Dynamic languages like Perl, Python, Ruby, Lua, etc. have
come onto the scene demonstrating that C++'s type rigidness and
minimal introspection and reflection support are liabilities more than
assets for certain types of tasks. GUI programming is one of these
tasks. This is one of the reasons that Microsoft picked a new language
to base their stuff on (C#). They realized that they needed a language
that was more dynamic than C/C++. This is where Objective-C excels,
which is what NeXT realized way back over a decade ago. Objective-C
was the foundation for their GUI API because it offered both a clean
objected-oriented way to do things, but also because of the language's
dynamism. If somebody were to pick a new base language today to be the
basis of a new GUI framework, (not counting Microsoft), I suspect a
language like Python or Ruby would be the basis.


So what is Objective-C++?
Objective-C++ is a language extension that lets you put both
Objective-C and C++ code in the same file and interact. Before
Objective-C++, you would be forced to wrap stuff from both so they
communicate through their common denominator, C (well, almost common
denominator in C++'s case). Objective-C++ exists for convenience to
save the programmer time from having to do this extra work.

The philosophy behind Objective-C++ is "peaceful coexistence". The
designers wisely decided to avoid creating a monster of a language. So
they took the approach that you can mix the two languages, and you can
contain objects within the other language, but you can't subclass
between the two languages. So I can't take a C++ class, and make it
inherit from an Objective-C class or vice-versa. The obvious benefit
of this is that no new rules need to be invented and both C++ and
Obj-C objects behave identically as described in their fundamental
languages.

To convert objects, Objective-C++ does nothing here either. (This
somewhat follows the C++ minimalist philosophy.) The benefit of course
is that nothing strange has to happen. So if you do need to convert
objects, you do that manually. Since both languages can speak to C
(and primitive data types), this is the most obvious communication
layer. So for example, if you need to convert an std::string to an
NSString,, you get the char* representation from the std::string using
.c_str(), and then feed it to NSString.

So when you ask, how is this going to behave in Objective-C++, once
you factor in the "peaceful coexistence" philosophy, the answer is
pretty much, 'as you would expect'.


// Mixing Example:
// This example is a little bad because I really need to reference
count NSColor.
// I should be using something like osg::ref_ptr but for Obj-C objects
or should be
// explicitly retaining the objects.
std::vector<NSColor*> vector_of_colors;
list_of_colors.push_back([NSColor blueColor]);
list_of_colors.push_back([NSColor redColor]);
list_of_colors.push_back([NSColor greenColor]);


// Cpp class definition example with Obj-C stuff
class CppExample
{
public:
 void setColor(NSColor* the_color);
private:
 NSColor* someColor;
 std::vector<NSColor*> listOfColors;
};


// Obj-C class definition example with C++ stuff
@interface ObjCExample : NSObject
{
 // instance variables go inside the braces
 osg::Vec4 someColor;
 std::vector<NSColor*> listOfColors;
}
// methods go outside the braces, but before @end
- (void) setColor:(const osg::Vec4&)the_color;
@end


So finally to your questions:

* How do you integrate the Objective-C++ code into a C++ application?

So any file that has both C++ and Objective-C, you compile as
Objective-C++. (This is most easily accomplished by naming the file
extension as .mm.) If the file is just C++, then just compile as C++.
Conversely, if the file is Objective-C, just compile as Obj-C (.m).
The linker seems to just do the correct thing with all the object
files when you put them together.


* How do objects created  in Objective-C++ look/behave on the C++ side?

Exactly like C++



* How do C++ look/behave on the Objective-C++?

Exactly like C++



* When writing a cross platform app what do you do about managing code
between OSX specific pathways and more conventional C++ style widget
API?

* I am generally curious, and also interested from the perspective of
writing osgViewer, i.e. how do I keep the core code general purpose
enough to work cross platform easily, whilest still providing another
hooks/mechnansim to allow good native support.  Cocoa is quite unusual
when compared to the likes of Qt/WxWindows/Fox/MFX/X11 ;-)

So 'conventional C++' is a little loaded. I think NeXTSTEP predates
most of those libraries except for X11 which is C-based, right? And
certainly remember that Obj-C works better with C than C++ does being
that Obj-C is a pure superset. And wxWidgets looks like it copied MFC
as its design template. But I know what you're getting at.

Honestly, this isn't an area I have much experience in. I usually come
from the other direction or use a toolkit that already implemented
this. The problem I found with the cross-platform kits out there is
that at best they are Windows centric. This usually results in a very
poor user experience on the Mac. Often they stick out like a sore
thumb and don't support functionality that Mac users consider
basic/fundamental (drag-and-drop, copy/paste, proper keyboard
shortcuts, services, etc). So my approach has been what we've done
with the simpleviewers like osgsimpleviewerGLUT/SDL/Cocoa. In my
stuff, all the core/cross-platform functionality is at the lowest
level, and then I build platform specific layers on top. But I will
try to suggest some ideas here.

Specifically with C++, I would try to isolate the C++ and Obj-C code
as much as possible. You can do this pretty much the same way you
would shelter C and C++ from each other. In the C/C++ case, basically
in header files that need to be included by both, make sure the header
is C clean. What you do in the implementation files is open season.
Void pointers and forward declarations can help keep headers clean.
For Obj-C/C++, you probably want to try to make headers C++ clean (or
C clean). Forward declarations and/or void pointers can help here too
in C++ class definitions that need to hold members to Obj-C members. I
document this a little bit in my header file for simpleviewerCocoa.

So the multiple inheritance technique in the Qt viewer example worries
me because I don't think that's going to fly with Objective-C or any
non C++ language. In the Objective-C/Cocoa case, the NSView
Objective-C class instance will receive the events. You can't subclass
a C++ class from a Obj-C class. So the only policy is some kind of
containment.

Maybe another example to consider is how one would implement the
viewer for GTK+ through the C API. How would one approach GTK
integration in this case? And then I also wonder about people using
language bindings such as Java, C#, Python, Ruby, etc. These languages
don't support multiple inheritance. Anyway, if we can come up with a
good design that gets around the inheritance requirement, may there is
a chance that it will solve the problem with Cocoa/Obj-C.

Or maybe GLUT is the model to look at? It is already cross platform
and provides native back ends for different platforms. It uses Cocoa
on Mac. Source code is open.

I hope this is helpful.
-Eric

Additional References

See Mac OS X Tips and Tricks for more information/videos on getting started with Mac OS X and Xcode.