Ximian Hackers Self Help: Part 2
Novell Cool Solutions: Trench
Reader Rating
from 1 ratings
|
Digg This -
Slashdot This
Posted: 14 Jul 2004 |
These self-help letters began as a post to an internal Ximian development list. We've posted them here in a three-part series to provide you with insight into the development process at Ximian and within the GNOME community at large.
Contents
- Did You Know?
- Good Taste and Readability
- Booboo: Real World Usage
- Another Stylistic Point
- Inheriting vs. Aggregating
- Summary
Did You Know?
Did you know that an interface is not like a class, inasmuch that it specifies no data/method hiding, layout or implementation detail? It is just pure interfacing information, un-cluttered by dangerous crud such as public data elements.
Yes? Good.
Good Taste and Readability
Variables should be scoped as tightly as possible. This removes ambiguity, and allows small self contained bits of code to be safely and easily split out to cure the "function growth hormone imbalance syndrome."
For example:
. static void
. a_new_function (int a)
. {
. int i;
.
. for (i = 0; i < 10; i++) {
. int j;
. char tmp_buf [10];
.
. for (j = 0; j < 10; j++)
. ...do something...
. }
. }
This also allows the side effects, and useful scope of the variable to be made explicit. It also reduces the possibilities for combat coding, means that having read that code you can discard 'tmp_buf' from your mental stack, it's also helpful for the compiler etc., etc.
Booboo: Real World Usage
Sadly, Booboo was developed at the end of the Bonobo 1.0 lifecycle and squeezed through the crack under the rapidly descending portcullis of freeze deadlines. Consequently it is not perfect. However, to re-mint a phrase, 'it sucks less'.
Say we have a complex industrial interface like this (from bonobo/samples/bonobo-class):
. module Bonobo { module Sample {
. interface Echo : Bonobo::Unknown {
* void echo (in string message);
. };
. }; };
Here, we need to inherit our new GtkObject from Booboo, but in particular the class must include the epv in-line.
. typedef struct {
. BoobooClass parent_class;
.
* POA_Bonobo_Sample_Echo__epv epv;
. } EchoClass;
Inside the gtk_type_new function, instead of gtk_type_unique we use:
. type = bonobo_x_type_unique ( . PARENT_TYPE, * POA_Bonobo_Sample_Echo__init, NULL, . GTK_STRUCT_OFFSET (EchoClass, epv), . &info);
Alternatively the type creation method can be replaced by:
. BONOBO_X_TYPE_FUNC_FULL (Echo, Bonobo_Sample_Echo, . PARENT_TYPE, echo);
Note. Using a 'PARENT_TYPE' macro is good practice for explicit classes, and helps reduce bugs [ inasmuch that Booboo is not at all tolerant of chaining errors ].
Clearly then we need to initialize the epv to point to our new method, so in the class_init method we do:
. klass->epv.echo = impl_Bonobo_Sample_Echo_echo;
So, to create a CORBA server we simply do:
. Echo *echo = gtk_type_new (echo_get_type ());
And to get the CORBA reference to it we do:
. Bonobo_Sample_Echo corba_ref = BONOBO_OBJREF (echo);
Tragically, Booboo made it too easy to inherit interfaces, which leads us nearly to the next point. But first...
Another Stylistic Point
During the last minute, with an in-depth review of over a badzillion lines of code it has been accurately calculated that a good program has approximately 6 bugs for every 1000 lines of code.
Luckily the prophets K&R[1] understood this concept when they invented C, and in order to minimize the number of bugs, and retain taste and sanity, they not only invented the 'for' construct ( for suffering while users ), but also a bracing convention of infinite and inscrutable wisdom thusly:
if (x is true) {
we do y
}
However, there is one special case, namely functions: they have the opening brace at the beginning of the next line, thus:
int function (int c)
{
body of function
}
Note that the reduction in line count (and therefore in the number of bugs) not only makes the code beautiful, but satisfies the stringent new Kyoto requirements on the preserving of that vital non-renewable resource: visible screen lines.
See also:
usr/doc/linux/Documentation/CodingStyle - chapter 2.
Inheriting vs. Aggregating
By cunningly opening a super size, 'new formula', can of worms, I plan to bring Gnome productivity to a total halt. Here goes: I've seen interfaces that look like something like this[2]:
interface Foot : Bonobo::BodyPart {
long getNumberDigits ();
void setCompressiveForce (double forceInNewtons);
};
While this is all well and good[3] there is no particularly good reason to derive a Foot from BodyPart. Indeed, it ties the perfectly generic and re-usable Foot interface to a body, and ignores the thousands of lattice propelled ACME mechanical feet not to speak of the humble prosthesis.
Consequently, before inheriting, consider:
- Do I really need to inherit?
- Is the derived interface unarguably, inextricably intertwined with the parent?
- Why is my interface totally non-generic? Could I be re-using a generic interface, such as a property bag?
- Is IRS estate tax form 7165(b) really worth filling in, and wouldn't it be better to leave everything to Battersea Dogs Home?
I have seen inheritance badly misused. Please write nice separate generic interfaces and aggregate them together.
Also, when you see a huge and cumbersome interface replete with get and set methods, consider using a PropertyBag instead.
Summary
- Scope your variables as tightly as you can bear.
- Use Booboo.
- Inherit only under great duress.
- Trust K&R.
[1] Kernighan, Brian W., and Ritchie, Dennis M. The C Programming Language, 2nd Edition. 1988 Prentice Hall.
[2] Seemingly following the axiom "If it breathes inherit from it".
[3] Upon cursory inspection, it does appear that a Foot is a BodyPart.
Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com
