I'm not very excited about either version. The second (single large expression in return
statement) makes it hard to follow the control logic. The fact that the author has felt an urge to comment the code to make it clear what it does and that it doesn't fit on any reasonable line length are indicators that the expression is too complex and should be broken up.
The fist example, on the other hand, seems overly complicated to me. For example, how is
enum {
is_not_in_set = 0,
is_in_set = 1
};
in_set = FD_ISSET(socket_desc, &fdset);
if (in_set) {
// …
}
any more readable than simply using the result of the “function call” immediately as the conditional?
if (FD_ISSET(socket_desc, &fdset)) {
// …
}
Every name you introduce into the current scope adds additional cognitive load on the reader. This might be warranted if it adds additional information but I don't see how the use of the enum
helps here. It is clear that a call to FD_ISSET
tells me whether the file descriptor is in the set or not. I cannot see how the enum
is useful here at all. And what about the other enum
?
Likewise here.
connection_to_target = (result == ECONNSUCCESS) || (result == ECONNREFUSED);
if (connection_to_target == 1) {
// …
}
There is a lot of redundancy here. Where is connection_to_target
declared? What is its type? Why is it compared to 1? Why is it not const
? Why is it there at all?
Again, using the expression directly
if ((result == ECONNSUCCESS) || (result == ECONNREFUSED)) {
// …
}
would greatly improve readability and reduce complexity.
In the third case
sock_opt_read_result = getsockopt(socket_desc, SOL_SOCKET, SO_ERROR, &result, &result_len);
if (sock_opt_read_result >= 0) {
// …
}
an argument could be made for the use of a named variable because the function call is very long. But again, it would reduce cognitive load if the variable were declared const
and initialized immediately. Also, the name sock_opt_read_result
is really not helpful. The name of a variable should indicated what it means, not where it came from.
Finally, I find code much more readable when it focuses on the “success path” and breaks out of it in case of failure. In programming languages that have exceptions, this style emerges naturally. It helps you reduce the depth of your nested conditionals and makes it easier to see at which point we have success or failure.
So, I would re-write the code somehow like this.
if (!FD_ISSET(socket_desc, &fdset)) {
return Status_Failed;
}
if (getsockopt(socket_desc, SOL_SOCKET, SO_ERROR, &result, &result_len) < 0) {
return Status_Failed;
}
if ((result != ECONNSUCCESS) && (result != ECONNREFUSED)) {
return Status_Failed;
}
return Status_OK;
If you feel a need to explain why a certain condition indicates failure, the beginning of the respective “then” block is a good place to put a short comment.
The last conditional in the suggested code above might be controversial. I have written it like this to stay true with the suggested principle of keeping the “success path” straight. Alternatives like
return ((result == ECONNSUCCESS) || (result == ECONNREFUSED)) ? Status_OK : Status_Failed;
or
switch (result) {
case ECONNSUCCESS:
case ECONNREFUSED:
return Status_OK;
default:
return Status_Failed;
}
might be reasonable choices as well.
I'm fairly sure that we can agree that the suggested replacement in this answer is more readable than either of the original alternatives but this answer might still not be as non-opinion-based as you were hoping. I'm afraid that there won't be the one right way to write your code. In the end, I think it is also important to respect the personality of your co-workers during code review. If it is not perfectly clear which way to structure the code is superior, let them have their version and use your preferred way to do it in the code you write. These implementation details are local to each function and don't affect how maintainable the software is at a higher level. If you change your opinion later, you can always safely refactor any function's internals without risking to break anything.
By the way, have a look at Code Review if you want other people to discuss the quality of a piece of your code.