[Developers] Interface functions
Bert Bril
Bert.Bril at opendtect.org
Mon Nov 26 15:41:19 CET 2007
Hi all,
This is a general 'tutorial' type of posting - experienced programmers
may want to stop reading now. Thus, if you read this ... etc.
Lately, I've been explaining a lot about how to make nice class
interfaces - in the 'physical' sense. One aspect of this is the form in
which you present class functions. The form is a signal for users of
your class. Don't underestimate this: no matter how good you make your
classes, not only will people hate using them if the form is awful, you
will cause a lot more errors in the code that uses your class. And
lastly, even while you're building the class you will fall in the traps
yourself.
There are many aspects that are important, and I'll pick out a few:
1) Naming
2) Parameters
3) Return value
4) const-correctness
I'll take a look at (1) and (2) for now.
(1) The naming. A good function name says *exactly* what it does. Do not
underestimate this; I've seen lots of code from long-time professionals
that went wrong just because they didn't question their function naming
enough.
Say you have a Well object which can be planned, being drilled, or
finalised. The following function names may be right in some
circumstances, but are questionable at best in other:
* drilling() - what is this? isBeingDrilled()?
* getDrilling() - a drilling method? The 'get' suggests that the
function does some work to give the answer. It may return a 'Drilling'
object. Maybe you mean drillingStatus()?
* close() - what does it do? close down the well? endDrilling() maybe?
* investigate() - investigate what? And what would be the return value?
And so forth. There is a lot of literature on this, but the main idea is
that you place yourself in the position of the user of the class, and
think about the code (s)he will be writing. Is it easily readable? Would
there be misunderstandings? Is the function easy to find - the place in
the class, 'standard' naming, in the right class? What about the class
name itself?
(2) The parameters. Some parameters are fundamental types; you can often
make the interface easier to understand by giving a name to the
variable. This can save then unnecessary comments:
void setDrillRate(float rate,float tolerance_pct=10);
As you may know, we at OD like to minimize the amount of comments (I
know, sometimes a bit more comment would be useful). But sometimes you
have to make it very clear what you expect, and then comments may be
very useful. In that sense, a peek into the work of Bertrand Meyer (in
particular the 'design by contract' concept) may be useful.
Getting back to the 'minimum comments rule' (see also opendtect.org): we
want to let parameters speak for themselves as much as possible. When
you pass objects or references to them, you need to be careful to choose
exactly the right way. Here's how it's done in general:
* pass the object by value if it's small and simple
* pass the object by pointer if it may be null or in case you 'give it
away'.
* pass the object by reference if it's mandatory
Then there's the difference between const and non-const objects:
const X* : You can pass it, but you don't have to
X* : If you pass it, it becomes mine
const X& : You have to pass it, but I won't change it
X& : You have to pass it, and I will probably change it
The key here is to make sure the user of the class can see what you need
just by looking at the interface. Very often you do not need to give the
parameter a name in the header file, compare:
void drill(const DrillingMethod&);
with
void drill(const DrillingMethod& drillingmethod);
The parameter name is bogus and even a maintenance burden. Get rid of it.
One note about life time of the object. In many cases you just need the
object during the function itself. If the function is a constructor,
this is not that clear. Sometimes you want to be able to keep looking at
the passed object until long after the constructor is finished,
sometimes not. This is very important for the caller of the function,
because they will have to keep the object 'alive' in the former case. If
it's not 100% clear from what the class does, comment it. There is no
way to signal it otherwise. The default is that you make a copy of every
object that you will need after the constructor, and therefore that
every function is independent of the lifetime of the object after it's
called.
I'll be back on the other issues (I hope).
Bert
--
-- Bert Bril / OpendTect developer at dGB
-- Nijverheidstraat 11-2, 7511 JM Enschede, The Netherlands
-- mailto:Bert.Bril at opendtect.org , http://opendtect.org
-- Tel: +31 534315155 , Fax: +31 534315104
More information about the Developers
mailing list