views:

165

answers:

4

How would you get the dreamed DRY ideal in this sample, in the language of your choice:

drawLine(Point(0, 0), Point(w, 0));
int curRowY = 0;
for(int row=0; row<rowHeights.size(); row++) {
 curRowY += rowHeights[row];
 drawLine(Point(0, curRowY), Point(w, curRowY));
}

drawLine(Point(0, 0), Point(0, h));
int curColX = 0;
for(int col=0; col<colWidths.size(); col++) {
 curColX += colWidths[col];
 drawLine(Point(curColX, 0), Point(curColX, h));
}

Note: A multitude of ad-hoc preprocessor macros is likely to be extremely less readable&writable so that's out.

A: 

Maybe, in this case, you are taking DRY to too much of an extreme?

Nonetheless, as an academic exercise, I am looking forward to seeing whether anyone can come up with a solution that is as readable as your current code - but without the apparent duplication!

Stewart
indeed: 'readable' is the key.
+1  A: 

[I agree with Stewart, but I press on as an academic exercise.]

Tricky...

In a way, you're not really repeating yourself; you're doing two similar things that are (literally and figuratively) orthogonal to each other.

I suppose you could do the following, though it's no more readable and certainly no more performant:

[pseudo C#]:

void DrawGrid()
{
    DrawLines(w, rowHeights, true);
    DrawLines(h, colWidths, false);
}

void DrawLines(int lineLength, int[] lineSeparations, bool isHorizontal)
{
    MyDrawLine(Point(0, 0), Point(lineLength, 0), isHorizontal);
    int offset = 0;
    for (int i = 0; i < widths.length; i++)
    {
        offset  += lineSeparations[i];
        MyDrawLine(Point(offset, 0), Point(offset, lineLength), isHorizontal);
    }
}

void MyDrawLine(Point startPoint, Point endPoint, bool isHorizontal)
{
    if (isHorizontal)
    {
        SwapXAndYCoordinates(startPoint);
        SwapXAndYCoordinates(endPoint);
    }

    drawLine(startPoint, endPoint);
}

On second thoughts, I think this is just a silly idea... :-)

teedyay
Yep. This one is a direct application of DRY as usually seen, but clearly doesn't improve on the original code. Still I am curious why this (and similar) situations don't seem to benefit from DRY like most do.
+8  A: 

The answer is simple: vectors. E.g.

repeatLines(Point start, Point end, Vector direction, int[] gaps)
    {
    drawLine(start, end);
    for (int i = 0; i < gaps.Length; i++)
        {
        Vector vector = direction * gaps[i];
        start += vector;
        end += vector;
        drawLine(start, end);
        }
    }

repeatLines(Point(0, 0), Point(0, w), Vector(1, 0), rowHeights);
repeatLines(Point(0, 0), Point(h, 0), Vector(0, 1), colWidths);
Juozas Kontvainis
And we have a winner: the key insight here is that repeatLines needed a new parameter to determine horizontal vs vertical. This has the advantage that you can do other angles as well by using other vectors.
Godeke
Oh yes! I *like* this!
teedyay
... and I just now realized the elegance of the function. It's not a contrived at all, it has generic applicability and can be succinctly described as "draw a series of parallel, equal-sized line segments with the given gaps". Gotta accept the answer: I doubt anyone will come up with a better idea!
A: 

If your grid is square, I think the following could work:

void drawGrid()
{
    for(int i = 1, offset = 10; i <= numPoints; i++, offset += 10)
    {
        Point p = new Point(i * offset, i * offset);

        drawHorizontal(p);
        drawVertical(p);
    }
}

void drawHorizontal(Point p)
{
    drawLine(new Point(0, p.y), new Point(width, p.y));
}

void drawVertical(Point p)
{
    drawLine(new Point(p.x, 0), new Point(p.x, height));
}
Outlaw Programmer
yeah IF each cell was square AND the whole grid was square. but it isn't ;]