Vincent Gable’s Blog

December 8, 2008

C Comment Trivia

Filed under: Bug Bite,C++,Objective-C,Programming | , ,
― Vincent Gable on December 8, 2008

//I'll bet \
you \
didn't \
know \
you \
could \
comment \
like \
this \
in \
C/C++/Objective-C

Well, you can. Finding out was a lot of fun, believe me.

At some point, I’m not sure when, I unknowingly put a ‘\’ at the end of a block of // comments. That commented out the method-call the block was referring to. As you might guess from the fact that it had a big comment talking about why it was there, this was an important method call. I spent more time then I want to admit debugging and staring at my code trying to see the problem. Finally I noticed “hey, the color of that code is like a comment, even though it’s not in a comment”.

The More You Know!

Optimize CPU Usage of Your Website

Filed under: Programming,Quotes,Usability | , , , , ,
― Vincent Gable on December 8, 2008

The thing is, web developers should test their pages for CPU usage the same as app developers do. And anytime a page is idle, CPU usage should be at 0%. Same as with any other app.

Brent Simmons

Last quarter notebooks outsold desktops for the first time. Netbooks, and iPhones have been exploding in popularity as well. That means a significant number of your website’s visitors will be running off a battery, and since battery life decreases proportionally with CPU load, you really do owe it to your users to do this. The internet shouldn’t be something you have to be plugged into a power outlet to use.

December 6, 2008

The Most Memorable Thing a CS Professor Ever Told Me About Software Engineering

Filed under: Programming,Quotes | , , , ,
― Vincent Gable on December 6, 2008

The first semester of my sophomore year, I took CS 337: Theory in Programming Practice from Jaydev Misra. On the last day of class, he talked about computer science in general, took questions, and let us out early. And on thing he said really made an impression on me. I’m quoting from what I remember today, I didn’t write the exact quote down, so this could very well be embellished or incorrect in some detail,

Even if we had the fast computers we have today in the 1960’s, and even if we had the internet, we could not have built a modern web-browser, because we did not understand enough about building programs of that complexity.

It’s amazing how young software development is as a discipline.

December 4, 2008

NSAssert Considered Harmful

Filed under: Bug Bite,Cocoa,MacOSX,Objective-C,Programming,Tips | , , , ,
― Vincent Gable on December 4, 2008

The NSAssert() function is unreliable, and therefore dangerous. Plain-old assert() is a better choice.

Note that #define NDEBUG disables assert(); and #define NS_BLOCK_ASSERTIONS disables NSAssert(). One kind of assert being disabled does not mean the other kind is. Nether kind of assertion is disabled by default when building in “Release” mode — you must be sure to disable them yourself. Be careful, a user will not appreciate the difference between a bug and a failed assertion — both are a crash.

assert() immediately stops your program with a SIGABORT signal. You can’t miss a failed assert(), its behavior is predictable, and it fails fast (link is a PDF).

But a failed NSAssert() behaves unpredictably. Sometimes it stops program execution, sometimes it does not and leaves the program in a strange inconsistent state. I have entirely missed NSAssert()s failing, because I did not look at the console. if(!expr) NSLog(); would have been a better choice in the those cases, because at least I would have known how it behaved.

According to Apple,

Assertion macros, such as NSAssert and NSCAssert … pass a string to an NSAssertionHandler object describing the failure. Each thread has its own NSAssertionHandler object. When invoked, an assertion handler prints an error message that includes the method and class (or function) containing the assertion and raises an NSInternalInconsistencyException.

Complicated! The complexity means it is possible to customize what happens when an NSAssert() fails. That sounds cool, but I’ve never heard of someone needing to actually do that.

If a framework catches NSInternalInconsistencyExceptions, then your program will keep right on running after a failed NSAssert(). I have had this happen to me several times. I apologize for not having taken the time to investigate what frameworks were catching what.

Apple could change what catches what with any software update.

Variability and complexity are the last things you want while debugging. There’s no reason to invite it them by using NSAssert() over assert(). Since NSAssert() is not guaranteed to stop your program, it can not be relied on to guard against data corruption, or anything worse then a predictable crash.

UPDATE 2009-06-01: You can annotate assert(), so it prints an explanation like NSAssert(), by &&ing in a string after the condition. For example assert(i < j) is a lot more useful with an explanation: assert(i < j && "unexpected cycle in graph") — on failure it prints

Assertion failed: (i < j && “unexpected cycle in graph”), function WillHalt(), file /path/to/code.m, line 30.

Optimize People’s Time Not The Machine’s Time

Filed under: Quotes,Usability | , ,
― Vincent Gable on December 4, 2008

Bruce “Tog” Tognazzini gives the best example I’ve seen of optimizing a person’s time, not a machine’s time

People cost a lot more money than machines, and while it might appear that increasing machine productivity must result in increasing human productivity, the opposite is often true. In judging the efficiency of a system, look beyond just the efficiency of the machine.

For example, which of the following takes less time? Heating water in a microwave for one minute and ten seconds or heating it for one minute and eleven seconds?

From the standpoint of the microwave, one minute and ten seconds is the obviously correct answer. From the standpoint of the user of the microwave, one minute and eleven seconds is faster. Why? Because in the first case, the user must press the one key twice, then visually locate the zero key, move the finger into place over it, and press it once. In the second case, the user just presses the same key–the one key–three times. It typically takes more than one second to acquire the zero key. Hence, the water is heated faster when it is “cooked” longer.

Other factors beyond speed make the 111 solution more efficient. Seeking out a different key not only takes time, it requires a fairly high level of cognitive processing. While the processing is underway, the main task the user was involved with–cooking their meal–must be set aside. The longer it is set aside, the longer it will take to reacquire it.

You also need to consider actual performance vr perceived performance, when optimizing a user’s time.

Cocoa Coding Style Minutia: All Forward Declarations on One Line is the One True Way

This is a very petty point, but I believe there’s a right answer, and since it’s come up before I’m going to take the time to justify the best choice.

Forward Declare Classes on One Line, Not Many Lines

Right:
@class Foo, Bar, Baz...;

This is the style that Apple’s headers generally follow, look at NSDocument.h for example.

Wrong:
@class Foo;
@class Bar;
@class Baz;
...

Programming languages are to be read by people first, and interpreted by computers second. I really do hope anyone in software engineering can take that as an axiom!

Therefore, always favor brevity above all else with statements that are only for the compiler. They are by far the least important part of the code base. Keeping them terse minimizes distractions from code that can and should be read.

Naturally, it’s very hard to find a statement that’s only for the compiler. I can only think of one such statement in Objective-C, forward declarations of an object with @class.

What Does @class Do?

@class Foo; tells the compiler that Foo is an Objective-C class, so that it knows how much space to reserve in memory for things of type Foo. It does not tell the compiler what methods and ivars a Foo has, to do that you need to #import "Foo.h" (or have an @interface Foo... in your .m file.)

@class Foo; #import "Foo.h"
Foo is a black box. You can only use it as an argument. You can also send messages to Foo.

What is @class Good For?

Since #import "Foo.h" does everything @class Foo; does and more, why would you ever use @class? The short answer is less time wasted compiling.

Lets say you have a Controller class, and it has an ivar that’s a Foo. To get it to compile, you put #import "Foo.h" inside Controller.h. So far so good. The problem comes when Foo.h is changed. Now any file that has #import "Foo.h" in it must be recompiled. So Controller.h has to be recompiled. So any file that has #import "Controller.h" in it must also be recompiled, and so on. Many objects that don’t use Foo objects, but do talk to the Controller (or to something that talks to something that talks to the Controller!) have to be rebuilt as well. It’s likely that the entire project would end up being rebuilt. With even a moderately sized project, that means a lot of needless compile time!

One solution is to put a forward-declaration, @class Foo;, in Controller.h, and #import "Foo.h" in Controller.m, and the few files that actually do something to Foo objects. @class Foo; gives the compiler just enough information to build an object with a Foo* ivar, because it knows how much space that ivar will need in memory. And since only objects that need to talk to Foo objects directly have any dependency on Foo.h, changes to Foo can be tested quickly. The first time I tried this solution in one of my projects, compile times dropped from minutes to seconds.

Readers Need Less @class

Forward declarations add value to the development process, as does anything that saves programmers time. But @class tells a human reader nothing. Which is why I say you should use them in your code, but minimize the space they take up, by putting them all on one line.

@class Foo; tells a reader that “Foo is black-box that is a class.” That adds no useful information.

If the reader does not care about what a Foo is (they are treating it as a black box), then knowing that Foo is a class is useless information. Foo could be a struct, or a bit-field, or a function pointer, or anything else and they still would not need to know to understand the code.

Conversely, if they need to know what a Foo is to understand the code, then they need to know more then “it is a class”. They need to see Foo.h or documentation — @class just isn’t enough.

Exceptions

I want to again emphasize that this isn’t a big deal. I strongly feel that putting all forward declarations on one line is the right answer, but doing it wrong won’t perceptibly matter in the end.

So I don’t think there’s any reason to address exceptions to the rule. Do what you gotta do.

Best Practices

Use @class to speed up compile-times as much as you can, but use the keyword @class as little as possible, since it is for the compiler, not the person reading the code.

December 2, 2008

Bug In The Machine

Filed under: Announcement,Programming,Reverse Engineering | , , ,
― Vincent Gable on December 2, 2008

I was going through some old (OS 9 old at youngest!) backups, and found this dump from a MacsBug session. You can actually see a bug sitting in memory! To me it looks like the bug is inside an old television, with distortion sweeping across the screen, so some of the bug’s left side is wrapped around to the right.

 Displaying memory from 1D9F8CB0
  1D9F8CB0  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8CF0  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8D30  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8D70  •???•???•???•???•üÖ`´••••••P•••Ñ•y•pÄ@•••••Ä•@•••••••••H•••H••••
  1D9F8DB0  •••••••••••É9ÿ•••••••••••••••••••üçÄ´••••• •••‚ 0000000000000000
  1D9F8DF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8E30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8E70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8EB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8EF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8F30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8F70  0000000000000000000000000000000000000000000000000000000%***$*#**
  1D9F8FB0  #*$$*$*#*#**$$*00*$*$*$$**#*#*#*#*#*#**#%00000000000000*•!#•!!!!
  1D9F8FF0  !!!•!!!!!!!!!!!0%!!!!#!!!!!!!!!!!!!!!!!!*00000000000000*!"!•!!!!
  1D9F9030  !!••!!!!!!!!!!!0.!!••!!!!!!!!!!•!•!!•!!!#00000000000000*!!!(•!!!
  1D9F9070  !!!(•!!!!!!!!!!0%!!((!!!!!!!!•!!!!!!!!!!*00000000000000#!!! ••! 
  1D9F90B0  •••••••••••••••0*••!•••••••••••••••••••••00000000000000*!!!•••00
  1D9F90F0  •••••••••••••••0#••!•••••••••••!00•••••••00000000000000#!!!••#0/
  1D9F9130  0&••••••••••••••!••! •••••••••+0$0.••••••00000000000000#!!!•!0••
  1D9F9170  !00#••••••••!000000$!•••••••!00!••,••••• 00000000000000*!!!•0%••
  1D9F91B0  ••%0%••••••%00000000/••••••,0.••••%0•••••00000000000000$!••00•••
  1D9F91F0  ••!*00••••000000000000••••00!••••••00#•••00000000000000*!!/0••••
  1D9F9230  ••!••/0$•00000000000000••0$••••••••*0%!•!00000000000000#•#0$••••
  1D9F9270  •!•••!$•*00000000000000%•!•••••••!(•*0*• 00000000000000*•00••••!
  1D9F92B0  (•••••••0000000000000000•••••••!* •••%0•!00000000000000*00••••!0
  1D9F92F0  &!•••••/00000000000000000!•••'$00!••••00*00000000000000*•*!•••00
  1D9F9330  000••••000000000000000000•!•*00/%0••••••*00000000000000$!•!••$0•
  1D9F9370  ••%00•!000000000000000000*$00%!••0#••••••00000000000000$!••••0.•
  1D9F93B0  ••••$•%0000000000000000000•%!•••••0!••••!00000000000000*!•(•00••
  1D9F93F0  •••(••00000000000000000000!! •••••/0"••••00000000000000#!!!$0•••
  1D9F9430  ••!!••00000000000000000000•!!••••!#0%!•••00000000000000*!!*0*•••
  1D9F9470  ••!•••00000000000000000000*!•••("!••0#•••00000000000000*!!0,••••
  1D9F94B0  •! •••00000000000000000000#!•!•!••••/0•• 00000000000000#!%0!••••
  1D9F94F0  ••••••00000000000000000000#•*••••••••0%!!00000000000000*!•$•••%0
  1D9F9530  0000#•00000000000000000000#%00000%•••!•!•00000000000000*!!!••!0%
  1D9F9570  *•! ••00000000000000000000*#*$!!•0!•••••*00000000000000*!(!••00!
  1D9F95B0  ••••••00000000000000000000••!!•••/0•••••#00000000000000#!!!•$0••
  1D9F95F0  ••••••%0000000000000000000!(!!••••0%•••••00000000000000*!!!(0*••
  1D9F9630  ••!!!!.000000000000000000.!!!••!!!%0-!••!00000000000000*!(•0,•••
  1D9F9670  ••!•!•!000000000000000000•#*•••••••,0••••00000000000000$!!$0••••
  1D9F96B0  •!•$00•/00000000000000000•00/*••••••0.!•!00000000000000*!!!!••••
  1D9F96F0  #000•••!0000000000000000$(•.00%••••• •!!•00000000000000*!!••••••
  1D9F9730  00!•••••/000000000000000!!(!!*00•••••• !•00000000000000$!!(••••$
  1D9F9770  0•••••••!00000000000000*!!!!!•!0!••••••!$00000000000000#(!!••••0
  1D9F97B0  ,••••••!!$000000000000$!!!!!!•!00•••••••$00000000000000*!!!••••0
  1D9F97F0   ••••!••••!0000000000$(!!!!!••••0*••••••!00000000000000#!!!•••,/
  1D9F9830  ••••!!!•••••00000000*!!!!"!!••••/0••••••!00000000000000*!!!•••0!
  1D9F9870  ••••••••••••••$%%%•!!!!!!!!••••• 0)••••••00000000000000#!!!••/0•
  1D9F98B0  •••!!•••••••••.,/•(•!!!!!!•••••••0,!!••••00000000000000*!!!••0!•
  1D9F98F0  •••••••••••••00000•!!!!!!••••••••!0!!••••00000000000000#!!!•••••
  1D9F9930  ••!!••••••••.000000!!!!!••••••••••••!!••!00000000000000$••!•••••
  1D9F9970  ••!•••••••••0000000!• •••••••••••••••!•••00000000000000*!•!•••••
  1D9F99B0  •!!•••••••••0000000$!••••••••••••••••!!•!00000000000000#!!!•••••
  1D9F99F0  •!•••••••••!0000000*!"••••••••••••••••!• 00000000000000#!!••••••
  1D9F9A30  ••••••••••••0000000#!!••••••••••••••••••!00000000000000#!!!•••••
  1D9F9A70  ••••••••••••0000000•!!!••••••••••••••••••00000000000000$!"••••••
  1D9F9AB0  •••••••••••••000000!!!••••••••••••••••••!00000000000000*!!!•••••
  1D9F9AF0  •••••••••••••/0000•(!!!••••••••••••••••• 00000000000000#!•!•••••
  1D9F9B30  ••••••••••••••!*$•!!!!!••••••••••••••••••00000000000000#!!••••••
  1D9F9B70  ••••••••••••••••!!!"!!!••••••••••••••••••00000000000000*!!!•••••
  1D9F9BB0  •••••••••••••••••!!!!!•••••••••••••••••••00000000000000%$#*!!•! 
  1D9F9BF0  •!!!•• ! •! • • !#*$*#!!!•! !! !•• ! • !*00000000000000000000000
  1D9F9C30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9C70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9CB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9CF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9D30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9D70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9DB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9DF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9E30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9E70  0000000000000000000000000000000000000000000000000000000000000000
 Unrecognized symbol 'prinf'
 Closing log

I swear this is a real memory dump of a sold-for-money application that I didn’t have any part in writing. Unfortunately I don’t remember some specifics, like which application it was.

« Newer Posts

Powered by WordPress