Would be better than
return x >= ASCII_A;
surely. ASCII_A could be set incorrectly, or have a dumb type, and is more verbose anyway. By using the character directly, the code speaks its purpose.
Would be better than
return x >= ASCII_A;
surely. ASCII_A could be set incorrectly, or have a dumb type, and is more verbose anyway. By using the character directly, the code speaks its purpose.
I disagree. ASCII_A speaks it's purpose (we purposefully want an ASCII A stored here). And one can check the constant's definition, and immediately tell if it's correct. E.g.
const ASCII_A = 'A' // correct
const ASCII_A = 'E' // wrong
So: return x >= ASCII_A
tell us the intention of the code's author.Whereas:
return x >= ‘A’;
only tells us what the code does, which might nor might not be correct (and we have no way of knowing, without some other documentation).So, by those two lines:
const ASCII_A = 'E';
(...)
return x >= ASCII_A;
We know what the code is meant to do, AND that it does it wrongly (and thus, we know what to fix).These line, on the other hand:
return x >= ‘A’;
tells us nothing. Should it be 'A'? Should it be something else? We don't know.(If you say it's because it's written twice, well, that's only a valid clue if ASCII_E doesn't happen to be defined too.)
Ultimately you don't, but ASCII_A requires double the intentional actions to name it and have it also be 'A', whereas 'A' vs 'E' or whatever else is a much easier typo.
It's the whole idea behind NOT having magic values in your code. That is, that:
if (temp > 212)
tells us much less than: if (temp > WATER_BOILING_TEMP)
and that we can more easily spot an error with: WATER_BOILING_TEMP = 275
than with: if (temp > 275)Unless, as I wrote after, you have both ASCII_A and ASCII_E declared, which wouldn't be surprising.
I don't find the "spot the error" argument to be very convincing; I still name stuff, but just for the semantic value.
Or 275°C at around 60 bar.
Gets the whole message across in one line, as does using 65 with the comment.
return x >= 'A';
already and only means ascii A. Is there a C compiler anywhere where or likely in future where 'A' in C is NOT ascii A? The comment is redundant if correct, and could be wrong after an edit, so it has no value.
See, here's where you are wrong.
ASCII_A = "A"
alphas = ["Α", "А", "Ꭺ", "ᗅ", "ꓮ", "A", "𐊠", "A", "𝐀", "𝖠", "𝙰", "𝚨", "𝝖"]
for c in alphas:
print c == ASCII_A
Output? False
False
False
False
False
False
False
True
False
False
False
False
False
Several of the numerous possible utf-8 alphas. Those are not A in different fonts -- they are different unicode characters that look like A. And depending on your font they could look absolutely the same as plain ascii a (of which only one towards the middle of the list is). And depending on your locale and keyboard language settings, one of them could be as easy to click as the regular english A in ASCII.int main() { printf( "%d %d\n", 'A', "A" ); return 0; }
produces: 65 197730221
since the value of string "A" is its base address.
Of course, all of this is likely overkill for your specific example. If I'm writing a to_hex routine, I'm not going to extract those constants as the context & commonplaceness of the algorithm makes it redundant. For the same reason that one might write i++ in a for loop instead of i += ONE. However, extracting inline constants to named variables is frequently something I look out for in code review, especially the more frequently the same constant appears in multiple places, the more difficulty a reader might have trying to understand why that value is the way it is (or if there's any discussion at all), or if it's a value that will potentially change over time. The negative drawbacks of extracting constants is typically minimal & with modern-day refactoring it's a very small ask of the contributor.
> ASCII_A
It comes down to naming and purpose.
The example, ASCII_A, is terrible because it doesn't describe the purpose with its name.
What will end up happening in any large codebase is ASCII_A will get reused in dozens of different places for dozens of different reasons.
If it was named minValidLetterForAlgorithmX it would convey intent and its more likely to be used correctly.
I'm not so sure it's a straw man, I often see defining constants like this cargo culted even if there are only one or two uses. In that case 'A' is great because it's value is right there, I don't have to look at the assignment and then go look up what the actual value is, so it's more readable.
When it's used in several disparate places then ASCII_A is better and your arguments about correctness should take precedence, we sacrifice some readability but it's worth it.
But you’re channeling some crazy madness suggesting that someone would use ‘A’ to mean 65. Shudder. I guess we’ve all seen some horrors over the years.
Or just an encoding scheme.
> ASCII_A (usually spelled just 'A')
Of course, they are not the same thing. In the last 6 months I've worked on a very old system that uses not-quite-ASCII. 'A' was 65 but '#' wasn't 35.
If A signifies something else, use that name; otherwise just use plain 'A': it already gives us as much information as needed, and has one less place where the programmer can screw up.
As an aside, if someone changes the constant value of ‘A’ now, the world will be broken for a while. (But my code would recompile correctly unchanged with the new standard header.)