17

I am an amateur programer in a CS class trying to learn proper programming skills. This is how my code looks, the edges of it extends to 103 columns.

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }

Before I had those super long variable names I had thing like i, j, k, but my professor insists that we are not to use variables like that in the "professional world" and that even shortened variables like lenWord are insufficient because people might assume it stands for "Lennard's World Literature". He says to choose meaningful variable names but by doing so I feel like I've broken the Golden Rule of coding to keep it under 80 columns. How do I get around this?

20
  • 26
    Keep going; add more useful names. Can you think of a way to describe cipherColumn + (rowSize*nextWord) + nextWord that makes it clear what that calculation is for, for example? I bet that name's shorter than the calculation, so you get a readability benefit and a reduced line length. Also don't align assignments, or you have to move them all if you rename the longest variable.
    – jonrsharpe
    Mar 18, 2017 at 3:17
  • 2
    Hmm.. so are you saying I should create a new variable and store the result of cipherColumn + (rowSize*nextWord) + nextWord into it so I can use it further? Is that what the pros do? I'm genuinely asking
    – RaulT
    Mar 18, 2017 at 3:26
  • 8
    Yes, that's my suggestion. I am a pro and it's what I'd do, so... some of them, at least.
    – jonrsharpe
    Mar 18, 2017 at 3:27
  • 11
    golden rule is to write code that can be read and understood. we write code for other people(!) not for machines. for machines there is machine code. for some, code that looks like you described (single letter names etc) is a lack of respect for other programmers (and future you - because you will forget in next few weeks or months). there is no reason to stick to 80 columns, it's not MS DOS in the '80s.
    – rsm
    Mar 18, 2017 at 4:41
  • 3
    @stijn yes, but it's the last time we needed it. just like i don't compile my c code for 8-bit 8086 processor in case i need to store it on punch cards, i also don't think 80 columns golden stardard has any significance in 21 century. we should stretch this technology, not sit in the '80s and think it makes us clever hackers. clever is simplicity, readability and pushing technology to its maximum. we have full-hd monitors, it's time to use it.
    – rsm
    Mar 18, 2017 at 8:43

6 Answers 6

24

Normally when I see code posted here like yours, I edit it, because we hate horizontal scroll. But since that's part of your question, I'll show you the edit here:

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
}

That break may be surprising, but it's more readable than the version with horizontal scroll, and it's better than shortening the names to i, j, and k.

It's not that you should never use i, j, and k. Those are fine names when indexing 3 nested for loops. But here the names are really my only clue about what you expected to be happening. Especially since this code doesn't actually do anything.

Best rule to follow on variable name length is scope. The longer a variable lives, the more fellow variables its name has to compete with. The name CandiedOrange is unique on stack exchange. If we were in a chat, you might just call me "Candy". But right now, you're in a scope where that name could be confused with Candide, Candy Chiu, or Candyfloss. So the longer the scope, the longer the name should be. The shorter the scope, the shorter the name can be.

Line length should never dictate name length. If you feel like it is then find a different way to lay out your code. We have many tools to help you do that.

One of the first things I look for is needless noise to get rid of. Unfortunately this example doesn't do anything, so it's all needless noise. I need something to work with so first let's make it do something.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
    return cipherColumn;
}

There, now it does something.

Now that it does something, I can see what I can get rid of. This length stuff isn't even used. This continue doesn't do anything either.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Let's make some minor white space tweaks, because we live in a world of source control and it's nice when the only reason a line gets reported as changed is because it's doing something different, not because part of it had to line up in a column.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn = 0;
    int cipherColumn = 0;
    int offset = 1;
    int nextWord = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Yeah, I know it's slightly less readable but otherwise you'll drive people crazy who use vdiff tools to detect changes.

Now let's fix these silly line breaks that we have because we're trying to stay under line length limits.

int calcCipherColumn(
        char keyWord[25], 
        char cipherText[17424],
        int rowSize, 
        char message[388]
) {
    int keyColumn = 0;
    int keyOffset = 1;

    int nextWord = 1;
    int cipherColumn = 0;
    int cipherOffset = (rowSize * nextWord) + nextWord;

    char key = keyWord[keyColumn];
    char keyNext = keyWord[keyColumn + keyOffset];

    while (key != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyNext != cipherText[cipherColumn + cipherOffset]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

There, now the logic in the loop is focused on what changes in the loop. In fact, everything except cipherColumn could be marked final. And hey! Look at that. We now have room to do it.

All I did was add 3 more variables, rename one, and rearrange them a little. And the result just happened to make the lines short enough to fit without a silly linebreak on !=.

Sure the names key and keyNext are not that descriptive, but they each only get used once, don't live that long, and most importantly aren't doing anything that interesting in the loop. So they don't need to be. By introducing extra variables we now have room to make their names long if we need to. Things change, so eventually we may need to. If we do, it's nice that we have breathing room.

I also took the liberty of showing you Jeff Grigg's form 6 variant style of laying out input parameters to respect line length restrictions.

3
  • Wow that's descriptive! Yea I know that code doesn't really do anything, I probably should have posted more than a small snippet of it but I guess I was trying to get the general idea of what the pros do in regards to code column length and variable names, but your answer showed some very sweet changes I will definitely implement in my codes from now on! One more question I have is: where do you find it suitable to make linebreaks? Before operators? Is there an accepted "standard"?
    – RaulT
    Mar 18, 2017 at 17:12
  • 1
    @RaulT spend some time reading whatever codebase your working in. It will give you an idea what you can use that won't surprise other coders. Follow a standards document if you have one. But the best is to ask fellow programmers and ask them how readable your stuff is. Oh and check out codereview.stackexchange.com Mar 18, 2017 at 19:00
  • I would add a comment below cipherOffset and explain the calculation because that formula is not obvious. You WILL forget why in three weeks.
    – Nelson
    Jun 25, 2017 at 5:44
15

Others have already made some useful suggestions, let me summarize:

  • 80 characters per line might have been a golden rule in the 80s. Nowadays most people agree that 100 to 130 characters are fine.
  • Use linebreaks inside your expressions.
  • Split lengthy expressions by introducing intermediate results.

I like to add another recommendation: Don't be dogmatic about long names! The larger the scope of a variable is, the more information has to be put into its name. And generally it is a good idea to keep the scope of variables small.

For example, if you have a variable for the column of your keyword encryption table and it is clear that there is only this one table used in the scope of your variable, it is fine to call it column or even col. If the scope is larger and there are multiple tables involved, it makes sense to call it keyWordEncryptionTableColumn.

Another example: If you have a loop with a body spanning two or three lines and have to use an index for accessing elements of an array, there is nothing wrong with calling the index i. In this context it is much more readable (for most people at least) than, say arrayIndexOfMyVerySpecialDataSet.

5
  • 1
    I agree with you answer. At work we use 80 char/line for c/c++ for legacy reason and because we use reviewboard. For C# 100 chars/line, sometimes I broke the rule and go slightly over 100 to keep readability.
    – peval27
    Mar 18, 2017 at 9:59
  • Wow, what a great answer!! All these answerable have been great, thanks for the help I appreciate it!
    – RaulT
    Mar 18, 2017 at 14:42
  • I strongly agree with pressing the idea that 80 character lines is outdated. It still applies for certain projects and places (mostly for consistency), but for many, it's just plain unnecessary. Many devs are using something like Visual Studio or IntelliJ on a full monitor and have a second monitor for other stuff (documentation, etc). They thus have a lot of screen real estate for their code. If you're only using 80 characters per line, you probably have a ton of unused space. And the 80 character limit hurts you! Especially when you consider that the standard lib can force long ass names.
    – Kat
    Mar 21, 2017 at 18:26
  • 1
    My point being that in some languages, there's really no avoiding the fact that 80 characters is a big limitation. So why have it unnecessarily? It also begs mention that pretty much all the big name editors and IDEs have excellent smart soft word wrap these days, which lets you not restrict line lengths AT ALL. You can let the line lengths be whatever the reader can see. They can resize their window to get a more optimal result. I've personally found this approach to be ideal sometimes. And I've yet to be disappointed with how this soft wrap works.
    – Kat
    Mar 21, 2017 at 18:29
  • Whenever you use simple variable names, you MUST 100% be certain of the scope. I spent three hours to learn about JavaScript closure.
    – Nelson
    Jun 25, 2017 at 5:48
3

I generally agree with you teacher. However, if you have a variable that you are going to use a lot in a faily large piece of code, it can be better to use a shorthand form for it after being explicit about its meaning. Like when you have a lot of complex arithmetic expressions and assignments, those do not read that well with long variable names.

About outlining:

ExtractMessage(char keyWord[25], char cipherText[17424],
               int rowSize, char message[388]) 

This serves no purpose, just limiting the line length does not make it more readable. If you want this to be readable, do this:

ExtractMessage(
  char keyWord[25],
  char cipherText[17424],
  int rowSize,
  char message[388]
  )
{

And then you may even want to align type identifiers (add a space after int ). However, be careful/restrictive with outlining initalizations or argument lists like this:

int keyColumn    = 0;
int cipherColumn = 0;
int offset       = 1;
int nextWord     = 1;

The trouble is when you change a name or add a variable, you may have to reformat the whole block to maintain the pretty look. It isn't for the work as much as for the meaningless changes you would introduce, it would look horrible in a version control system. Your co-worker would see you changed the file and do a diff with the prior version to see what you did. Then every line would light up as changed, obscuring the real change. It would depend a bit on the quality of the comparing tool used how bad this would actually be but in general it is not a good idea to make the code too personal and/or have the formatting of one line depend on the other.

Sometimes outlining can serve a purpose, if you have tens of consecutive lines that are almost the same it will be easy to spot where they are different if you outline them.

Note that a workplace may have some automated formatting going on that will just eradicate any fancy formatting you do to your code before submitting it to the version control system.

2
  • 1
    Personally the first code block in your answer is much more readable to me than the second.
    – Miles Rout
    Mar 21, 2017 at 20:22
  • 1
    never do the third, it's a maintenance nightmare to keep it like that.
    – jwenting
    Apr 11, 2017 at 10:05
3

A lot of stylistic conventions (not rules!) sprung up over the years due to limitations in programming environments. Back in punch-card days, you had a hard limit on the number of characters that could appear on a physical source line (which was why Fortran reserved column 6 for line-continuation characters). It wasn't that many decades ago that I was working on an 80x24 amber-on-black VT220 terminal; while the editors I used didn't limit lines to 80 characters, life was just a lot easier if you did your best to avoid horizontal scrolling.

Under older versions of Fortran (up to '77, IINM), you couldn't even have identifers that were more than 6 to 8 characters long. Even as late as the '80s, C would only guarantee that the first 8 characters in external names were meaningful (which is why some library functions have wonderfully descriptive names like strpbrk).

Of course, two decades into the 21st century, we don't have those limits anymore. There's no reason not to use more descriptive identifiers.

The thing is, in the right contexts, i and j and k are perfectly reasonable, meaningful names. If I'm iterating through an array or a vector in a loop and I just need something to identify the current element, i works perfectly well. I wouldn't use a name like currentElement - it isn't any more meaningful in that context, and it just adds visual clutter.

Having said that, your teacher isn't wrong in forcing you to think in terms of longer, more descriptive names for everything - life will be easier for you if you get into that habit first, and then learn where to economize as necessary. As someone who was at one time forced to fit everything into 8 characters or less, it's definitely better to err on the side of more information than less. As you gain more experience, you'll learn where you can economize on identifier length, and where you need to be a bit more descriptive.

2

Disclaimer: I'm exaggerating a bit here to make my point clearer. So take any superlative with a grain of salt.

Your teacher is 100% right: There is no "golden rule" about 80 characters anymore (unless you are writing linux code, that is). That rule was established because of the size of the terminals at the time, but nowadays, you easily cram over 150 characters in your enditor window. And even if you exceed that limit, your editor will hopefully soft-wrap the line so you don't have to scroll. And the only reason to not go beyond 80 characters was the need of scrolling.

That said, there is indeed a need not to let your lines grow indefinitely. The longer the line, the harder it becomes for a human to parse. But short variable names are not the remedy for the long lines issue.

The remedy is to split your expressions logically by introducing even more properly named variables. Do not try to be clever with whitespace. Just identify any subexpression that can be aptly named, and create a variable for it. That simplifies both the code calculating the variable, and the code using that variable.


Not a part of your question, but I'd like to comment on it anyway: It is a very bad idea to vertically align your = operators.

There are three reasons for that:

  1. Editing a block containing vertically alligned operators is a PITA. Whenever the length of the largest variable changes (rename, addition, deletion), you need to retouch all lines in the block to get your "nice" layout back again.

    Of course, this problem may be reduced a bit by using a competent editor, so it's the minor reason. The real reason is the second:

  2. Those spurious whitespace changes introduced by realigning don't play nicely with modern version control systems like git. They tend to create significant amounts of merge conflicts where no real conflict has happened, and where no conflict would be signaled if the alignment were not used. Each of these spurious conflicts will cost you valuable time for nothing.

  3. The alignment carries zero semantical meaning. It's pointless. There is nothing that you can understand better with the alignment. Every line in your block needs to read by itself to understand what it does, the connection to the lines above and below is of purely syntactical nature.

Since the alignment does not carry any semantical meaning, but produces significant costs, you should unlearn the habit before it costs you any more time.


If you like the 80 character limit so much, try some fortran programming. True, the newer standards have raised the fortran line limit to 132 characters, but it remains in effect as ever crippling the compilation of any program that exceeds the limit. If you are any good at programming, you will soon come to hate fortran, including its line length limit. After that, you will be healed for the rest of your life.

I have myself had to do some fortran programming professionally, and I tell you, it has taught me to hate that line length limit most dearly. There is absolutely nothing more frustrating than having to split an otherwise simple and readable line into parts just because the compiler won't compile it correctly anymore. And there are definitely lines of code which are most simple when they are expressed as a single line.

-1

I'm not sure if this works for c or not but is there a way to split formulas across multiple lines? I know something like that exists for python.

See if you can start + (rowSize*nextWord) + nextWord]) { on a new line. (Like press enter in your IDE and see if it indents it so C know's that the previous expression is being completed on the current line)

3
  • 1
    Yes, this definitely is possible. C does recognize lines and lines of code until you add something like a semicolon. The problem with that is that our functions cannot exceed 50 lines, and although my example code doesn't have 50 lines it is only a fraction of my total function. I feel heavily constricted to write in a 50 by 80 box, algorithms with meaningful variables that can perform the functions I need them too. I could keep storing these long chunks of code into new functions but I feel like I'll end up with so many function calls, people will get lost reading the code.
    – RaulT
    Mar 18, 2017 at 3:22
  • 5
    "I feel like I'll end up with so many function calls, people will get lost reading the code." Quite the contrary! Extracting code into separate methods allows you to give them descriptive names increasing readability (especially of the method you are extracting from). If you end up with too many methods your class might be doing to much (single responsibility principle). Extracting methods into a separate class again allows you to give that thing a descriptive name. Mar 18, 2017 at 4:20
  • Any function that is approaching 50 lines is probably too long and too complex, (with the possible exception of data initialisation with a complexity of 1), but usually when limits like that are discussed they are lines of code not text lines so splitting a single line of code, i.e. to the semicolon often will not count as an extra line, check with the Prof! Mar 18, 2017 at 6:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.