swarm-support
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

A story about [self Class] (continued...)


From: mcmullin
Subject: A story about [self Class] (continued...)
Date: Wed, 9 Apr 1997 16:06:13 -0600 (MDT)


Here's one for you old C programmers:  objC BOOL is
not, repeat NOT, equivalent to the C logical data type;
i.e. BOOL is not int.

In fact BOOL is typedef'd as (unsigned char).

So what?

Well, good old C programmers are used to thinking that
any word-sized value which is non-zero will count as
logical TRUE.  For example, a non-nil pointer, or a
non-zero int.  This is *not* a safe assumption in
objC.  In particular, if there is an explicit or
implicit conversion to BOOL, the low order byte of the
word-sized value is chopped off as the value to be
used.  Now this low order byte can *easily* be zero
even though the whole word is not.

Why do I mention this now?

I just had a weird problem where I had an object for
which I set up a custom probeMap, but when I probed it
I got the default probeMap instead.  I mentioned this
in a post last week - when I claimed to have identified
the problem as being that I was using [self class] in a
class method (instead of simply "self").  Boy was I
wrong!  I had concluded that [self class] was not
reliably usable within class methods: it now seems that
was complete nonsense.  Granted, when I changed [self
class] to simply "self" in the relevant places, it did
*seem* to fix the probeMap problem; but it subsequently
transpired that almost *any* change to my program
whatsoever "fixed" the problem; and, more to the point,
the problem recurred when I made another further,
independent, change to the program.

I have now definitively (?) nailed this problem.  It is
due to the following method in probeLibrary.m:

  -(BOOL) isProbeMapDefinedFor: (Class) aClass {
    return [classMap at: aClass] ;
  }

my "corrected" version is:

  -(BOOL) isProbeMapDefinedFor: (Class) aClass {
    return ([classMap at: aClass] != nil);
  }

Now (if you're an experienced C person), your immediate
reaction is going to be to say that these are just the
same thing, because, of course, in C *any* non-zero
"int" counts as "true".  OK, strictly speaking, we're
working with a pointer in this case, but our global
portability assumptions make that the same size as an
int, so we can still say any non-nil pointer will mean
"true".

Now I would always say that *relying* on that kind of
equivalence is a bad *stylistic* idea, because it makes
the implied conversion from int/pointer to a logical
value obscure.  But I know lots of people do it and,
depending on the compiler, there might actually be some
performance advantage (though, if so, I would tend to
say that is a fault in the compiler...).

BUT: in objC it's not just stylistically objectionable
- it's actually wrong (:-( And this seems like a real
big gotcha for people familiar with the C equivalence
between int/pointer and logical values.  This is the
first time I've encountered this, and it is really
horrible.

Because BOOL is actually (unsigned char), if you take
an arbitrary non-zero int or pointer value and convert
it to an unsigned char (which is what the original code
above implicitly did - the declared return type being
BOOL) there is absolutely no guarantee you will still
get a non-zero result.  As I've explained, the typical
conversion will just take the low order byte of the int
or pointer - which can easily be zero even though the
rest of it is not.  So:

  ((BOOL)(somePtr))

is not at all the same expression (even in logical
terms) as:

  (somePtr != nil)


I'm pretty sure this is what was causing the erratic
probeDisplay behaviour I was experiencing.  I can't
demonstrate it definitively *because* it is so
erratic.  Since 255 out of 256 possible values for the
low order byte of the pointer in question will *not*
give any problem, it's quite rare.  But given the
testing I *have* been able to do, and the analysis I've
given above, then I feel pretty confident this *is* the
problem.

Final point: although my fix above for
-isProbeMapDefinedFor: is perfectly OK, a preferred fix
is probably:

  -(BOOL) isProbeMapDefinedFor: (Class) aClass {
    return ([classMap containsKey: aClass]);
  }

- the -containsKey: method actually correctly checks
for the nil value.  This version of the fix is probably
the one Glen will incorporate in the next release.

That's it.  Now just remember to repeat 10 times every
day for the next week, "BOOL is not int" (;-)

Cheers,

Barry.


-- 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| Barry McMullin, ALife Group,               |    address@hidden |
| Santa Fe Institute, 1399 Hyde Park Road,   |  Voice: +1-505-984-8800 |
| Santa Fe, NM 87501, USA.                   |  FAX:   +1-505-982-0565 |
| http://www.eeng.dcu.ie/~mcmullin           |                         |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



                  ==================================
   Swarm-Support is for discussion of the technical details of the day
   to day usage of Swarm.  For list administration needs (esp.
   [un]subscribing), please send a message to <address@hidden>
   with "help" in the body of the message.
                  ==================================


reply via email to

[Prev in Thread] Current Thread [Next in Thread]