CocoaHeads: Objective-C 2.0

Michael Jurewitz will give a presentation tonight on Objective-C 2.0 at CocoaHeads Silicon Valley. The meeting will be in Town Hall at 7:30pm. Objective-C 2.0 is a major language upgrade coming in Leopard.

Map to 1 Infinite Loop


Thursday, September 13 at 7:30pm
Town Hall, Building 4 Apple

If you enter the campus from the main De Anza driveway, turn left and follow the road all the way around until you see the gigantic 4 on the sidewalk. Walk up and knock so that someone can let you in.

There's no fee or pre-registration required. You can just show up. In addition to the featured presentation, CocoaHeads is a great place to get help with Mac programming, and we often have time at the end for demos or feedback on current projects.

We really appreciate Mike coming out during an incredibly busy schedule. Please come show your support.
Design Element
CocoaHeads: Objective-C 2.0
Posted Sep 13, 2007 — 31 comments below




 

Majd Abdelahad — Sep 13, 07 4589

Is there going to be an online version of this for us east coasters?

d chalmers — Sep 13, 07 4590

I thought Obj-C 2.0 was still NDA'ed...?

Andrew — Sep 14, 07 4594

d. Chalmers:

See:

http://en.wikipedia.org/wiki/ObjectiveC#Objective-C_2.0

and

http://www.apple.com/macosx/leopard/developer/xcode.html

Ulai — Sep 14, 07 4599

Sounds good, but is Objective-C 2.0 really that much of a breakthrough?

Let me provide an example: How do you guys feel about the fact that Objective-C 2.0 will not even bring support for overloaded operators? This means that a scientist who is working on complicated models involving, say, complex numbers will never move towards Cocoa development. He will want to create a class called ComplexNumber, let z and w be two instances of that class, and he will want to add those complex numbers with z + w, instead of ComplexNumber.Add(z,w). You can imagine the latter notation being way too cumbersome as the models get more complicated. Therefore, scientists working with complex number at least (and there are many of them I might add), will never move to Cocoa. Yet.

Scott Stevenson — Sep 14, 07 4600 Scotty the Leopard

How do you guys feel about the fact that Objective-C 2.0 will not even bring support for overloaded operators?

This is a design decision, I believe. Objective-C is intended to have a small set of syntax and code should look relatively similar from project to project. One opinion (and it would seem, the prevailing one on the Objective-C team) is that operator overloading opens the door for code that is too hard to read.

Developers that want to use operator overloading could use C++ for the internal logic processing, and Cocoa/Objective-C++ for the UI level.

The main standout points of Objective-C 2.0 are:

- Garbage collection
- Properties with synthensized accessors
- Property metadata
- Foreach-style loops
- Some other fancy stuff that may still be NDA'd

David Wareing — Sep 14, 07 4601

I'm happy that ObjC 2.0 won't support operator overloading. Overloading, IMO, is just another C++ "feature" that helps obfuscate code and muddy designs.

Russell Finn — Sep 15, 07 4602

he will want to add those complex numbers with z + w, instead of ComplexNumber.Add(z,w)

How would your hypothetical scientist feel about using actual Objective-C syntax, which would look more like [z plus: w]? I admit it's not the same as z + w, but it's more readable than what you posted. (Or he could use Objective-C++ to combine his matrix class library with a Cocoa UI, and have the best of both worlds.)

It would be easier to take your criticism more seriously if it looked like you'd actually investigated the language, instead of running down a bullet list looking for your favorite missing features.

Scott Stevenson — Sep 15, 07 4603 Scotty the Leopard

@Russell Finn:
How would your hypothetical scientist feel about using actual Objective-C syntax, which would look more like [z plus: w]
This is a good point because the Objective-C 2.0 dot syntax does not support methods with arguments like object.add(1,2) or even object.print(1). It's designed for property setters and getters:
object.name = @"Leopard"; NSLog(@"name: %@", object.name);

Messages that do not involve the setting and getting of properties still look like this in Objective-C 2.0:
NSString *newString = [string stringByAppendingString:@"New String"];

Pieter Omvlee — Sep 15, 07 4604

Great to read a post again after such a long time (a long holiday?) and more on the subject;
I agree with the majority here in that I think that overloading should be left out (luckily they did leave it out!)

I should really move to the US, why do you get all that free cool stuff, I would love to be there...

Ulai — Sep 15, 07 4605

Hello again Russell and Scott. Thanks for your answers.

Yes, I did realize just after having posted the thought that I had written the C++ style method instead of the Objective-C one. I happen to know a thing or two in Objective-C. However, changing the style of methods to the Objective-C ones does not change my arguments one bit.

Russell talks about [z plus: w] being more readable than .Add(z,w). Sure I agree with that. But this is one example. And probably among the simplest you could find. What about the example of z+w+v ? This would translate into [[z plus: w] plus: v]. Or some string formatting stuff. Simply just not as good as z+w+v. The thing will get worse as we move to real-world applications of the scientists.

What is it about this belief that overloading operators will make code less readable? To me it is like saying that every word in the English dictionary should mean one and only one thing. That of is of course not so and what they mean depend on the context. When you read code that says z+w you will have read the surrounding code, and in your study of the code you will long have known that z and w are complex numbers.

Don't get me wrong though. I happen to like Cocoa and Objective-C a lot. However, I do for sure miss overloading operators. I happen to use C# daily at work and overloading has not caused me any confusion at all. It has just served to make my life easier. After all, the meaning of '+' is just determined by the context, which will be obvious when the code in question has been looked at.

Blain — Sep 15, 07 4606

I have this to say about Operator Overloading: When it's possible to get a compile message of "This is valid and well-formed code, but there's so many ways I can translate it, I can't even guess what to do," you've got a serious design flaw in your language.

The reason dot property syntax isn't as bad as I feared is because all NSObjects are pointers, so fooObject.property can't be mistaken for a c construct.

Scott Stevenson — Sep 16, 07 4607 Scotty the Leopard

Ulai, you present some interesting thoughts for focused mathematics and scientific computing, but I don't have much (and by "much" I mean "any") experience programming in those areas so I really can't comment on it.

My opinion is that for general-purpose desktop application programming, operator overloading causes more problem then it solves by developers inventing their own metalanguages that someone else has to learn later.

At the end of the day, Objective-C's main priority seems to be general-purpose programming. That said, you can mix Objective-C and C++ if it suits your needs.

I happen to use C# daily at work and overloading has not caused me any confusion at all

Which makes sense since if it did, I doubt you'd be requesting it. :) Of course, the challenge is that Objective-C has a lot of users to take into consideration. Something that you consider a weakness I consider a strength, but that's the whole point of having multiple languages to choose from.

None of this stops you from writing a Mac app, of course. The UI logic and internal calculation logic can be written in different languages.

Blain — Sep 16, 07 4608

Ah. C#. That's a different kettle of fish. I'm intending to write an article about c++ vs ObjC, but the C# has a nice twist, in that it's not C-compatible.

Correct me if I'm wrong, but C# frowns on the use of pointers, and makes them mostly inaccessable. Problem is that, to play nicely with C, pointers are vital. C++ muddles through, and here's where the overloading falls apart.

All Obj-C objects are actually pointers to mostly-opaque structs. To get to the value pointed at foo, you use *foo. If foo is an array, you can point to the first element as bar = foo, and then talk about *bar, and the next element is pointed at by bar+1.

So suppose we have an C array of ComplexNumber.
ourNumber = numberArray[0];

No problem. The value of the complex is *ourNumber.

So if we want to add two complex numbers, we'd want
*c = *a + *b;
But we want to use constants as well.
*c = *a + 1;
which is a mess and much worse than brackets, especially when you get *c=*a * *b;!

So let's overload so adding pointers returns a pointer to the sum of the values.
c = a + b;
But now
c = a + 1;
is ambigous; Is that the index of the object after a in the array, or one added to the value of a?

Either we get confused scientists, or we lose backward language compatibility. Again, this is moot with a lang that doesn't allow for pointer math. But it leads to lots of bugs if it's not called a new language.

The thing is that complex numbers are an edge case, and Obj-C is meant more towards doing 80% really well instead of 100% mostly okay.

What would I suggest to the wayward scientist? Simple. If you know C#, use it, and the mono to cocoa bridge.

Or use a language taylored to the physics, and use obj-c to display, but not compute the results. Model, view, controller and all.

Eric Wing — Sep 17, 07 4610

FYI, C99 supports complex numbers. Example:

#include <complex.h> #include <stdio.h> int main(int argc, char* argv[]) { float complex my_result; float _Complex my_complex1 = 3.0 + 4.0*I; float complex my_complex2 = 1.0 + 2.0*_Complex_I; my_result = my_complex1 + my_complex2; printf("Add: %f + %fi\n", creal(my_result), cimag(my_result)); my_result = my_complex1 * my_complex2; printf("Multiply: %f + %fi\n", creal(my_result), cimag(my_result)); return 0; }

Obj-C is a pure superset of C; no need to write your own class in this case.

Nicko — Sep 21, 07 4615

I have to confess that I really don't understand this idea that operator overloading somehow makes code harder to read. Yes, people can write obfuscated code using overloaded operators, but they can also choose obtuse message names and it's not considered a flaw in the language. Used properly, operator overloading makes code substantially more readable.

Recently I had cause to add an NSTimeInterval to an NSDate. If I was writing this in a language with operator overloading I'd have written:
endTime = startTime + delay
In the absence of operator overloading I instead have to write:
endTimer = [[[NSDate alloc] initWithTimeInterval: delay sinceDate: startTime] autorelease]]
Can you honestly say that the former is harder to read than the later? The exact implementation of the addition process is hidden from sight but this is a feature, not a bug. It's called abstraction!

It's interesting to note that if the language grew the capacity to handle operator overloading through mapping of operators to appropriately named messages it would be relatively easy to retrofit support for this into existing libraries; all you have to do it write categories to support the new operators. This also means that you don't have to add complex support for trying to map to "left" and "right" forms of operator since if I come up with a new class and I want to be able to have it as the right-hand operand dealing with an existing class then I just add a category to the existing class.

Scott Stevenson — Sep 21, 07 4616 Scotty the Leopard

@Nicko: I have to confess that I really don't understand this idea that operator overloading somehow makes code harder to read

It's not a empirical fact. It's an opinion based on experiences of the language designers. You can certainly provide supporting evidence for either side, but ultimately the point is moot because Objective-C does not have operator overloading.

Can you honestly say that the former is harder to read than the later?

No, but I think it's beside the point. In any case, it's a very contained, tiny example which I don't think illustrates the thinking behind the decision.

In the example you give, you talk about the ease of writing code with operator overloading. In my opinion, ease of reading code is more important in most cases. The more layers you have, the more you have to dig to find out what's going on.

There's certainly less code to read in that one snippet, but shorter code doesn't necessarily mean more clear or easier. Cocoa and Objective-C discourages fancy language tricks and instead favors the shallow, low-tech solution. Something like Ruby/Rails takes a different approach. It's a choice: there's no way to prove one is better than the other.

It's called abstraction!

Hmmm. I'm not sure I agree with that. Redefining the basic meaning of a C operator is much different that creating a shim method over several smaller ones. But I could be convinced otherwise.

When you tackle a big chunk of code, it's already quite a lot of work to figure out the naming schemes and how all the classes fit together. It can become quite a bit more complicated if you have to figure out how the original author decided to recast operators. Again, this is just my opinion.

Nicko — Sep 21, 07 4618

@Scott
You can certainly provide supporting evidence for either side, but ultimately the point is moot because Objective-C does not have operator overloading.
Well, the topic of the thread is a future release of the language which benefits from newly added features, has changes which makes currently erroneous code legal and is still only in beta, so discussion of what Objective C either might or should have seems appropriate. Furthermore, I'm actively considering building a patch to gcc to add support for it!

In the example you give, you talk about the ease of writing code with operator overloading. In my opinion, ease of reading code is more important in most cases.
I talked about both, and I think that both are important. The question I asked of you was which was more readable but the deeper question is "Which makes the programmer's intent clearer to the reader?" My most common frustration with coding complex applications in Objective C is that the intent of the code is all to often obscured by the detail.

The more layers you have, the more you have to dig to find out what's going on.
That is certainly true in some cases, but in many others, if the programmer is doing his or her job, there should be no need to dig. If I've got three variables called "startTime", "delay" and "endTime" then when the heck do you think that the "+" operator is going to do in this context? The exact same thing could be said for adding two NSString objects, ORing one NSSet with another or even adding an NSView subclasss to an NSTabView. Unless the programmer is actively trying to deceive the reader it is almost always going to be the case that a succinct representation of the intent is going to be more meaningful to others, precisely because you don't need to dig. That's one of the main benefits of abstraction.

Redefining the basic meaning of a C operator is much different that creating a shim method over several smaller ones.
True, but there is also a huge difference between redefining an operator and overloading it. I'm not supporting trying to redefine the basic meaning of an operator, I'm arguing that the concepts like "addition" and "OR" have a natural meaning contexts other than int or double, that programmers know what it means to subtract, for instance, an object from a set, and that allowing the extension of these natural meanings into other types of object makes it easier to represent your programming goals.

Scott Stevenson — Sep 21, 07 4622 Scotty the Leopard

@Nicko: If I've got three variables called "startTime", "delay" and "endTime" then when the heck do you think that the "+" operator is going to do in this context?
I see the value in what you're describing and I'm not totally closed to having my mind changed, but this particular case of the plus symbol, I think, highlights one important area.

If you consider 64-bit versus 32-bit, and whether the variable is a pointer or a simple value type, plus can already mean a number of things. Adding "whatever the programming thinks plus means" is an additional burden.

Not that I'm saying it's a deal breaker, I just don't think it's trivial. For what it's worth, I think it would be really nice to have some string conveniences in the syntax since that's much less likely to be ambigious. I'm not as sold on mathematical operations.

If I've got three variables called "startTime", "delay" and "endTime" then when the heck do you think that the "+" operator is going to do in this context?
I can imagine what it's supposed to do, but trying to find the difference between my intent and what the computer thinks is happening has left me with countless hours in front of the debugger. I'm not saying operator overloading doesn't have value, I'm just curious if the value is enough to overpower the drawbacks.

Nicko — Sep 22, 07 4631

If you consider 64-bit versus 32-bit, and whether the variable is a pointer or a simple value type, plus can already mean a number of things. Adding "whatever the programming thinks plus means" is an additional burden.

You are right that C's implicit casting of numerical types can be confusing, and that there is already a meaning for adding integer types to pointers. That said part of the issue here is a mind-set in which object handles are being thought of as structure pointers rather than opaque references. The ObjC syntax certainly allows one to use the form (objHandle + 42)->member, but I can't say that I've ever seen that used. As such (since we're talking about a fundamental language change) I'd rather see that form deprecated for use with Object pointers and attempts to use it will just cause the compiler to warn objClass may not respond to '__add__:' or something of that ilk.

In the end I think this debate ultimately comes down to the question "Do I trust the authors of code I have to read to use overloaded operators in a manner that is intuitive and meaningful?" If I don't trust them to do this then overloaded operators will mean I have to look all over the place to find the meaning of their code. If I do trust them then I'll be able to skim through the code and know what the programmer meant much more quickly than if the code was all in line. Perhaps I just have more faith in other programmers than you do :-)

huxley — Sep 22, 07 4632

To me it is like saying that every word in the English dictionary should mean one and only one thing. That of is of course not so and what they mean depend on the context.

You'd probably change your mind if you had to debug a complex conversation.

Blain — Sep 23, 07 4637

I'd rather see that form deprecated for use with Object pointers and attempts to use it will just cause the compiler to warn objClass may not respond to '__add__:' or something of that ilk.

One of my bugaboos (Woohoo! Bugaboos is considered a word!) about C++ is that it's not a perfect superset of C, while Obj-C is. In other words, any C program will compile in Obj-C, while it's possible to make a C program that either won't compile with C++, or will compile differently. This is my major sticking point. As soon as you have to use "Extern C" or similar, you no longer have an upgrade. You have a completely different language.

The other problem becomes the heavy use of @selector and similar items. How do you differentiate between -[add:] taking an int and -[add:] taking a float? How would it be backwards compatible without any special hints?

I also stand by my holding the compiler-defined signs as sacred to Obj-C, but I can see a few compromises. Namely, that not only Obj-C should extend itself while keeping true to the strict C/Smalltalk separation, but that Obj-C++, the fusion of C++ and Obj-C that we already have, should improve and evolve. That is, no operator overloading on .m files, but .mm is fair game.

Not only that, but I can see setting aside a playpen for compiler-defined overrides. Namely, endTime = startTime + delay still plays with pointer math, and isn't the same as endTime = [startTime addTimeInterval: delay]; (Which, I might add, is quite readable). But I could see a use for something like:
endTime = [startTime + delay];

That way, the brackets let the coder and compiler know it's an object message instead of pointer math, but with a twist: like the dot notation, it's syntactic sugar at the compiler level, not the language level. In other words, which message gets called would be dependent on the following variable.

With an int, the compiler would swap in -[addIntValue:]. With a long, the compiler would swap in -[addLongValue:]. And NSObject's -[addLongValue:] would call -[addIntValue:], etc. With an object, it'd be -[addObjectValue:], and so forth. Yes, this wouldn't allow for overloading based on which id. But part of Obj-C's foundations is that it's not the kind of object that matters as much as what it can do; check at runtime for [respondsToSelector:].

Does that sound like a promising idea for Obj-C++ 3.0?

Nicko — Sep 23, 07 4639

I'd rather see that form deprecated for use with Object pointers and attempts to use it will just cause the compiler to warn objClass may not respond to '__add__:' or something of that ilk.

One of my bugaboos (Woohoo! Bugaboos is considered a word!) about C++ is that it's not a perfect superset of C, while Obj-C is. In other words, any C program will compile in Obj-C, while it's possible to make a C program that either won't compile with C++, or will compile differently. This is my major sticking point. As soon as you have to use "Extern C" or similar, you no longer have an upgrade. You have a completely different language.


I'm not sure I agree with your completely different language assertion but irrespective of that, we don't need to worry in this case. Due to the way that ObjC works, by the time the compiler has to worry about what foo + bar means it already knows the type of "foo" (and "bar", see below) and it knows if foo is a base type (behave normally), a pointer (perform pointer addition), a structure (throw an error) or, since this is ObjC, an object reference. Thus correct pure C code would not need to have its behaviour modified in any way.

But I could see a use for something like: endTime = [startTime + delay];

I can see that working in some ways, and it helps in dealing with questions about operator precedence between different classes, but I see a couple of big problems. Firstly, you're heading towards context-sensitive grammars, which are bad in a number of ways. Secondly, unless you deprecate pointer addition on object references you still have confusion over what [startTime + offset + delay] means.

With an int, the compiler would swap in -[addIntValue:]. With a long, the compiler would swap in -[addLongValue:]. And NSObject's -[addLongValue:] would call -[addIntValue:], etc. With an object, it'd be -[addObjectValue:], and so forth. Yes, this wouldn't allow for overloading based on which id. But part of Obj-C's foundations is that it's not the kind of object that matters as much as what it can do; check at runtime for [respondsToSelector:].

The exact behaviour for this was something I had been thinking about for a while. For base types as the right-hand operand I'm inclined to convert it into an NSNumber (and an NSValue for structs) and pass it as an object, that way the programmer never has to implement more than one call if she does not want to. Conversely, since ObjC does not have multiple inheritance, since we know the class of the operand at compile time and since we know the messages that the recipient responds to at compile time, I think that it would make sense to look at all the messages of the form __add__XXX: to find the XXX that is furthest down the class ancestry for the right hand operand. If there is no match then we pass it to the base __add__: message, which may or may not be implemented and will be warned about if it is not. This would have both valuable static type checking benefits (which would avoid some of the classes error one gets in languages like Python) and would have profound performance improvements, since the ObjC runtime can ensure that the conversion from SEL to IMP only has to happen once and get cached rather than having a full dynamic lookup every time.

Blain — Sep 23, 07 4640

I think what we're butting heads up against is a philosophical difference in how C++ treats objects and Obj-C treats them. Obj-C is strongly typed in a way, in that there's only one object structure, the id. Everything else is on top of it, in terms of data and methods. Because of this, you don't need to know the class to use an obj-c object. There is no clarification necessary.

void * testy = [NSString stringWithString:@"Hello, world!"];
NSLog(testy);

Not only does this compile and run, but I didn't even get a warning. Obj-C is already context-sensitive. It's a language arch deluxe, keeping the hot side hot, and the cold side cold. The smalltalk side is completely different than the C side, in class declaration, in class definition, in calling, etc. The difference is that the context (object vs void *) is delineated by the brackets, not by the type that it might or might not be.

This is the crux of the matter: the compiler does not know the class it's being passed -- it doesn't need to; the structure it cares about is constant. A lot of Obj-C's magic uses this. Obj-C doesn't have multiple inheritance, simply because it uses protocols, both formal and informal, instead.

- (void)setDelegate:(id)anObject;

You'll find this in many NSObjects, even ones that aren't directly related. It takes an id. Not even an NSObject. There is not even a shred of a clue what class it's going to be, or even if it stays the same class over time. But it doesn't need to. As long as you check with respondsToSelector:, you're fine. That's right, the compiler need not even know what functions the class has. This is the difference. We don't care about your class, as long as you do your duty.

As for SEL and IMP, do look at methodForSelector:. We already can have the caching technique and eat it, too. And we don't have to sacrifice dynamicness for it. Let us go on without premature optimization.

Nicko — Sep 23, 07 4641

This is the crux of the matter: the compiler does not know the class it's being passed -- it doesn't need to; the structure it cares about is constant.

This is simply untrue. Consider the following code:
- (void) foo: (NSView*) v {} - (void) barResponder: (NSResponder *) r view: (NSView *) v button: (NSButton *) b { [self foo: r]; [self foo: v]; [self foo: b]; }

The first call to foo: raises a warning (passing argument 1 of 'foo:' from distinct Objective-C type) while the other two pass silently. The compiler is well away of the class of objects, and of the class hierarchy. Now it may well be the case that the recipient does not care, and can indicate so by typing the parameter as 'id' rather than 'Foo*', but that's a very different thing to the compiler not knowing that class.

As for SEL and IMP, do look at methodForSelector:. We already can have the caching technique and eat it, too. And we don't have to sacrifice dynamicness for it. Let us go on without premature optimization.

I think you are missing the point I was making. If we are going to have some sort of operator overloading then, to satisfy exactly the sort of polymorphic behaviour that you were describing, you want to be able to attempt to pass any class as the operand. That said, the behaviour of an operator is likely to differ depending on the type of the operand (e.g. multiply my polynomial by (a) a rational number or (b) another polynomial, but never allow (c) an NSWindow, because that would be meaningless).

We have a choice here; we can just require ever implementation of every operator to contain some sort of switch code to find the right behviour, we can define some sort of class hierarchy based run-time matching to find a 'best match' message name or we can do that same sort of matching and perform as much of that matching as possible at compile time.

The first option is dreadfully inefficient (since the switch will run every time). The second option could have some sort of built-in caching, though it would be a different type of caching to the existing methodForSelector: cache since it would have to understand the class hierarchy of the operand as well as the recipient. The third option could be done at compile time, which has the added advantage of allowing the compiler to raise a warning if there is no known matching selector.

There is actually a forth option, which might give the best of both worlds, which would be to implement option 2 and option 3, performing the lookup (and caching it) at runtime but performing a static check at compile time to allow for warnings. This is akin to the current arrangement where sending a random message to an object can raise a compiler warning but may well work at run-time. Now that I think about it, I think that this is the plan I shall try to implement!

Blain — Sep 23, 07 4642

This is the crux of the matter: the compiler does not know the class it's being passed -- it doesn't need to; the structure it cares about is constant.

This is simply untrue. Consider the following code:


Perhaps I should qualify my statement. While the compiler and IDE do know of the classes, especially for things like autocomplete, it doesn't necessarily need to know where specific values and functions are. Or even if they'll be the same.

Correct me if I'm wrong, but C++ has two ways for member functions. The lesser used is a virtual function, which is akin to Obj-C's messages, in that which code is run is determined at runtime. The default, however, is statically bound at compile time based on the variable class. This allows for very fast execution, but can lead to fragile base classes, because a subclass can't redefine a non-virtual function.

The problem is that I think one major advantage of Obj-C is delegates and other informal protocols. But they require virtual functions at every step of the way. But I digress.

If we are going to have some sort of operator overloading then, to satisfy exactly the sort of polymorphic behaviour that you were describing, you want to be able to attempt to pass any class as the operand.

To a degree, yes. For what I focus on, math is actually very low, as I focus more on classes that depend on things like tableView:objectValueForTableColumn:row:, which really could be almost any class. I mention -stringValue below, which also can lead to overloading confusion. If you can add two strings (concatenate), and you can treat an NSButton as a string using -stringValue and -setStringValue, can you add two buttons?

We have a choice here; we can just require ever implementation of every operator to contain some sort of switch code to find the right behviour, we can define some sort of class hierarchy based run-time matching to find a 'best match' message name or we can do that same sort of matching and perform as much of that matching as possible at compile time.

Now that I think of it, take a look at the value methods. They're a good example, in some ways. Both NSCell and NSNumber implement -stringValue, -compare:, intValue, -floatValue, -doubleValue, and the like. They're Obj-C's current response to operator overloading, in two ways. First, the two classes are unrelated save at NSObject, yet they receive the same messages. The second thing, however, is when you hook things up in the nib, there's no mention of it being an int, float, or string. This is a detail done at runtime, effectively overloading the operand as well.

I still bristle at the term "best match," as it always gives me an image of a compiler playing 'pin the tail on the donkey.' But I'm curious as to your solution. I still suggest that it'd be best to extend Obj-C++, which still needs better C++/Obj-C inter-operability and already has some precedent for operator overloading, than to modify Obj-C itself.

The real acid test is if it will still allow for -poseAsClass, categories added at runtime via loaded bundles, and method swizzling. And as much as we disagree over operator overloading, I will gladly be one of the first to download and take your improved compiler for a spin.

Chuck — Sep 23, 07 4643

To jump in on the operator overloading discussion: I think it's worth pointing out that C++ is not the only language that allows such things, and we shouldn't get stuck on its eccentricities as the definition of the feature. I believe Smalltalk had operator overloading, and Ruby kept it as well with (as far as I know) no real complaints from Ruby programmers. In these languages, operators are just methods that objects respond to. Objective-C 2 already extends in the dot operator to work with objects -- allowing other operators to take on special behaviors isn't too radical a stretch.

Nicko — Sep 30, 07 4672

Correct me if I'm wrong, but C++ has two ways for member functions. The lesser used is a virtual function, which is akin to Obj-C's messages, in that which code is run is determined at runtime. The default, however, is statically bound at compile time based on the variable class.

That's right, all ObjC messages are bound at runtime but C++ defaults to binding methods at link-time. That said, virtual methods (and ObjC messages) are still type-checked by the compiler. I'm unsure of the details in C++ but in ObjC there is no run-time type checking of parameters.

I mention -stringValue below, which also can lead to overloading confusion. If you can add two strings (concatenate), and you can treat an NSButton as a string using -stringValue and -setStringValue, can you add two buttons?

Firstly, in the model I propose the "button plus button" case would never behave as you suggest simply because the left-hand operand would always stay as the target of the message and never be coerced into any other type. Secondly, I am not proposing any sort of automated type coercion at all. I think that this feature of C++ is the source of many of the problems people have with C++ operator overloading and it makes it very confusing indeed. Operator overloading in languages like Smalltalk, Python and Ruby happily get away without that complexity.

Now that I think of it, take a look at the value methods. They're a good example, in some ways. Both NSCell and NSNumber implement -stringValue, -compare:, intValue, -floatValue, -doubleValue, and the like.

Any automated use of the "-XXXValue" methods leads to exactly the madness of C++ operator overloading that I'm trying to avoid. They are fine when you are trying to present an object in a specific context (e.g. display the value on the slider as a -stringValue but process it as a -doubleValue) but go any deeper than that and you get to just the sort of obfuscation of meaning that Scott was complaining about at the start of this thread.

I still bristle at the term "best match," as it always gives me an image of a compiler playing 'pin the tail on the donkey.'

If you allow for multiple inheritance and automated type coercion then I agree. In fact what you get is the mess that C++ offers. In Objective C we have simple, linear class inheritance and I'm not proposing to support any coercion. In this case the "best match" is very simple. Just like any other method invocation the parameter has to be a instance of the parameter type or a subtype of that; if there is more than one match then take the match which is closest in the class inheritance chain. So, if I have different methods for a responder, a view or a button then an NSPopUpButton is going to match the button, a generic NSControl is going to match the view, an NSWindow is going to match the responder and an NSDictionary is not going to match anything and raises a warning at compile time, not at run time.

The real acid test is if it will still allow for -poseAsClass, categories added at runtime via loaded bundles, and method swizzling. And as much as we disagree over operator overloading, I will gladly be one of the first to download and take your improved compiler for a spin.

Pose as class will not be a problem, though if you add overloaded operators at run time then the compiler has every right to warn about their use at compile time since they didn't exist then. Categories not only work, but are the "right" way to do this. The classes from the current libraries can have operator overloading support added through categories. Furthermore, if I come up with a new class and I want to add specific support for it as the right-hand operand on some existing class I can retrofit that through a category too. Method swizzling is an ugly hack but it should still work with my envisioned implementation.

Blain — Oct 01, 07 4686

I think we're on the same page now. The auto-conversion was my biggest gripe, and adding pointers, although in theory allowed by C, is wrong enough that this won't be used in the literal sense. I am concerned that we'd end up breaking the commutative property for numbers (IE, a+b == b+a), but this can be easily mitigated, and would be a definite win for something like += as an append assignment.

I'd support something that could be done in a way that degrades gracefully with backwards compatibility. Perhaps if there's NSObject class foo and bar. And we want to overload -(void)[doThing:] I can see the following.
-(void) doThing: (NSObject *) ourValue; -(void) doThingWithFoo: (Foo *) ourValue; -(void) doThingWithBar: (Bar *) ourValue; #ifdef OBJ_C_2_1 @overload -doThing: #endif
Without the extensions, we'd have three messages, obviously. And you can explicitly ask for them by name. Heck, you can even have doThing: do class-checking, and reroute appropriately at runtime as a fallback.

With the extensions, when the compiler comes across doThing: with a known foo as the argument, it'd substitute in the doThingWithFoo:, for instance. This way, there's no mangling needed, binary backwards compatibility is preserved, and debug tools all will be honest about which doThing is being called. The overloading naming can be akin to accessors, where it searches for (message name)As(class) first, then tries (message name)With(class), (message name)Using(class), (message name)(class), (message name)_(class) etc.

Question: suppose we have foo, and bar is a subclass of foo. If foo has a doThingWithFoo:, but bar only has doThing, which would be called when [barObject doThing: fooObject] is used? Would it be the generic but most recently implemented bar's doThing:, or the specialized but not as directly associated foo's doThingWithFoo? I'm leaning towards the former, but I can see arguments for either.

Of course, if you want to explicitly override the type, it'd be a case of bar.fooValue, which moots things in that it's no longer bar being used, but an accessor-generated foo. That works very well.

---
Finally, the issue of operator overloading remains with the non-class core types. I'm not talking about int and float as much as NSPoint, NSSize, NSRect, etc. I could see use in NSSize + NSSize, or NSPoint + NSPoint.

I'm tempted to try this last bit in Obj-C++. Namely, C++ allows for structs to be treated as classes, so I'll try making NSPoint::operator+(NSPoint val) without it declared in the struct definition.

Timothy Mowlem — Oct 01, 07 4689

The one feature missing for me that would be a big boon would be some system of packages or modules to organise code.

The java package system is very useful for separating classes into namespaces, thereby avoiding name clashes and improving high level view of the code.

Is there any likelihood of such a feature being added to Objective-C going forward?

Blain — Oct 01, 07 4690

I'm hesitant to agree to namespaces, on the basis that I don't want line 4 to significantly impact what line 400 does. With import/include and prefixing, the code either compiles or it doesn't. With namespaces, you run the risk of getting one class when you're thinking of another.

The other issue is that I don't know how namespaces could avoid conflicts of a messages. That is, if someone category-extended an NSObject when they made it for 10.4, and in 10.5, a message with that name comes out, bad things happen.

In the meantime, frameworks (with recursive frameworks, at that) and the use of a 2 or 3 letter prefix has been holding up rather well.

Hamish — Nov 04, 07 4973

@Nicko:
Recently I had cause to add an NSTimeInterval to an NSDate. If I was writing this in a language with operator overloading I'd have written:
endTime = startTime + delay

In the absence of operator overloading I instead have to write:
endTime = [[[NSDate alloc] initWithTimeInterval: delay sinceDate: startTime] autorelease]]

Luckily, in the presence of categories you simply have to write:
endTime = [startTime plus:delay]

Of course, someone (you or Apple) still has to write the method for this, but operator overloading doesn't change that fact.




 

Comments Temporarily Disabled

I had to temporarily disable comments due to spam. I'll re-enable them soon.





Copyright © Scott Stevenson 2004-2015