16 Feb 12
17:26

The Class Class as an argument in objective C++

When you say the same word over and over it starts to become meaningless. Mix this together with metaclasses and reflection. Then take objective-C and add it to C++. You then have an objective-C @Class construct for forward declaration, the Class object, the NSObject class method, and the C++ class keyword. It was only a matter of time before this would drive somebody crazy and lead me to waste an hour of debugging the wrong thing.

Here is the definition of the class method in objective-C which you can include in objective C++ without warnings or errors:

- (Class)class

‘class’ doesn’t mean anything in regular c or objective-c, but my projects often involve C++ classes, so I’m usually working in .mm files.
This lowercase method name matches the C++ keyword, but is allowed by the compiler in objective-c++, presumably because the compiler looks at context to apply c keywords to.

However this is not allowed:

-(void)giveMeAClass:(Class)class

I spent about an hour and a half trying to figure out how to forward-declare or include the class declaration. Because this was in a class header that also had NSObject, which declares the ‘class’ method above (which uses Class as a return value), this went against my intuition but unfortunately when going into debugging mode, sometimes I (and admit it, you too!) get fixated on one path and make some very silly decisions along the way that end up preventing a breadth first approach that would get the solution faster.

I did learn some interesting things along the way. Such as, Class is a typedef pointer to a struct, which is why it is one of the only (possibly the only) objective-c object that doesn’t use an asterix when passing it around.

But the real problem was not ‘Class’. It was ‘class’. ‘class’ is a c++ keyword, as mentioned earlier, and you cannot use it for parameter names, only for method names. I should have seen this, but the ‘class’ method case through me off.

The correct solution (as NSObject also uses) is just to call your Class variable names aClass.

-(void)giveMeAClass:(Class)aClass

Arg.

01 Feb 12
16:08

std::vector size() method and gotcha with unsigned vs signed

Guess who wins in signed vs unsigned integer conversion? I guessed wrong today, or rather, I’ve been assuming wrong for quite a while.

consider this example:

   std::vector<SomeClass*> myVec;
   int countdown = -1;
   // ... (fill the vector)
   if (countdown < myVec.size()) 
      countdown++;  // this will never get hit

myVec.size() returns size_t, which is an unsigned int and countdown is an int, so to compare these two, the compiler will implicitly cast. You will get warnings when you do this kind of comparison, so listen to them. I assumed in the conversion of primitive values, signed int has precedence. That line casts countdown to an unsigned int, meaning that it has a very high value (0xfffffff), so the conditional is always false.

So the if statment was evaluating to

   if ((unsigned int) -1 < 1) // pretend there is 1 element in the array 
      countdown++;

which is

   if (0xFFFFFFFF < 1) // false (same as  UINT_MAX < 1)
      countdown++; 

The correct code then is:

   if (countdown < (int) myVec.size()) 
      countdown++;  // this will now be run

Here are the rules for implicit type conversion from the C99 standard:

6.3.1.8 Usual arithmetic conversions

If both operands have the same type, then no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

I don't understand the statement after the bold section. But it is clear that unsigned types have precedence over same ranked types.