On Mon, Feb 28, 2022 at 9:10 AM Larry McVoy <lm@mcvoy.com> wrote:
So I'm curious, did Plan 9 run on a similar number of architectures and
support a similar number of graphics cards?

Yes, it did.

If it did that, nicely, then you have a great point, the X11 people
(and most of us) clearly missed a better way to do things.  If this is
the case, I'd like to understand how you did it because just including
different definitions doesn't begin to scratch the surface of what the
#ifdefs did in X11, there were tons in the actual code.

#ifdef has more or less always struck me as the solution to the wrong problem. "We have all this code and we want to shoehorn it into a new environment," instead of, "we have many environments, so we carefully structure the code to accommodate the differences." Of course, the latter is harder than the former, but it also pays larger dividends over time as compared to the former.

Maybe the constant system interface made all the difference, that
could be. 

If it supported a much smaller number of targets, well, sure, it's
easier to be clean if you have a clean set of targets.

In fairness, a meaningful comparison is hard: plan9 ran on ~a dozen different architectures over its lifetime, but never supported near the variety of software or workloads of Unix, and didn't exactly "compete" in the market the way Unix did. The PC port in particular supported oodles of graphics cards at one point, but not as many as X did, mostly because there weren't all that many folks working with the unsupported cards, so there wasn't a lot of motivation to write tons of drivers.

Could it have retained its elegantly clean structure over time had things evolved differently? That's impossible to answer, but I'm sad that we never got the chance to find out.

I remain grateful for the #ifdefs, I could make enough sense of it
all to bring up X11 on every platform I worked on.  It wasn't pretty,
there was a ton of "I don't recognize this $WHATEVER, what happens if
I just #if 0 around the whole thing?  Wow, it compiles, lets see if
I get a window system.  Yep, I do.  Shrug."  That limited what I had
to understand to the much smaller subset of code I was actually
going to run, yeah, that set of #ifdefs was a mess but not such
a mess that I didn't get a working X11. 

I'm not arguing that #ifdef is good, I'm just acknowledging it had
a lot of benefit to me, and _for me_, the cost was worth it in that
instance.  I could have X11 working in less than a day.

I do think that #ifdef, used extremely judiciously, can have some utility: for example, compiling out debug code by setting a constant.  Consider:

#ifdef NDEBUG
const bool DEBUGGING = false;
#else
const bool DEBUGGING = true;
#endif

static inline
void
DBG(const char *fmt, ...)
{
    if (DEBUGGING) {
        va_list ap;
        va_start(ap, fmt);
        vfprintf(stderr, fmt ap);
        va_end(ap);
    }
}

    DBG(foo);

if `NDEBUG` is defined, then the body of the static inline becomes, `if (0) { ... }` and one hopes our compilers are sufficiently smart to elide the entire thing.

The biggest problem with #ifdef wasn't so much that it existed, but rather that it was used for too many things that it wasn't well-suited for. The second biggest problem was that it was semantically unaware of the language; it was purely textual. Bummer.

I do get your point about abstracting the interface differences away,
I actually hate #ifdefs in the code with a passion so in BitKeeper we
had all that stuff buried under the abstractions.  We made everything
look like Unix, even on Windows, except for fork().  I haven't called
fork() directly in close to 20 years, we picked up spawn() and made that
work everywhere.  The abstraction layer cuts down on the #ifdefs in the
code a LOT.

Agreed. But getting those abstractions right requires experience and taste. #ifdef is a blunt took for a nuanced problem.

        - Dan C.


On Mon, Feb 28, 2022 at 06:22:28PM +1100, Rob Pike wrote:
> Plan 9 had the distinct advantage of a constant system interface at the
> source level. X11 did not, but it also made essentially no attempt to
> abstract it away, so the lines starting #ifdef often outnumbered the actual
> code. I couldn't make hide nor hair of it, and had no way to reliably test
> any change.
>
> C with #ifdefs is not portable, it is a collection of 2^n overlaid
> programs, where n is the number of distinct #if[n]def tags. It's too bad
> the problems of that approach were not appreciated by the C standard
> committee, who mandated the #ifndef guard approach that I'm sure could
> count as a provable billion dollar mistake, probably much more. The cost of
> building #ifdef'ed code, especially with C++, which decided to be more
> fine-grained about it, is unfathomable.
>
> Google alone might well count for many millions of dollars in wasted
> compilation equipment. I remember giving a Plan 9 demo to someone soon
> after I got to Google. None of the features of the system were of interest.
> The thing that astounded my audience was the ability to build the kernel on
> a P90 in 20 seconds or so, and the window system in under 3. At that time,
> a build of a Google server would require hours on a large distcc cluster.
>
> I still shudder to think of it. It's worse now, of course, far worse, but
> Google has far larger clusters to handle it and some improvement in
> tooling. However, the #ifdefs persist.
>
>
> Tom Cargill warned Bjarne about this around 1984, but the plea fell on deaf
> ears.
>
> -rob
>
>
> On Mon, Feb 28, 2022 at 12:07 PM Douglas McIlroy <
> douglas.mcilroy@dartmouth.edu> wrote:
>
> > > The X11 tree was a heavily ifdef-ed.  And it needed to be, I don't have
> > > an answer as to how you would reuse all that code on different hardware
> > > in a better way.
> >
> > Plan 9 did it with #include. The name of the included file was the same for
> > every architecture. Only the search path for include files changed. Done
> > with
> > care, this eliminates the typical upfront #ifdefs.that define constants
> > and set
> > flags.
> >
> > Other preprocessor conditionals can usually be replaced by a regular if,
> > letting
> > the compiler optimize away the unwanted alternative. This makes
> > conditionals
> > obey the scope rules of C.
> >
> > Doug
> >

--
---
Larry McVoy                  lm at mcvoy.com             http://www.mcvoy.com/lm