C# 7 switch/case using "when" the way it's not meant to be used [closed] - switch-statement

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I've started using this format of switch statement. It works, but is there a purist view that the following is bad practice? On the plus side it can be a lot more readable than deeply nested if statements. On the downside, I don't think it is meant to be used like this:
int hour = DateTime.Now.Hour;
string timeWord;
switch ("ignore")
{
case string x when hour < 12:
timeWord = "morning";
break;
case string x when hour < 18:
timeWord = "afternoon";
break;
case string x when hour < 24:
timeWord = "evening";
break;
default:
throw new LogicException("Another fine mess you got us into");
}
Console.WriteLine("Good {timeWord}");
In terms of default I prefer defensive programming. I don't like using defaults as a catch-all. Impossible thing happen with amazing regularity. (ref: HHGTTG) The real question though is the (mis/ab)use of case.
EDIT UPDATE + Further update as I screwed up a cut and paste
It was suggested I post an example I has put in a comment. Here is a different one. There is an if-then example followed by a case. In no way are they meant to be the same, just to show what I meant about the clarity of nested ifs.
public class example
{
static Random rnd = new Random();
bool B1, B2, B3, B4, B5;
static bool GetBool() { return rnd.Next(1) == 0 ? false : true; }
bool Accept() { return GetBool(); }
bool Decline() { return GetBool(); }
List<bool?> nullBools = new List<bool?> { false, true, null };
bool? Other() { return nullBools[rnd.Next(2)]; }
void MaybeException() { }
public example()
{
// I don't think it is difficult to miss the holes in this logic
B1 = GetBool(); B2 = GetBool(); B3 = GetBool(); B4 = GetBool();
if (B1 && B2)
{
if (B3)
if (B4 & B5)
if (!Accept() & !Decline())
Other();
else
Decline();
else
if (B4 & !B5)
if (B1)
Decline();
else
Accept();
else
MaybeException();
}
else
{
if (!B1 && B2)
if (B5 & B4)
if (!Accept() && Other() != null)
Decline();
else
{
if (!Other() == null)
if (!Accept())
Decline();
else
Decline();
}
else
{
if (B4 && !B5)
Accept();
else
if (Other() == null)
if (!Accept())
Decline();
Decline();
}
}
// As opposed to
switch ("IGNORE")
{
case string B_0234 when !B1 && !B2 && B3 && B4:
case string B_1200 when B1 && B2 && !B3 && !B4:
case string B_1204 when B1 && B2 && !B3 && B4:
case string B_1234 when B1 && B2 && B3 && B4:
if (Other() == null)
Accept();
break;
case string B_0004 when !B1 && !B2 && !B3 && B4:
case string B_0134 when B1 && !B2 && B3 && B4:
case string B_1000 when B1 && !B2 && !B3 && !B4:
case string B_1030 when B1 && !B2 && B3 && !B4:
case string B_1203 when B1 && B2 && B3 && !B4:
case string B_1004 when B1 && !B2 && !B3 && B4: // Compile error duplicate
if (Other() == null)
if (!Accept())
Decline();
case string B_0230 when !B1 && B2 && B3 && !B4:
case string B_1201 when B1 && B2 && !B3 && B4:
case string B_1230 when B1 && B2 && B3 && !B4:
MaybeException();
break;
//case string B_0101 when !B1 && B2 && !B3 && B4:
//case string B_0000 when !B1 && !B2 && !B3 && !B4:
default:
throw new Exception("Whoops missed the two above impossible??");
}
}
}

I personally, wouldn't use such a construct - it is confusing, in particularly given that the object your are supposedly switching on isn't involved in the switching.
In your particular example, switching on hour would be much more natural.
A sequence of if statements (with returns) would read more naturally to me.
Alternatively, a dictionary, mapping hour with the return string could work well.

Compare it to the if-else structure, which has always been available:
if (hour < 12)
{
timeWord = "morning";
}
else if (hour < 18)
{
timeWord = "afternoon";
}
else if (hour < 24)
{
timeWord = "evening";
}
else
{
throw new LogicException("Another fine mess you got us into");
}
The latter code has pretty much the same structure, allows extending the conditions, and supports the last catch-all else part.
It doesn't have the "ignore" part, which might be confusing at first:
What exactly is being ignored here?
... Oh, it's the string "ignore" itself!
So what's the advantages of the case code structure? I could think of these:
case makes it clear that you want to check various values of some "main" variable, which may be modified by other variables. While if-else has pretty generic conditions.
If you are obliged to put braces {} around if-else code clauses, the switch code may become shorter
These advantages don't look strong to me.

Related

Why is code analysis warning "Using logical && when bitwise & was probably intended" being raised?

Code:
BOOL CCreateReportDlg::CanSwapBrothers()
{
BOOL b1in2 = FALSE, b2in1 = FALSE;
CStringArray aryStrNames;
// Must have valid data
if (!IsSwapBrotherInit())
return FALSE;
// Get cell pointers
auto pCell1 = GetSwapBrotherCell(1);
auto pCell2 = GetSwapBrotherCell(2);
if (pCell1 != nullptr && pCell2 != nullptr)
{
// Look for brother (cell 1) in cell 2 array
auto strName = pCell1->GetText();
pCell2->GetOptions(aryStrNames);
const auto iNumNames = aryStrNames.GetSize();
for (auto iName = 0; iName < iNumNames; iName++)
{
if (aryStrNames[iName] == strName)
{
b1in2 = TRUE;
break;
}
}
if (b1in2)
{
// Look for brother (cell 2) in cell 1 array
auto strName = pCell2->GetText();
pCell1->GetOptions(aryStrNames);
const auto iNumNames = aryStrNames.GetSize();
for (auto iName = 0; iName < iNumNames; iName++)
{
if (aryStrNames[iName] == strName)
{
b2in1 = TRUE;
break;
}
}
}
}
return b1in2 && b2in1;
}
The line of interest is the return statement:
return b1in2 && b2in1;
I am getting a code analysis warning:
lnt-logical-bitwise-mismatch
Using logical && when bitwise & was probably intended.
As far as I am concerned my code is correct. Why is this being raised?
The compiler sees && applies to integer operands and an implicit conversion of the result to an integer type. BOOL has multiple bits; it isn't the same as the built-in type bool.
As noted in the page you linked to, "A logical operator was used with integer values" will cause this warning and that condition is certainly present here.
"MFC" coding styles violate modern recommendations in a lot of ways, using a non-standard boolean type is just one of the smaller issues. CStringArray is also a code smell, modern C++ uses templated containers and has powerful algorithms for manipulating them, you never should be writing search code yourself.

I need help understanding why my if statement is executing

I am having a hard time understanding why my first if statement is executing if my string variable exam1ScoreKnown is assigned the string "YES" or "Y". I only want the if statement to execute if the string is anything other than "YES" or "Y". Also, I have checked to make sure the variable is assigned "YES" or "Y" right before the if statement.
if (exam1ScoreKnown != "YES" || exam1ScoreKnown != "Y") {
totalWeight = totalWeight - exam1Weight - exam2Weight - finalExamWeight;
}
else if (exam2ScoreKnown != "YES" || exam2ScoreKnown != "Y") {
totalWeight = totalWeight - exam2Weight - finalExamWeight;
}
else if (finalExamScoreKnown != "YES" || finalExamScoreKnown != "Y") {
totalWeight = totalWeight - finalExamWeight;
}
This Boolean expression
(exam1ScoreKnown != "YES" || exam1ScoreKnown != "Y")
is equivalent to
!(exam1ScoreKnown == "YES" && exam1ScoreKnown == "Y")
I think in this rewritten form it is easier to see that it is a tautology, ie it is true every which way. I think you need to replace the or by and.

how to use OR operator in nodejs

I am trying to add an if condition; Idea is If I enter the input as print or text with 4 in it, else block should be called.
if ((turnContext.activity.text.indexOf('print') == -1) || (turnContext.activity.text.indexOf('4') == -1))
Now, it goes into the if block as opposed to else.
You have to use: &&. Otherwise when the text is print, the text is not 4 entering the if block.
if ((turnContext.activity.text.indexOf('print') == -1)
&& (turnContext.activity.text.indexOf('4') == -1)) {
// not 4 nor print
} else {
// print or 4
}
The execution goes into else block if text is 'print' or string contains 4 in it.
if (turnContext.activity.text !== 'print' && turnContext.activity.text.indexOf('4') === -1) {
}

LongAdder Striped64 wasUncontended implementation detail

This is a question not about how LongAdder works, it's about an intriguing implementation detail that I can't figure out.
Here is the code from Striped64 (I've cut out some parts and left the relevant parts for the question):
final void longAccumulate(long x, LongBinaryOperator fn,
boolean wasUncontended) {
int h;
if ((h = getProbe()) == 0) {
ThreadLocalRandom.current(); // force initialization
h = getProbe();
wasUncontended = true;
}
boolean collide = false; // True if last slot nonempty
for (;;) {
Cell[] as; Cell a; int n; long v;
if ((as = cells) != null && (n = as.length) > 0) {
if ((a = as[(n - 1) & h]) == null) {
//logic to insert the Cell in the array
}
// CAS already known to fail
else if (!wasUncontended) {
wasUncontended = true; // Continue after rehash
}
else if (a.cas(v = a.value, ((fn == null) ? v + x : fn.applyAsLong(v, x)))){
break;
}
A lot of things from code are clear to me, except for the :
// CAS already known to fail
else if (!wasUncontended) {
wasUncontended = true; // Continue after rehash
}
Where does this certainty that the following CAS will fail?
This is really confusing for me at least, because this check only makes sense for a single case : when some Thread enters the longAccumulate method for the n-th time (n > 1) and the busy spin is at it's first cycle.
It's like this code is saying : if you (some Thread) have been here before and you have some contention on a particular Cell slot, don't try to CAS your value to the already existing one, but instead rehash the probe.
I honestly hope I will make some sense for someone.
It's not that it will fail, it's more that it has failed. The call to this method is done by the LongAdder add method.
public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
}
}
The first set of conditionals is related to existence of the long Cells. If the necessary cell doesn't exist, then it will try to accumulate uncontended (as there was no attempt to add) by atomically adding the necessary cell and then adding.
If the cell does exist, try to add (v + x). If the add failed then there was some form of contention, in that case try to do the accumulating optimistically/atomically (spin until successful)
So why does it have
wasUncontended = true; // Continue after rehash
My best guess is that with heavy contention, it will try to give the running thread time to catch up and will force a retry of the existing cells.

I would like to write a nested IF statement in Excel using Dates in multiple cells

I would like to have A2 = The Output Date:
B2 = A2
If B2 ="X" output Date C2
If B2 ="X" and C2="X" output Date D2
If B2 ="X" and C2="X" and D2="X" output Date E2
I tried to write the statement as
If(B2="X",C2,IF(C2="X",D2,IFD2="X"E2)))
Excel boolean chaining is sometimes unintuitive, especially so depending on your background. Try this:
=IF(B2 = "X", IF(C2 = "X", IF(D2 = "X", E2, D2), C2), "ERROR")
The idea is to check the most common condition first, then perform additional checks as they pass. This is roughly equatable to this code:
public string ExcelCheck(string b2, string c2, string d2)
{
if (b2 == "X")
{
if (c2 == "X")
{
if (d2 == "X")
return "E2";
return "D2";
}
return "C2";
}
return "ERROR";
}
You mixed up the sequence.
If you do
if(B2 = "X")
then return C2;
if(B2= "X" && condition2)
then return D2;
if(B2="X" && condition2 && condition3)
then return E2;
then it will always return C2, because that's the only condition you only ever really test.
You need to do it in this sequence:
if(B2="X" && condition2 && condition3)
then return E2;
if(B2= "X" && condition2)
then return D2;
if(B2 = "X")
then return C2;
// TODO: What if none of the conditions match ???
So It needs to look like this:
=IF(AND(B2="X",C2="X",D2="X"),E2,IF(AND(B2="X",C2="X"),D2,IF(B2="X",C2,"Define a default value please in case all conditions are wrong")))

Resources