I'm not sure if I'll do a lot of this, but today I was working and realized that there's something I've been using in C/C++ that I really love. I also was thinking about something in C/C++ that I don't love, and how Objective-C does is so much better. So I decided to have a Feature of the Week - for at least this week.
C/C++: Assignments Everywhere
I didn't used to do it, but of late, it's made my code so much more readable to me. Maybe it's me, maybe I've gotten to be a better coder, but I used to write a lot of code that looked like this:
variant *a = getVariant(3);
if (a == NULL) {
cLog.error("unable to get variant #3");
}
a = getVariant(2);
if (a == NULL) {
cLog.error("unable to get variant #2");
}
and it's even worse in a re-used iterator:
std::vector<std::string>::iterator it = mClients.find("Steve");
if (it != mClient.end()) {
// do something with the fact we have 'Steve'
}
it = mClients.find("Jeff");
if (it != mClient.end()) {
// do something with the fact we have 'Jeff'
}
But it doesn't have to be this way. With the C/C++/ObjC ability to have assignments anywhere, you can compress this all very nicely:
variant *a = NULL;
if ((a = getVariant(3)) == NULL) {
cLog.error("unable to get variant #3");
}
if ((a = getVariant(2)) == NULL) {
cLog.error("unable to get variant #2");
}
and the re-used iterator becomes:
std::vector<std::string>::iterator it;
if ((it = mClients.find("Steve")) != mClient.end()) {
// do something with the fact we have 'Steve'
}
if ((it = mClients.find("Jeff")) != mClient.end()) {
// do something with the fact we have 'Jeff'
}
Sure, this isn't rocket science, but it's allowed my code a new level of readablility - certainly in the looping where the definition of the variable is outside the loop and the assignment is within it. There's nothing like readable code. It's a real benefit.
ObjC: The Clever Mr. nil
But one thing I love about ObjC is it's use of the nil. It's far more than the C/C++ NULL because you can message nil with anything, and that's where it's so valuable for code readability. Take the following code, for instance. It's going to get a few things in a data structure, and to do it right, and by "right" I mean safely so as not to get null pointer seg faults, we need to do something like this:
TPClient *boss = getBoss();
if (boss != NULL) {
Channel *chan = boss->getChannel("red");
if (chan != NULL) {
cLog.info("red channel has %d bits", chan->getBits());
}
}
Sure... you can be careless, and write this all optimistically as:
cLog.info("red channel has %d bits", getBoss()->getChannel("red")->getBits());
but if there's any problem in those calls, it's a SegFault to be sure. But ObjC and nil can handle this nicely:
[NSLog @"red channel has %d bits", [[[self getBoss] getChannel: @"red"] getBits]];
and the latter is so much more readable. It's the fact that you have to code defensively that kills the readability of the code. Not so in ObjC. It handles the possibility of any one of these steps returning a nil, and carries on as if that's expected behavior.
There you have it. My favorite little language do-dads for today.