Is this a coding horror?
-
I don't know - it isn't in my code anymore... I wrote this wonder this morning, and realized I could prune it down to just the one line:
private void SetRole(SMUser user, UserRole userRole, string roleName, List<string> inRoles, List<string> outRoles)
{
(((user.Roles & userRole) != 0) ? inRoles : outRoles).Add(roleName);
}I mean, yes it works. But... It's not there anymore: I changed the whole way I handle roles for other reasons. But still, It's a bit impenetrable...
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
First, the advantage of terse code is that you can more of the code on the screen at a time. If that advantage outweighs others, such as possibly the next guy getting confused, maybe it's worth it. Maybe you're writing code on a 40 column x 20 row terminal like an Atari 800. This likely may not be the case. The next issue is optimization. Does this code optimize better than the equivalent:
if ((user.Roles & userRole) != 0) inRoles.Add(roleName); else outRoles.Add(roleName);
I bet the rewritten version isn't any less optimized. Third, which one is easier to single-step through? Some debuggers only let you step through lines, not statements. And finally, if you're doing this so that people will go, "wow, you can do that? that works? wow", then you're likely to be breaking the Principle of least astonishment.
-
First, the advantage of terse code is that you can more of the code on the screen at a time. If that advantage outweighs others, such as possibly the next guy getting confused, maybe it's worth it. Maybe you're writing code on a 40 column x 20 row terminal like an Atari 800. This likely may not be the case. The next issue is optimization. Does this code optimize better than the equivalent:
if ((user.Roles & userRole) != 0) inRoles.Add(roleName); else outRoles.Add(roleName);
I bet the rewritten version isn't any less optimized. Third, which one is easier to single-step through? Some debuggers only let you step through lines, not statements. And finally, if you're doing this so that people will go, "wow, you can do that? that works? wow", then you're likely to be breaking the Principle of least astonishment.
Firstly, no, Visual Studio on a 22" monitor, so I don't have that excuse. Secondly, if the two do not optimize to the same code, then someone as Microsoft should be up against the wall. Thirdly, I think the VS compiler will allow single step only on the second version. Finally, no, I did it because it seemed reasonable at the time, after I had removed a pile of code (which is why it has a dumb name - it didn't for long and got deleted completely soon afterwards) When I realized what I had left myself, the initial response was "Yeuch"! So I stuck it here. It realized some interesting responses - from my point of view it is pretty nasty, and not something I would want to leave in production code. Interesting that some people seem to think it is fine, if it is commented!
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
-
I agree with you in principle: the code should be readable, so comments, or at least those which simply describe what is being done, should be unnecessary. However, we need comments for two reasons:
-
To cover why we are doing it. For simple cases this might be obvious from a function name, but even for trivial calculations, describing why you're doing it is useful. For example, which of these is clearer?
surfaceVolume = volume * 298 * p / (T * 101325);
or
// Volume by ideal gas law at STP (25C, 1 atm)
surfaceVolume = volume * 298 * p / (T * 101325);(Yeah I know I should have consts for those values and in similar real code I do.)
-
Sometimes the language feature won't let us express our thought without a bunch of syntax. In a procedural scalar language like what most of us use, this is particularly true for array operations. E.g.
// a + b
double[] r = new double[a.Length];
for(int i = 0; i < r.Length; i++) r[i] = a + b;Experienced people might be able to read a loop and immediately process it to what it represents, but many won't be able to. Linq helps with certain categories of syntax (complex foreach loops to filter an enumeration), but array-based maths still needs comments for what you really mean.
// Volume by ideal gas law at STP (25C, 1 atm)
surfaceVolume = volume * 298 * p / (T * 101325);Or even better...put that formula in a well named function and call it, so your call looks something like
surfaceVolume = CalculateVolumeByIdealGasLaw(volume, pressure, temperature);
Now you don't need the comment. And your code is easier to test.
-
-
If people maintaining this code are used to the "?" operator, then this code is quite readable, and nearly simple. But if they're not, then they'll find it a coding horror ;P
-
Firstly, no, Visual Studio on a 22" monitor, so I don't have that excuse. Secondly, if the two do not optimize to the same code, then someone as Microsoft should be up against the wall. Thirdly, I think the VS compiler will allow single step only on the second version. Finally, no, I did it because it seemed reasonable at the time, after I had removed a pile of code (which is why it has a dumb name - it didn't for long and got deleted completely soon afterwards) When I realized what I had left myself, the initial response was "Yeuch"! So I stuck it here. It realized some interesting responses - from my point of view it is pretty nasty, and not something I would want to leave in production code. Interesting that some people seem to think it is fine, if it is commented!
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
So why do you think some people think it's okay? I've heard programmers tell me that swapping the value of x and y without using a temporary intermediate is somehow better, coding ending up looking something like this: *x^=*y^=*x^=*y eeek
-
I don't know - it isn't in my code anymore... I wrote this wonder this morning, and realized I could prune it down to just the one line:
private void SetRole(SMUser user, UserRole userRole, string roleName, List<string> inRoles, List<string> outRoles)
{
(((user.Roles & userRole) != 0) ? inRoles : outRoles).Add(roleName);
}I mean, yes it works. But... It's not there anymore: I changed the whole way I handle roles for other reasons. But still, It's a bit impenetrable...
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
Your code is not a horror in any ways! Instead, its a clever code and must be upvoted as I have given 5up for that!
-
So why do you think some people think it's okay? I've heard programmers tell me that swapping the value of x and y without using a temporary intermediate is somehow better, coding ending up looking something like this: *x^=*y^=*x^=*y eeek
Kenneth Kasajian wrote:
So why do you think some people think it's okay?
http://www.codeproject.com/Messages/4008174/Re-Is-this-a-coding-horror.aspx[^]
Kenneth Kasajian wrote:
*x^=*y^=*x^=*y
In embedded assembler, when you are after every last clock cycle in a limited uProcessor, then swap by XOR can be a real time saver - since it only uses the ALU, there is less external memory access, which can save a lot of time. I don't like to work that close to the wind though - and if I do, it get commented to hell and back. In C++ or C#? Don't go there! :laugh:
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
-
Definitely agree with you. But at work, I'm always surprised to see the number of junior developers who don't understand (or don't want to try to understand) this simple construct.. (the "?" operator, I mean)
-
So why do you think some people think it's okay? I've heard programmers tell me that swapping the value of x and y without using a temporary intermediate is somehow better, coding ending up looking something like this: *x^=*y^=*x^=*y eeek
-
(((user.Roles & userRole) != 0) ? inRoles : outRoles)
...this is the part that needs some 'splaining. Maybe something as simple as:
var rolesList = (user.Roles & userRole) != 0) ? inRoles : outRoles;
rolesList.Add(roleName);This is what I was thinking as well, which is why I looked at all the responses. The only I would change, in .NET 4, is to use the HasFlags method of enum:
var rolesList = user.Roles.HasFlag(userRole) ? inRoles : outRoles;
rolesList.Add(roleName);This also means no brackets are necessary.
-
// Volume by ideal gas law at STP (25C, 1 atm)
surfaceVolume = volume * 298 * p / (T * 101325);Or even better...put that formula in a well named function and call it, so your call looks something like
surfaceVolume = CalculateVolumeByIdealGasLaw(volume, pressure, temperature);
Now you don't need the comment. And your code is easier to test.
Up to a point. Code which contains nothing but several levels of 'well named functions' wrapped around a simple arithmetic calculation are a pain to debug (trying to actually find the places where calculations are done and therefore being able to see whether they're done right). It's kind of like trying to read a book by just looking at the contents page. It's hard to read such long names, too (unless you put in underscores to make it look like a sentence but then the arguments seem to be bound to the last word). This would go in a function for me if I were using it in more than one place (which in this example I almost certainly would be). Your proposed name misses the most important point, by the way. It should be called "STPVolume" or "GetVolumeAtSTP" or something like that.
-
There seems to be a common opinion that the ternary is pure evil and should never be used, even as far more recent and difficult to understand concepts (anonymous delegates, lambdas, LINQ etc) are accepted. I don't understand why, it's a simple and elegant construction and easy to parse (for a person as well as a computer). I guess it's because it can be horribly abused (see some other posts in this forum), but so can pretty much every language feature.
-
This is what I was thinking as well, which is why I looked at all the responses. The only I would change, in .NET 4, is to use the HasFlags method of enum:
var rolesList = user.Roles.HasFlag(userRole) ? inRoles : outRoles;
rolesList.Add(roleName);This also means no brackets are necessary.
-
Up to a point. Code which contains nothing but several levels of 'well named functions' wrapped around a simple arithmetic calculation are a pain to debug (trying to actually find the places where calculations are done and therefore being able to see whether they're done right). It's kind of like trying to read a book by just looking at the contents page. It's hard to read such long names, too (unless you put in underscores to make it look like a sentence but then the arguments seem to be bound to the last word). This would go in a function for me if I were using it in more than one place (which in this example I almost certainly would be). Your proposed name misses the most important point, by the way. It should be called "STPVolume" or "GetVolumeAtSTP" or something like that.
You think debugging is more difficult with more functions? I disagree. My IDE steps into functions, or over them...which makes debugging simpler, not harder. I can step over functions I've already eliminated as the problem, and into those which could be an issue. Rather than stepping on every line of code. And I should know if the bug is in a function or not by writing tests for it. My "STPVolume" or "GetVolumeAtSTP" function should have test methods ensuring it's accurate. As for the name, physics isn't my domain, so I didn't know the proper name, I made my best guess. The essence of my point still stands.
-
Definitely agree with you. But at work, I'm always surprised to see the number of junior developers who don't understand (or don't want to try to understand) this simple construct.. (the "?" operator, I mean)
-
You think debugging is more difficult with more functions? I disagree. My IDE steps into functions, or over them...which makes debugging simpler, not harder. I can step over functions I've already eliminated as the problem, and into those which could be an issue. Rather than stepping on every line of code. And I should know if the bug is in a function or not by writing tests for it. My "STPVolume" or "GetVolumeAtSTP" function should have test methods ensuring it's accurate. As for the name, physics isn't my domain, so I didn't know the proper name, I made my best guess. The essence of my point still stands.
Yes. IDE stepping is the last resort of debugging, one should be able to find the suspect piece of code quickly without diving through a big tree of methods. (I'm suffering from this at the moment in a real project, in fact.) Obviously, you don't just want the whole application in one big main(), but taking something which is only one or two lines out of line does not (imo) help readability. (Taking it out to avoid duplicating the calculation is a separate matter and a good reason to do so, because the pain of having duplicate code massively outweighs the problem of having too many functions.) Your tests will tell you if the function is 'accurate', but it won't tell you some things which may be important when you want to use it (that you didn't think of at the time). For example, just what is standard temperature and pressure? ... there are different definitions and to find which one is being used you need to find the calculation. This is more common with more complex methods, or order of event firing or other slightly tricky things like that.
-
Yes. IDE stepping is the last resort of debugging, one should be able to find the suspect piece of code quickly without diving through a big tree of methods. (I'm suffering from this at the moment in a real project, in fact.) Obviously, you don't just want the whole application in one big main(), but taking something which is only one or two lines out of line does not (imo) help readability. (Taking it out to avoid duplicating the calculation is a separate matter and a good reason to do so, because the pain of having duplicate code massively outweighs the problem of having too many functions.) Your tests will tell you if the function is 'accurate', but it won't tell you some things which may be important when you want to use it (that you didn't think of at the time). For example, just what is standard temperature and pressure? ... there are different definitions and to find which one is being used you need to find the calculation. This is more common with more complex methods, or order of event firing or other slightly tricky things like that.
-
I've never heard of "the problem of having too many functions"... Have you read books like Clean Code or Code Complete, etc?
-
I don't know - it isn't in my code anymore... I wrote this wonder this morning, and realized I could prune it down to just the one line:
private void SetRole(SMUser user, UserRole userRole, string roleName, List<string> inRoles, List<string> outRoles)
{
(((user.Roles & userRole) != 0) ? inRoles : outRoles).Add(roleName);
}I mean, yes it works. But... It's not there anymore: I changed the whole way I handle roles for other reasons. But still, It's a bit impenetrable...
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
It looks perfectly simple to me. I'd be very disappointed if a programmer couldn't understand it!
-
I don't know - it isn't in my code anymore... I wrote this wonder this morning, and realized I could prune it down to just the one line:
private void SetRole(SMUser user, UserRole userRole, string roleName, List<string> inRoles, List<string> outRoles)
{
(((user.Roles & userRole) != 0) ? inRoles : outRoles).Add(roleName);
}I mean, yes it works. But... It's not there anymore: I changed the whole way I handle roles for other reasons. But still, It's a bit impenetrable...
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together. Manfred R. Bihy: "Looks as if OP is learning resistant."
hmm... The only thing I'd argue with is doing all that then adding the adding the "Add" method to the end. Being used to the ternary operator, I could read it fairly quickly, but to make it more human readable, perhaps an assignment a variable should have been assigned to the chosen list, then the second line should have implemented the Add method. In ANSI C in college, they encouraged this type of stacking behavior. In fact, they demanded it, but it was more of a performance issue than simply being "clever."