Derek Parnell wrote:
On Tue, 10 Feb 2009 14:01:29 -0800, Walter Bright wrote:

Derek Parnell wrote:

 ... it creates a new problem; code
duplication.
I don't think that duplicating a small run of code is a problem.


My apology. The problem is more than run-time performance issues. The more
pressing problem, IMHO, is the one of maintenance costs. Duplicated code is
a significant cost burden. Not only may each duplication require updating,
but there is extra effort in analyizing every duplicate to see if it *does*
need updating. And every act of updating increases the opportunity for
introducing bugs.

Let's take an example, like the enum for O_XXXX in std.c.linux.linux. Some of those values are common between platforms, and some are unique to particular platforms. So you might be tempted to write:

enum
{
    O_RDONLY = 0,
    O_WRONLY = 1,
    O_RDWR = 2,
    O_CREAT = 0100,
version(OSX) O_SYMLINK   = 0x200000,
}

instead of:

version (linux)
{
  enum
  {
    O_RDONLY = 0,
    O_WRONLY = 1,
    O_RDWR = 2,
    O_CREAT = 0100,
  }
}
else version (OSX)
{
  enum
  {
    O_RDONLY = 0,
    O_WRONLY = 1,
    O_RDWR = 2,
    O_CREAT = 0100,
    O_SYMLINK   = 0x200000,
  }
}
else
{
    static assert(0); // need platform support
}

The first version is definitely shorter. But is it easier to maintain? I argue that it is *harder* and *buggier* to maintain. Let's say I am using linux and I need to add O_APPEND to it. I just stuff it in like:

enum
{
    O_RDONLY = 0,
    O_WRONLY = 1,
    O_RDWR = 2,
    O_CREAT = 0100,
    O_APPEND = 02000,
version(OSX) O_SYMLINK   = 0x200000,
}

and it works great for linux. Now I port my code to OSX, and it mysteriously dies. After much frustration, I discover that O_APPEND for OSX is 8, not 02000. (Yes, this kind of thing has happened to me. I only found it by suspecting the problem, and then going through every fscking definition comparing it to the one in the system .h file. Yeech.)

Now let's try the other way. I add O_APPEND to the linux branch, and linux works great. Now I port to OSX, and the compiler dies with "O_APPEND is undefined". I know immediately exactly what is wrong, look up the .h file, and insert the right O_APPEND into the OSX version of the declaration.

Furthermore, when I build a FreeBSD version, the compiler bings at me for every declaration that needs some porting attention, instead of silently using the wrong values.

This would be even better if the OSX and linux declarations were split into separate "personality" modules. That way you can develop happily on OSX without fear of accidentally breaking linux support. You can defer dealing with the linux version until you actually on the linux machine and are in an efficient position to take care of it.


Coders need languages that help them do their job, and one way to help is
to reduce the need for duplicated code.

I know there's a risk by getting in the way of programmers wanting to do things a particular way. To do it, I have to be pretty convinced that there is a better way. The C preprocessor is like crack, everyone knows it's bad but they snort it anyway because it feels so good <g>. C++ was supposed to get a bunch of features that obviate the preprocessor, but have a look at the premier C++ library - Boost - which uses the preprocessor heavily. Boost also uses every last iota of what the preprocessor can do, because if your cpp implementation is not 100% most of Boost will not compile (I know this from experience, DMC++ is 100% now).


Duplicating (nearly all of a) source file is NOT, repeat NOT, a
satisfatory solution.
I'm not insensitive to this as I do it myself in maintaining Phobos. It is a problem, but not a huge one. I find that the meld utility (on linux) makes this chore a snap.

Because of D's limited support for text macros, I am using third party
tools to get me out of this problem too.

meld is particularly nice. Andrei showed it to me:

http://www.linux.com/feature/61372

Reply via email to