Showing posts with label Objective-C. Show all posts
Showing posts with label Objective-C. Show all posts

Sunday, November 22, 2009

How does Go fit in with the C-family of languages

The C-family of languages is a pretty large group. It could be discussed which language is fit and which don't but I think it's worthwhile including the languages: C, C++, Objective-C, Java, D, C#.

First we got C++ which is trying to extend C into an object oriented language by taking inspiration from Simula. And then came Objective-C which took a more dynamic approach to object oriented programming and tried essentially to embed smalltalk in to C.

Years later we got Java which try to retain the simplicity of Objective-C compare to C++ but give it a more C++ looking syntax. C# tried to create better Java by using the basic ideas of Java but allow more the power of C++.

And right in the middle there comes D and tries to be what C++ should have been, or rather could have been if we could throw the nasty bits out.

A lot has been centered around C++, and I feel Go is about going back to the roots. Go feels a lot more like C:

  • Fairly simple and clean language. Compared to C++ with its huge feature list
  • No inheritance
  • No classes
  • No constructors and destructors. No RAII
  • You just allocate structs. No code is run like on C++. Like C you have to create separate initialization functions
  • The standard library is very similar to the C standard library. The way you deal with IO, strings etc, feel much more like C than C++
  • In C++ structs are not just simple structs. They can contain invisible fields you didn't explicitly put there like a vtable. In Go structs are just like C structs. There is no vtable

Unlike Java and C# there is no virtual machine. However like those and unlike C++ if a crash happens you are not left in the cold. You get a stack backtrace on the console. In this respect Go is more in the C++ and D camp than in the Java and C# camp. While Java, C# and D have been about trying to keep the basic ideas from C++ and fix them, Go seems to be more about getting duck typing like found in languages like Python, Ruby into the C-family. Or perhaps one could say the designer skipped the whole class and inheritance thing and looked at all the great stuff done with C++ templates which essentially gives compile time duck typing and decided that was a model on to witch Go's dynamic dispatch should be built on

Benefits of Go's interface type

Go doesn't use inheritance but achieve much the same through interfaces. However interfaces have some benefits over the traditional approach I'd like to highlight. Below I am showing two code examples illustrating a struct or class B with a corresponding interface name A.
 struct A {
   virtual int alfa(int a) = 0;
   virtual int beta(int b) = 0;  
 };

 struct B : public A {
   int alfa(int a);  
   int beta(int b);  
   int d;
 };

 int B::alfa(int a) {
  return d + a;
 }

 int B::beta(int b) {
  return d + b + 3;
 }
Below is the Go version of the code above:
 type A interface {
  alfa(a int) int;
  beta(b int) int;
 }

 type B struct {
  d int;
 }

 func (m B) alfa(a int) int {
  return m.d + a;
 }

 func (m B) beta(b int) int {
  return m.d + b + 3;
 }
In C++ we can call the methods defined on the struct B through its interface A like this:
 int x, y;
 B b;
 b.d = 3;
 A *a = &b;

 x = a->alfa(1);
 y = a->beta(2);
Likewise in Go:
 var x, y int;
 b := B{3};
 var a A = b;
 x = a.alfa(1);
 y = a.beta(2);
On the surface this looks very similar but there are some notable differences. In C++ the inheritance hierarchy can be arbitrarily deep and so dynamic dispatch is dependent on traversing a vtable on a class to its superclass on so on until the correct implementation is found. In Go there is no inheritance tree, so each method will be accessed as if a single function pointer. In this way Go is more similar to how you typically create some kind of polymorphism in C. In C it is common to define structs with lists of function pointers, which are changed depending on type etc. The other difference is that if you change the code on Go to this:
 var x, y int;
 b := B{3};
 x = b.alfa(1);
 y = b.beta(2);
Then the calls are resolved statically. There is no function pointer lookup, simply because there are no virtual functions in Go. If you call a method on a struct in Go, the compiler knows exactly what method you are calling. However if you change the code in C++ likewise, you are still making a virtual method call. To be fair in some cases the compiler can figure out the right method call. But the bp pointer could have been passed around and you can't know if it points to a subclass of B or not. With Go, this problem doesn't exist since structs don't have subclasses, making the job much easier for the compiler.
 int x, y;
 B b;
 b.d = 3;
 B *bp = &b;

 x = bp->alfa(1);
 y = bp->beta(2);

Better consistency in type system

Having methods on structs be statically resolved also makes it trivial to support methods on basic types like ints and floats. Something which isn't possible in C++ or Java. The reason that isn't possible is because ints and floats don't have vtables. While in Go you don't need a vtable to have methods, so it is not a problem. In my view this blurs the distinction between basic types like ints and objects which are e.g. in Java two clearly different things. That is a good thing since it creates better consistency. There are less special cases.

How to deal with missing features in Go

A lot of people will probably complain about all those C++ not found in Go. E.g. without constructors and destructors how does one handle resources safely through RAII? Go doesn't really need RAII because it has closures. That is used extensively in e.g. Ruby to get the same benefits. E.g. here is some code I wrote that opens a file, reads one line at a time and closes the file.
 ReadLines("struct-template.h", func(line string) {
  fmt.Printf(doStuffWithLine(line));
 })
The ReadLines function was implemented like this:
 func ReadLines(file_name string, fn func(line string)) {
  file, err := os.Open(file_name, os.O_RDONLY, 0);
  defer file.Close();
     if file == nil {
      fmt.Printf("can't open file; err=%s\n",  err.String());
      os.Exit(1);
     }

  in := bufio.NewReader(file);
  for s, err := in.ReadString('\n'); err != os.EOF; s, err = in.ReadString('\n') {
   fn(s)
  }  
 }
Which shows another way to deal with RAII. One can use defer which will call method after defer when function goes out of scope. Exceptions are not present in Go either but you can mimic the kind of error handling you do with exceptions by using multiple return values were one signals error and use the named return value feature.
 func ProcessFile(file_name string) (err os.Error) {
  file, err := os.Open(file_name, os.O_RDONLY, 0);
  // ...
  return;
 }
In the simple example above err will automatically be bound to the return value. So if the function didn't handle the error returned in err it will be automatically propagated to the calling function.

First impressions from the Go programming language

I spent the last week or so learning the new programming language release from Google called Go. The first program I written this a simple text processing tool. That is the kind of tools I've previously written in Python and Ruby. I would say that Python is still better suited for this kind of job. However that is mainly due to less functional regular expressions and string libraries found in Go. Although it is unavoidable that when using a statically typed language there is a bit more overhead. In particular with respect to typing.

Compared to regular statically typed languages

However for a statically typed language I can't find anything that can compare. I could write code in a manner to remind me a lot of how it feels to write code and script language. Other languages which I'm familiar with like C++, Objective-C, Java are much more verbose and clunky to use. Those are languages which encourage much more planning and feels better suited for larger applications.

C is a simple language but it lack so much features that it becomes cumbersome to do string processing. No string class and a bit too code spent managing memory.

Compared to Haskell and C#

Of course there are other statically typed languages like Haskell and C#. Now Haskell is probably a more innovative and elegant language then Go. But it is also the language requires much more understanding before it can be used productively. Most developers are not intimate with the functional languages. Especially pure functional languages like Haskell. With Go on the other hand I could use the skills I had developed while using languages like Python, C++ and C. That meant I could be productive quite quickly. With a sharp unafraid to comment because so much has happened without language to last year's and I haven't used in years. I know at least that the C# that I used to use could not compete with Go in ease-of-use.

Compared to Scheme

I have written text processing utility and scheme previously. The whole development process is nicer than most other languages I think. Mainly because of the interactive style development that scheme allows. I could quickly and easily test segments of my code in the interactive shell because everything in scheme is an expression. In this respect go is as cumbersome as any other traditional language. You run test your program one file at a time.

Of course came that same problem as Haskell. You can easily reuse programming skills developed while using C and C++ for many years. It's cumbersome to get used to reading scheme code that takes time to get used to what functions are called and how to print special characters like newline etc.

Wednesday, September 12, 2007

Why Objective-C is cool

I've been asked to do an intro about Cocoa. So I thought about what would I tell people about Cocoa if I had some time. Sure I could throw up a quick tutorial on how to code a Cocoa app showing a bare minimum of how Objective-C works. But there are a million of tutorials like that and it doesn't really do the Cocoa justice. I want to give people an idea of why Cocoa or perhaps more specifically Objective-C is cool. I think anybody who has played computer games to some extent know how the game Doom (1993) from id software revolutionized gaming on the PC platform. What few people know was the the game was actually not developed at the PC platform at all. At the time Doom was developed in 1992, Windows 95 didn't exist yet and software development on PC's looked like this: Not very impressive. Instead it was developed on computers from NextStep, the company founded by Steven Jobs after he was kicked out of Apple. As id developer John Romero says:
Why do I care so much about NeXT computers? Because we at id Software developed the groundbreaking titles DOOM and Quake on the NeXTSTEP 3.3 OS running on a variety of hardware for about 4 years. I still remember the wonderful time I had coding DoomEd and QuakeEd in Objective-C; there was nothing like it before and there still is no environment quite like it even today.
To get an impression of how far ahead of its time Objective-C and what is now known as Cocoa was ahead of its time, consider this:
In fact, with the superpower of NeXTSTEP, one of the earliest incarnations of DoomEd had Carmack in his office, me in my office, DoomEd running on both our computers and both of us editing one map together at the same time. I could see John moving entities around on my screen as I drew new walls. Shared memory spaces and distributed objects. Pure magic.
Consider how long time ago that was, CORBA didn't support C++ for remote method invokation until 1996. At the time id did this it was just in its infant stage. Not to mention this was long long before Java RMI made remote objects populare and mainstream. It isn't even common to do this kind of thing today, and yet this was something that was quite trivial to do in Objective-C and Cocoa back in 1992.

Introducing Objective-C

Every time someone introduce you to Objective-C they will tell you about what a small and simple language it is. How easy it is to learn etc. But that was not my impression when I first tried to learn it. At the time I knew C++. When I saw an example of how to declare a class:
@interface MyClass : NSObject
{
  int         mSomeNumber;
  NSString*   mSomeString;
}

- (int)someNumber;
- (void)setSomeNumber:(int)aNum;
@end
I didn't think it looked easy or simple at all. Especially when I saw some code examples:
- (void)drawRect:(NSRect)frameRect
{
  // Fill whole background with white
  [[NSColor whiteColor] set];
  [NSBezierPath fillRect:frameRect];

  // Construct rows of lines
  NSBezierPath *gridLines = [[NSBezierPath alloc] init];
  for (unsigned row = 0; row <= mNoRows; ++row) {
      [gridLines moveToPoint: rowLeft];        
      [gridLines lineToPoint: rowRight];
      rowLeft.y  += rowHeight;
      rowRight.y += rowHeight;            
  }        

  // Set style to draw line in
  [[NSColor blackColor] set];
  [gridLines setLineCapStyle:NSSquareLineCapStyle];
  
  float pattern[2]  = {2.0f, 5.0f};
  [gridLines setLineDash:pattern count:2 phase:0.0f];

  // Draw specified lines in given style
  [gridLines stroke];
  [gridLines release];    
}
The code below is just to give an idea of what Objective-C syntax is like. What the code does is not important. It has been simplified a bit to understand better. It basically draws several rows with black lines on a white background. When I first saw this kind of code I didn't think it looked easy at all. And I thought whoever said that Objective-C was a much simpler language than C++ must have been smoking something that wasn't good for them. The problem was that I was too caught up in the syntax. The syntax is indeed very unusual, but if one looks beyond that, the structure of the syntax is actually quite simple. Perhaps the best way to understand the syntax is to understand, why it looks so strange.

Background

Unlike C++, Objective-C wasn't really a new language at all originally. There was no Objective-C compiler. Instead Objective-C was just plain old C, with an added preprocessor. As any C/C++ developer worth his/her salt should know all statements starting with # specifies a preprocessor directive in C/C++. E.g. #define and #include. The preprocessor runs before the compiler and replaces the directives with actual C/C++ code. What the makers of Objective-C did was to add another preprocessor, but instead of marking the directives with #, they marked them with @. That way their special preprocessor could find all the new directives easily. While this does make Objective-C look like some alien entity inside C, it does make it trivial to distinguish between pure C code and the add-ons from Objective-C. Unlike C++, where what is C and what is C++ is blurred. Actually C++ isn't a strict superset of C like Objective-C although it usually compiles C code. The reason being among other things that C++ reinterprets a lot of regular C code into new C++ concepts. E.g. a struct isn't just a struct anymore but actually a class in C++.

Syntax inspiration from smalltalk

The second stumble block in order to understand Objective-C syntax is to realize it is derived from Smalltalk, while C/C++ syntax is derived from Algol. Algol based languages separate arguments with comma, while smalltalk separates with name of argument and colon. Below is a code snippet that demonstrates setting the position and dimension of a rectangle object.
// Smalltalk
rectangle setX: 10 y: 10 width: 20 height: 20

// Objective-C
[rectangle setX: 10 y: 10 width: 20 height: 20];
[rectangle setX1: 10 y1: 10 x2: 20 y2: 20];

// C++
rectangle->set(10, 10, 20, 20);
The Smalltalk/Objective-C syntax improves readability of code. When specifying a rectangle some libraries use the start and end coordinates while others use start coordinates and size. With Smalltalk/Objective-C it is made quite clear what is done. While with C++ it is not clear whether the first or the second line of Objective-C code is used. Unlike Smalltalk Objective-C methods are called by enclosing call with []. This was originally to aid the preprocessor in extracting what was regular C code and what was Objective-C specific code.

A small and simple language

What do we exactly mean by saying that Objective-C is a small an simple language. C++ looks simpler syntax wise for the novice. However as said before syntax in deceiving. C++ add a host of new features to the C language: classes, virtual methods, non-virtual methods, constness, templates, friend classes, multiple inheritance, pure virtual functions, operator overloading, function overloading, private, public and protected members, constructors etc. Objective-C on the other hand add very little, it is just classes, methods, categories and protocols. There is only one way to create classes and to inherit form them. You can specify whether inheritance is public or private e.g. There is only one kind of methods. There is no distinction between virtual and non-virtual. They can't be const or not const. The concept of constructors and destructors don't exist. Instead these are just normal methods. As mentioned Objective-C is so simple they didn't even need to create a new compiler. A preprocessor was enough. This can make Objective-C seem overly simple. How can you do much with a language like that? The answer is the Objective-C runtime. The runtime is in fact what makes most of the Objective-C magic happen. Most of Objective-Cs features is provided at runtime and not done at compile time.

Methods and Selectors

Objective-C differs from C++ in that one distinguish between methods and selectors. To call a method on an Objective-C method you send a message. The method is not called directly. Instead Objective-C determines based on the selector which method to call. Conceptually one can think of a message (selector) as simply a string with a list of arguments. The code below e.g. send the message setX:y:width:height: to object rectangle. This will invoke a method on rectangle if it understands the message.
[rectangle setX: 10 y: 10 width: 20 height: 20];
If we think of Objective-C as just a preprocessor as it originally was, all message sending is replaced with a call to a C function:
id objc_msgSend(id theReceiver, SEL theSelector, ...)
So when the preprocessor encounters our rectangle message it is translated into something like this:
objc_msgSend(rectangle, "setX:y:width:height:", 10, 10, 20, 20);
objc_msgSend queries rectangle for its class and then queries the class for methods it contains. Then it finds out which method corresponds to the given selector. The method is nothing but a function pointer of the form:
id (*IMP)(id, SEL, ...)
Of course this is a simplified explanation. In reality every selector is registered. Meaning we don't pass newly created strings to objc_msgSend each time we invoke a method but a pointer to a string. This pointer has to be unique. So we can't pass any string pointer. So if we got å string we can find the unique pointer to this string by using the function:
sel_registerName(const char *str)
Which returns the pointer if it exist or registers the selector as a unique string pointer if it doesn't exist. The benefit of this is that selectors can be looked up quickly and compared quickly by just comparing their pointer addresses rather than comparing each character of the string.

Unique dynamic features of Objective-C

I don't intend to go into every minor of the Objective-C runtime library but the example above should give an idea of how the dynamic features of Objective-C works.

Classes

In C++ classes don't exist passed compile time. Or at least in modern C++ compilers which support runtime type identification classes exist in a watered down sense in that one can query if two classes have a relationship. In Objective-C it is almost opposite. Classes don't exist at compile time but rather are runtime entities. Classes are registered at runtime with function:
void objc_addClass(Class myClass);
Likewise methods and selectors are registered at runtime. So classes can in fact be modified at runtime. Of course users don't call objc_addClass. These methods along with the ones that registers methods are generated by the preprocessor from the class definition provided by the programmer. But it is this fact that classes and methods exist as structures in memory at runtime that allows the programmer at runtime to query classes about their member variables and functions and whether they respond to a selector or not. In fact an Objective-C developer could create an application which could let user specify classes to call and functions to call. User could just type in the name of a class. Then developer could use C function NSClassFromString() to get corresponding class. NSSelectorFromString() could be used to retrieve the selector. With this one could query class further about arguments existing for selector etc. To learn more about Objective-C look at wikipedia

Saturday, September 08, 2007

The right tool for the job: C++ vs Objective-C

I read Alexei's blog entry about C++ vs Objective-C. I agree fully with his statement that:

The argument (which you can go and read yourself) boils down to “C++ can do everything Objective-C can” versus “sure it can, but not easily, usably or understandibly.” The usual argument comes down to object models: With Objective-C, you can send any object any message, and if it understands it, it will respond. C++ is restricted by its compile-time type system, so that even if you have arbitrary objects that all implement the member function foo, there is no way to call that method on a set of them unless they all inherit from the same base class. Except that you can, as exemplified boost::any and boost::variant.

Actually I pretty much agrees with everything Alexei says and the comments put forth by different people. C++ templates is a wonderful thing while often complicated to understand and use. My major issue with them is that they can't be extended into runtime.

So anyway what I want to emphasis is that templates is not substitute for Objective-C's dynamic features. I work daily on a C++ application with +4 million lines of code. The application have a natural fit with OO design because it has a number of data objects which can be inspected, manipulated and visualized in many different sorts of views at the same time. E.g. one view can show the object in 3D while another can show an intersection in 2D. So Model-View-Controller is a natural fit for it.

The more I work on it the clearer Greenspuns Tenth Rule of programming becomes to me:

Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.

Bottom line is that the kind of structure a large application like this would typically have is what Objective-C was designed for. And thus when I look at the app, all we do in C++ is making a bug-ridden slow implementation of Objective-C.

Creation of views for data objects has to be abstracted because we might create new views we never thought about when the data objects were designed. Thus construction of views has to be abstracted. In Objective-C this is easy. Classes can be passed around like objects and instantiated. C++ on the other hand provides no abstraction of object creation so we ended up making this elaborate scheme with Class ids and factory classes.

We created reference counting, a system for sending messages between object for notifications etc. All stuff that Objective-C was designed for. We end up with huge amount of code for the overall architecture. And it is not even working that well.

But we are not the only ones. Every time I look at a large C++ framework or toolkit I realize that they are just re-implementing Objective-C features in a non standard and buggy way. When I say non-standard I mean that every toolkit has those features but they are done differently in each one and thus not compatible.

E.g. VTK (Visual Toolkit) has reference counting, message passing and abstraction of object creation. Open Inventor has their own reference counting etc. The Qt GUI toolkit has basically gone around the limitations of the C++ language for dynamic behavior and essentially created a library that allows for object introspection and runtime and dynamic dispatch. Essentially they have reimplemented Objective-C in C++. While they have don't quite a good job and I love the Qt toolkit it is still a kludge and non-standard.

So what exactly is my point? My point is that while people can argue from a theoretical foundation that C++ really is the better language due to all its features the power of templates etc, reality speaks for itself. In practice C++ very frequently fails as a language. It seems quite plain to me that when any large C++ toolkit seem to make a half bad implementation of Objective-C then something is wrong with the language.

Does this mean that I think Objective-C is a better language? No, far from it. I just think that one should use the best tool for the job. Frequently it seems like Objective-C would have been the best tool but C++ was selected instead. While C++ has an obvious advantage in implementing algorithms and high performance code, it doesn't seem like the mistake has been done as frequently at the Objective-C camp.

My speculation would be that this is because Objective-C's deficiencies are so obvious. While C++ deficiencies are not as clear. One can more easily kid oneself into thinking C++ will solve the problem without any hassle. And not at least because C++ is better known, a Objective-C developer will more likely consider using C++ for specific parts of the program than the other way around.

C++ and Objective-C complements each other very well in my opinion and they have different enough syntax from each other that it should be easy to keep the two apart in a program. But too often people think C++ is the silver bullet that can be used equally well for any task.