Social Question

LostInParadise's avatar

What is the balance in programming between brevity and understandability?

Asked by LostInParadise (31913points) September 16th, 2011

Let me give a small example to illustrate what I mean, a simple programming problem of a type that I am sure has been solved many times before. I needed to know how many days it has been since the previous Thursday, where the answer is 0 if the current day is Thursday.

The way that a typical non-mathematically oriented programmer would do this would be to call a function to get the day of the week of the current day and store it in a variable wkday. (In the language I was using, the function return value goes from 1 for Sunday to 7 for Saturday). Then go through all the 7 cases and assign the number of days to some variable daysBack. This is perfectly reasonable. It takes negligible computer time and would require a single comment to indicate what is going on, saying something like /* Find number of days since previous Thursday */.

This solution upset my aesthetic sense. Since Thursday is 5, why not just calculate wkDay – 5? The problem of course occurs if wkDay comes before Thursday. We end up with a negative number telling how to get to the following Thursday. The solution is to add 7 to get back to the previous Thursday. So the code would look like:

daysBack = wkDay – 5
if daysBack < 0 then
daysBack = daysBack + 7

How to get rid of that annoying if statement? Oh, we are just doing modular arithmetic, so I could write:

daysBack = (wkDay – 5) mod 7

The problem here is that most programming languages, will not change negative numbers to positive ones. -3 and -10 mod 7 come back as -3. There is a simple solution. Add 7 to the value in parentheses. What we get is congruent mod 7 to the original with no negatives to worry about.

daysBack = (wkDay + 2) mod 7

The problem now is that anyone looking at this final solution will have a hard time figuring out what the code does, including me if I have to revisit the code. It will require an additional comment, countering any justification that I might have of making the program more readable.

Having spent all this time to come up with a one line solution, I am sticking with it. Should I have just stuck with the original?

Observing members: 0 Composing members: 0

19 Answers

bobbinhood's avatar

Deleted by me. I was having a brain fart.

tom_g's avatar

Not sure if this works, but what about

daysBack = 7 – (5 – wkDay)

So if today is tuesday (wkDay = 3), then daysBack would = 5.

If today is Sunday (1), then daysBack would = 3.

Note: This should also work if today is Friday (6). In that case, daysBack = 8.

CWOTUS's avatar

How about a simple IF to check if the current wkday is > or < Thursday (or equal to, for that matter):

IF wkday >= 5 THEN (comment: today is greater than or equal to Thursday)
Diff = wkday – 5
ELSE (comment: today is less than Thursday)
Diff = 5 – wkday
END IF

tom_g's avatar

@CWOTUS – That will work, but @LostInParadise wants to “get rid of that annoying if statement”.

This will work:

daysBack = 7 – (5 – wkDay)

bobbinhood's avatar

@tom_g Note: This should also work if today is Friday (6). In that case, daysBack = 8. But on Friday, daysBack should be 1. It has only been one day since the most recent Thursday, not 8.

tom_g's avatar

@bobbinhood….

daysBack = 7 – (5 – wkDay)
daysBack = 7 – (5 – 6)
daysBack = 7 – (-1)
daysBack = 7 + 1
daysBack = 8

I am reading his problem to be the Thursday of the previous week. Maybe I’m interpreting this incorrectly.

EDIT: Now that I have re-read this, maybe I am incorrectly interpreting this (??).

CWOTUS's avatar

@tom_g

Guess I should have read through the whole problem.

Well, I’ll be interested in a solution that doesn’t require an IF statement of any kind. Offhand, I don’t see one.

tom_g's avatar

@CWOTUS – No, I think you’re right. I think I read it wrong. C’mon @LostInParadise, I need some spec clarification.

tom_g's avatar

Ok, now my head hurts. If he wants the number of days since the most recent thursday, I think this should work…

daysBack = 2 – (wkDay – 5)

So, to test, I will look for the following results…

Tuesday (wkDay = 3) should result in daysBack = 4…

daysBack = 2 – (3— 5)
daysBack = 2 – (-2)
daysBack = 2 + 2
daysBack = 4

Friday (wkDay = 6) should result in daysBack = 1…

daysBack = 2 – (6 – 5)
daysBack = 2 – (1)
daysBack = 1

If it’s not the most recent thursday that he is looking for, but rather the thursday from the previous week, then use this:

daysBack = 7 – (5 – wkDay)

LostInParadise's avatar

The closest previous Thursday will be a number from 0 to 6. Any answers that are negative or greater than 6 will not work.

daysBack = 7 – (5 – wkDay) gives 8 when wkDay = 6

The modular arithmetic approach works. I just have to avoid negative numbers, which is easy.
Instead of daysBack = (wkDay – 5) mod 7, I add 7 in the parentheses to get
daysBack = (wkDay + 2) mod 7

It is very simple, but it looks very strange. For clarity, I could have written
daysBack = (wkDay – 5 + 7) mod 7

tom_g's avatar

Wait. You had a solution?

My solution also works (now knowing that it was the _most recent occurrence of a thursday):

daysBack = 2 – (wkDay – 5)

LostInParadise's avatar

Yes, when I asked if you could see the solution, I meant to imply that I had thought of one and that I was challenging you to see it. Sorry if I was misunderstood. What I meant to discuss was the trade-off between writing compact code and the danger that it might not be understood.

2 – (wkDay – 5) is not going to work. Suppose wkDay = 5, meaning it is Thursday. What I want is 0, but what you wrote gives 2.

HungryGuy's avatar

I say use what’s the clearest to understand.

This may be more code:

daysBack = wkDay – 5
if daysBack < 0 then
daysBack = daysBack + 7

but it is much less cryptic than this:

daysBack = (wkDay – 5) mod 7

Which is very important when you come back in 6 months to do revisions or debugging.

Don’t laugh, but in C and Javascript, I prefer to say:

x = x + 1;

rather than:

x++;

gasman's avatar

@LostInParadise: “daysBack = (wkDay + 2) mod 7” ...The problem now is that anyone looking at this final solution will have a hard time figuring out what the code does, including me if I have to revisit the code. It will require an additional comment, countering any justification that I might have of making the program more readable.

I’ve heard the phrase self-documenting code but I think even crystal-clear code requires some comments for adequate documentation. Using a single line of terse code to do what other implementations might take several lines to do has great aesthetic appeal, optimizing memory space and execution time.

Comments, however, are free. They don’t get interpreted or compiled or assembled. So I use tons of comments and never feel bad about it. You could write a whole paragraph including some pseudocode just to document the one actual line of code. I don’t think that’s so strange. I’ve written assembly code where every single instruction was commented. And sometimes a whole page of text to document some high-level subroutine.

On the other hand, what’s a few microseconds or kilobytes among friends? The “clunky code” where you handle each of the 7 days of the week as separate cases will certainly be clearer to somebody looking at it who doesn’t already know what’s going on (including you a few years from now!).

LostInParadise's avatar

@gasman , I agree with you about the importance of comments, but it is possible to have too much of a good thing. I have seen cases where there were so many comments that they actually got in the way of following the code.

HungryGuy's avatar

@LostInParadise – I agree, too. That’s why I prefer to put the comments in a flowerbox at the top of a subroutine. If a particular block of code within a subroutine is so complex that it needs its own comments, then make that code its own subroutine with its own comments.

LostInParadise's avatar

@HungryGuy, I agree with you up to a point, but sometimes I will put a comment at the start of a loop to explain what it does. You are absolutely right about the use of subroutines. It should take no more than about 2 minutes to get the gist of a subroutine. And don’t get me started on nested if statements that are five levels deep.

HungryGuy's avatar

@LostInParadise – Yeah! I’m with you there, too! Lasagna code can be just as bad as spaghetti code :-p

mattbrowne's avatar

Brevity plus good textual comments.

Answer this question

Login

or

Join

to answer.
Your answer will be saved while you login or join.

Have a question? Ask Fluther!

What do you know more about?
or
Knowledge Networking @ Fluther