D component programming is a joke (Was: Re: Component programming)

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Aug 1 22:24:32 PDT 2013


On Thu, Aug 01, 2013 at 10:34:24AM -0700, Walter Bright wrote:
> On 8/1/2013 2:23 AM, John Colvin wrote:
> >On Thursday, 1 August 2013 at 00:47:43 UTC, H. S. Teoh wrote:
> >Add in some code examples and that could make a nice article.
> 
> Yes, please!

Alright, so I decided to prove my point about component programming by
actually writing a fully-functional version of the calendar layout
program, so that I have a solid piece of evidence that component
programming lives up to its promise. :) In addition, I decided that for
maximum reusability, I want the output lines available in an input
range, with absolutely no binding to writeln whatsoever (except in
main() where the range is handed to writeln for output). In retrospect,
that was perhaps a bit too ambitious... I ran into a few roadblocks to
actually get the code working, so it took me a lot longer than I
anticipated to finish the code.

However, I *will* say that I'm very proud of the code: already there are
a few pieces that, if properly cleaned up and refined, probably deserve
inclusion in Phobos. Reusability FTW!! Now, just tell me if you've ever
seen a calendar layout program made of straightforward, reusable pieces.
I for sure haven't. I tried looking at the C code for the Unix cal
program once... It looked frighteningly similar to an IOCCC entry. :-/

My D version, however, built using ranges through and through, has many
pieces that are easily reusable. For example, if you wanted to output
only a single month instead, you could just call join("\n") on the range
of formatted month lines that the full year layout algorithm uses to
splice lines from multiple months together -- it's *that* reusable.

Anyway. Enough hand-waving in the air. Let the actual code speak for
itself:

	https://github.com/quickfur/dcal/blob/master/dcal.d

Now, w.r.t. the roadblocks I alluded to.

When I first started working on the code, my goal was to maximize usage
of existing Phobos facilities in order to show how many batteries D
already comes with. As it turned out, I could only use basic Phobos
components; some of the more complex pieces like frontTransversal, which
would've been perfect for the bit that splices formatted month lines
together, couldn't be used because it wasn't flexible enough to handle
the insertion of fillers when some subranges are empty. In the end, I
had to code that range by hand, and I can't say I'm that happy with it
yet. But at least, it's nothing compared to the hairy complexity of the
C version of cal.

Another place where I wanted to use existing Phobos components was
chunkBy. There's probably a way to do it if you think hard enough about
it, but in the end I felt it was simpler to just write the code myself.
Might be a failure on my part to recognize how to put existing Phobos
ranges in a clever enough way to achieve what I wanted. I did try to do
something similar to byWeek(), but somehow it didn't do what I wanted
and I decided to just code it by hand instead of investigating further.

By far the biggest roadblock I ran into was that after I wrote
everything up to (and including) pasteBlocks, my unittests refused to
work. Somehow, pasteBlocks kept repeating the first line of the output
(the month names, if you look at the unittest) and refused to advance
farther.  Eventually I traced the problem to Lines.popFront(), which
pops each subrange off the range of ranges. The problem is that this
only works on some ranges, but not others; if you pass the output of
formatMonths() straight to pasteBlocks(), it will NOT work. Why? Because
pasteBlocks return a std.algorithm.Map object, which recreates the
subrange each time, so Lines.popFront() is only popping a temporary copy
of the subrange, not the real thing. I was about to give up and try
another approach, when out of the blue I decided to try and see if I
could stuff the range returned by formatMonths() into an array, and then
pass *that* to pasteBlocks() -- and behold, it worked!!

This was a totally unexpected fix, that a newbie probably would never
have thought of, so this is a potential trap for newcomers to D who
expect components to just be pluggable. In retrospect, it makes sense --
you need to somehow buffer the ranges of formatted month lines
*somewhere* in order to be able to splice them together out of their
natural depth-first outer/inner range order. But this is not obvious at
all from first glance; perhaps it's a sign of a leaky abstraction
somewhere. We should probably look into why this is happening and how to
fix it. And there should be a way to test for this in pasteBlocks'
signature constraint so that future code won't fall into the same trap,
but I can't think of one right now.

Once this last bit worked, though, everything fell into place quickly.
After all unittests were passing, no more bugs were found!! The program
can print beautifully laid out calendars with no problems whatsoever.
I'm so in love with D right now... If I'd done this exercise in C or
C++, I'd be spending the next 2 days debugging before I could present
the code for the world to see. D ranges and unittest blocks are t3h
k00l.


T

-- 
It always amuses me that Windows has a Safe Mode during bootup. Does that mean that Windows is normally unsafe?


More information about the Digitalmars-d mailing list