Most readable way to write simple conditional check - language-agnostic

What would be the most readable/best way to write a multiple conditional check such as shown below?
Two possibilities that I could think of (this is Java but the language really doesn't matter here):
Option 1:
boolean c1 = passwordField.getPassword().length > 0;
boolean c2 = !stationIDTextField.getText().trim().isEmpty();
boolean c3 = !userNameTextField.getText().trim().isEmpty();
if (c1 && c2 && c3) {
okButton.setEnabled(true);
}
Option 2:
if (passwordField.getPassword().length > 0 &&
!stationIDTextField.getText().trim().isEmpty() &&
!userNameTextField.getText().trim().isEmpty() {
okButton.setEnabled(true);
}
What I don't like about option 2 is that the line wraps and then indentation becomes a pain. What I don't like about option 1 is that it creates variables for nothing and requires looking at two places.
So what do you think? Any other options?

if (HasPassword() && HasStation() && HasUserName())
okButton.setEnabled(true);
bool HasPassword() {
return passwordField.getPassword().length > 0;
}
etc.

Note that option 1 does not allow for short circuiting behavior. That is, you calculate the value of all of the conditionals before evaluating the result of the first.

I would modify option 1 so that you're using variable names that actually have a meaning. That is, change the name of "c2" to be something like "stationIDIsEmpty" (and move the NOT into the conditional). That way the conditional is readable without having to glance back and forth for every variable.
So my code would probably look like:
boolean enteredPassword = passwordField.getPassword().length > 0;
boolean stationIDIsEmpty = stationIDTextField.getText().trim().isEmpty();
boolean userNameIsEmpty = userNameTextField.getText().trim().isEmpty();
if (enteredPassword && !stationIDIsEmpty && !userNameIsEmpty) {
okButton.setEnabled(true);
}

I voted for Chris Brandsma's answer.
But just wanted to mention the main issue I have with Option 1 is you are losing the benefit of &&. With option one, although I think it's more readable, you are processing comparisons when they may not be required.

Personally, I like the second way, because I find that using that way can make the predication of the conditionals clear. That is, with that method done properly, you can make the conditional comprehensible by "verablizing" it (whether or not you actually speak it is irrelevant).
That is, with your second option, it becomes clear that your conditional translates roughly as this: "If the password length is greater than zero, AND the stationIDTextField (trimmed) is NOT empty, AND the usernameTextField (trimmed) is NOT empty, then..."

I prefer the following:
if (passwordField.getPassword().length > 0
&& ! stationIDTextField.getText().trim().isEmpty()
&& ! userNameTextField.getText().trim().isEmpty())
{
okButton.setEnabled(true);
}
With this coding style I accomplish two things:
I can easily see that each extra line of the if is part of the condition because of the && (or ||) at the beggining.
I can easily see where the if statement ends because of the { at the next line.

Option1 is prime for applying the refactoring 'Replace temp with Query'. The reason being that someone can stuff in code between the variable is initialized and the check and change the behavior of the code. Or the check might be made with stale values.. an update has been made to the textfields between initialization and checking.
So my attempt at this would be
if (GetPasswordLength() > 0
&& FieldHelper.IsNotEmpty(stationIDTextField)
&& FieldHelper.IsNotEmpty(userNameTextField)
{
okButton.setEnabled(true);
}
FieldHelper is a class with public static methods (also called a Utility class / Static class in C#)

Related

Can I include conditional logic in VS Code snippets?

I would like to write a snippet in VS Code that writes a "switch" expression (in Javascript), but one where I can define the number of cases.
Currently there is a snippet that produces the outline of a switch expression with 1 case, and allows you to tab into the condition, case name, and the code contained within.
I want to be able to type "switch5" ("5" being any number) and a switch with 5 cases to be created, where I can tab through the relevant code within.
I know the snippets are written in a JSON file, can I include such conditional logic in this, or is it not possible?
Thanks!
The short answer is that you cannot do that kind of thing in a standard vscode snippet because it cannot dynamically evaluate any input outside of its designated variables with some limited workarounds like I'll mention next.
You might - I and others have written answers on SO about his - type your various case values first and then trigger a snippet tat would transform them into a switch statement. It is sort of doing it backwords but it might be possible.
There are extensions, however, that do allow you to evaluate javascript right in a snippet or setting and output the result. macro-commander is one such extension. I'll show another simpler extension doing what you want: HyperSnips.
In your javascript.hsnips:
snippet `switch(\d)` "add number of cases to a switch statement" A
``
let numCases = Number(m[1]) // 'm' is an array of regex capture groups
let caseString = ''
if (numCases) { // if not 'switch0'
let tabStopNum = 1
caseString = `switch (\${${tabStopNum++}:key}) {\n`
for (let index = 0; index < m[1]; index++) {
caseString += `\tcase \${${tabStopNum++}:value}:\n\t\t\$${tabStopNum++}\n`
caseString += '\t\tbreak;\n\n'
}
caseString += '\tdefault:\n'
caseString += '\t\tbreak;\n}\n'
}
rv = `${caseString}` // return value
``
endsnippet
The trickiest part was getting the unknown number of tabstops to work correctly. This is how I did it:
\${${tabStopNum++}:key}
which will resolve to ${n:defaultValue} where n gets incremented every time a tabstop is inserted. And :defaultValue is an optional default value to that tabstop. If you don't need a defaultValue just use \$${tabStopNum++} there.
See https://stackoverflow.com/a/62562886/836330 for more info on how to set up HyperSnips.

Opposite of 'else' during a switch or conditional

I'm wondering if any programming language has an operator like so (ALWAYS is a placeholder--I'm asking what language has something like ALWAYS)
if a
doAStuff()
else if b
doBStuff()
ALWAYS
//runs if a or b is true
win()
else
doElse()
Basically, the opposite of else. It runs if something else in the statement ran.
logically, it would be like this
always = true
if a
doA()
else if b
doB()
else
always = false
doElse()
if always
win()
Does any language have that logic built into a keyword, such as ALWAYS from the first example?
Not really 'language-agnostic'. More like 'find-my-language'. With Forth and Lisp you can add such a construct naturally to the language, and it will work just like existing constructs. I'm not aware of any language that has it by default. If you have a less extensible language than Forth or Lisp, then the natural ways to do this are to use a local function (if you have first-class functions) or to set a flag as you show, or else to factor the code such that both conditions can be treated as pairs without a lot of repetition.
So, in JavaScript:
;(function() {
function both() { win(); more stuff, potentially }
if (a) { doA(); if (b) both() }
else if (b) { doB(); if (a) both() }
else neither()
})()
At upon reading that, it should be clear that the 'both' case is never going to happen in that second block. So this simplifies to:
;(function() {
function both() { win(); more stuff, potentially }
if (a) { doA(); if (b) both() }
else if (b) doB()
else neither()
})()
Which doesn't seem worth the effort. So it seems even less worth a language feature. Why not go further and write this?
if (a) { doA(); if (b) { win(); more stuff, potentially } }
else if (b) doB()
else neither()
If b is an expensive test, just save the result of it. If b must not be tested before a, save both results. Obviously, both tests must always be run anyway.
;(function() {
var a = testA(),
b = testB()
... as above ...
})()
As for the last option, "factor the code such that both conditions can be treated as pairs", what you're looking for is:
if (a && !b) doA()
if (!a && b) doB()
if (a && b) { doA(); doB(); win() } // or no doB() if you really want that
if (!a && !b) neither()
With else if if you like. I'd prefer this option actually in a pattern-matching language. Mercury will even throw an compile-time error if you forget one of the four possible outcomes.
Not sure if this is what you're looking for, but a simple do-while loop will ALWAYS run at least once in Java.

nested ternary operator vs nested if else, which is better in readability purpose

I found code in code review which was written by my team member. It contains nested ternary operator. I told him to use if else if there is more than one nesting for readability purpose. We had argue on that.
following is code
ColorEnum color = opacity == Opacity.FIVE? ColorEnum.BLACK :
opacity == Opacity.TEN? ColorEnum.WHITE :
opacity == Opacity.FIFTY? ColorEnum.RED :
opacity == Opacity.TWENTY? ColorEnum.BLUE :
opacity == Opacity.FIFTEEN? ColorEnum.PURPLE : null;
And this code is changing as new configurations come.
So What is better here? ternary operator or if else?
Just reformatting your code makes it quite clear:
ColorEnum color =
opacity == Opacity.FIVE ? ColorEnum.BLACK
: opacity == Opacity.TEN ? ColorEnum.WHITE
: opacity == Opacity.FIFTY ? ColorEnum.RED
: opacity == Opacity.TWENTY ? ColorEnum.BLUE
: opacity == Opacity.FIFTEEN ? ColorEnum.PURPLE
: null;
LISP adopts the cond construct which has both the same structure and the same semantics, and is considered good practice. As an aside, Clojure also supports a form which tests the value of a single expression with a single predicate applied to different values (one for each clause) and calls it condp—that would be a perfect match for your use case.
The idiom with the ternary operator has the advantage over an if-else cascade for being an expression so you need only a single statement to assign it to the variable. if-else will force you to pull the assignment into each then clause, introducing more boilerplate and more opportunity to fail on correctness.
A switch statement could also be considered as an alternative, but it would have the following deficiencies:
like if-else, it is not an expression;
you are restricted to just different constant values of a single expression (the type of the expression being quite constrained, too).
it's prone to bugs due to the boilerplate break missing somewhere.
I would suggest to use switch statement. It would be more readable than ternary and if-else.
switch(opticity)
{
case Opticity.FIVE: color = ColorEnum.BLACK;
break;
case Opticity.TEN: color = ColorEnum.WHITE;
break;
case Opticity.FIFTY: color = ColorEnum.RED;
break;
....
default: printf("Error message\n");
}
For this purpose, probably a switch-case statement would be best in terms of readability.
Go with switch.
I've a thumb rule which I consistently follow (Although not hardset)
1) Only one conditional evaluation, go with ternary operator
2) Two conditional check, go with if(){} else if(){ } else{} construct
3) Three or more go with switch ladder
“Programs must be written for people to read, and only incidentally for machines to execute.”
― Harold Abelson, Structure and Interpretation of Computer Programs
As others have mentioned, a switch would be a good alternative. To reduce boilerplate code (breaks, assignments), I would further recommend putting the switch into a dedicated method:
(All examples are in C#)
public ColorEnum OpacityToColor(Opacity opacity)
{
switch (opacity)
{
case Opacity.FIVE:
return ColorEnum.BLACK;
case Opacity.TEN:
return ColorEnum.WHITE;
case Opacity.FIFTY:
return ColorEnum.RED;
case Opacity.TWENTY:
return ColorEnum.BLUE;
case Opacity.FIFTEEN:
return ColorEnum.PURPLE;
default:
throw new System.ArgumentOutOfRangeException("opacity");
}
}
// Elsewhere
ColorEnum color = OpacityToColor(opacity);
If your language has a neat dictionary/map initialization syntax (e.g. Python, C#), you could also use that for a very concise and clear notation:
public static readonly Dictionary<Opacity, ColorEnum> ColorByOpacity =
new Dictionary<Opacity, ColorEnum>
{
{Opacity.FIVE, ColorEnum.BLACK},
{Opacity.TEN, ColorEnum.WHITE},
{Opacity.FIFTY, ColorEnum.RED},
{Opacity.TWENTY, ColorEnum.BLUE},
{Opacity.FIFTEEN, ColorEnum.PURPLE}
};
// Elsewhere
ColorEnum color = ColorByOpacity[opacity];

How to suppress the warning "Assignment within conditional. Did you mean == instead of =?"

With the new ASC 2.0 compiler I get warnings when I code like below:
// (_achievementsFromServer is an Array)
while(item=_achievementsFromServer.pop())
{
// do something with item here
}
The warning reads: "Assignment within conditional. Did you mean == instead of =?"
While in general I appreciate all warnings from the compiler, I'd like to suppress this one in this case because I did not mean == here. I want to pop all items in the array and do something with it until the array is empty.
while( (item=_achievementsFromServer.pop())==true )
seems to work but looks a bit confusing. Any other ideas?
This may seem better.
while(_achievementsFromServer.length > 0) {
var item:Object = _achievementsFromServer.pop();
}
Just like removeChild
var d:DisplayObjectContainer;
while(d.numChildren > 0) {
d.removeChildAt(0);
}
While I was hoping for some other way, I think #AmyBlankenship improved my own suggestion:
while((item=_achievementsFromServer.pop())!=null)
{
//....
}
It's clear and understandable what's going on, and doesn't rely on checking the length of the Array on every iteration.
Googling some more I found a compiler option -compiler.warn-assignment-within-conditional that could be set to false but then you won't be warned anywhere in your project anymore. And I'm not so confident that I never accidently type = instead of ==, so that's not a good solution I think.

LINQ-to-SQL oddity with multiple where clause arguments on the same field

My problem requires me to dynamically add where clauses to a IQueryable based on user input. The problem i'm having is that Linq-to-SQL doesn't seem to like having multiple where clauses on the same field, it actually duplicates the search arg value for the last item on all parameters. I verified this behavior through a SQL trace. Here is what I'm seeing.
WHERE ([t22].[OpenText] LIKE #p11) AND ([t22].[OpenText] LIKE #p12)
-- #p11: Input NVarChar (Size = 10; Prec = 0; Scale = 0) [%classify%] // Should be 2da57652-dcdf-4cc8-99db-436c15e5ef50
-- #p12: Input NVarChar (Size = 10; Prec = 0; Scale = 0) [%classify%]
My code uses a loop to dynamically add the where clauses as you can see below. My question is how do I work around this? This pretty much seems like a bug with the tool, no?
// add dyanmic where clauses based on user input.
MatchCollection searchTokens = Helper.ExtractTokensWithinBracePairs(filterText);
if (searchTokens.Count > 0)
{
foreach(Match searchToken in searchTokens)
query = query.Where((material => material.OpenText.Contains(searchToken.Value)));
}
else
{
query = query.Where((material => material.OpenText.Contains(filterText)));
}
Closing over the loop variable considered harmful! Change
foreach(Match searchToken in searchTokens) {
query = query.Where(
material => material.OpenText.Contains(searchToken.Value)
);
}
to
foreach(Match searchToken in searchTokens) {
Match token = searchToken;
query = query.Where(
material => material.OpenText.Contains(token.Value)
);
}
You are closing over the loop variable, which is considered harmful. To fix do this:
foreach(Match searchToken in searchTokens)
{
Match searchToken2 = searchToken;
// ^^^^^^^^^^^^ copy the value of the reference to a local variable.
query = query.Where(material => material.OpenText.Contains(searchToken2.Value));
// use the copy here ^^^^^^^^^^^^
}
The reason why your version doesn't work is that the query refers to the variable searchToken, not the value it had when the query was created. When the variable's value changes, all your queries see the new value.
I don't have enough rep to leave comments yet (or this would be a comment and not an answer) but the answers listed here worked for me.
However, I had to turn off compiler optimizations in order for it to work. If you do not turn off compiler optimizations (at least at the method level) then the compiler sees you setting a loop variable to a local variable and throws the local variable away.