(C++ Beginner) I hate to post here, but... why won't my "if" statement evaluate a string?

Started by
34 comments, last by Sarmon 11 years, 9 months ago

[quote name='King Mir' timestamp='1342474441' post='4959760']
[quote name='Servant of the Lord' timestamp='1342471896' post='4959736']
C++ switch statements only work with some data types (mostly ints) - not with std::strings. Even so, that's pretty ugly syntax. happy.png
Which is why I said "some languages" and not "c++ and some languages"[/quote]Ah, I thought your "some languages" was a not-so-subtle "hint hint", referring to C++ itself (What with the topic being about C++, and the "Close enough?" comment).[/quote]I was responding to kunos's question if any languages allowed the syntax he quoted.

Why do you think switches are ugly?[/quote]
Not switches, per se, but using switches (which are typically meant to branch logic) to imitate the use of AND logic (which is what && is for).
In some situations it may be the best solution, but in general I prefer to use if() when I mean logical IF, and && when I mean logical AND. smile.png
[/quote]Totally don't agree here. Switching on a variable is what switches are for.
Advertisement
Switching, yes, but you aren't switching (the code execution path isn't really changing much), you're faking multiple logical ANDs, and using more lines to do so, with - in my opinion - slightly less code clarity.


[quote name='Servant of the Lord' timestamp='1342478231' post='4959787']
Ah, I thought your "some languages" was a not-so-subtle "hint hint", referring to C++ itself (What with the topic being about C++, and the "Close enough?" comment).
I was responding to kunos's question if any languages allowed the syntax he quoted.[/quote]

Ah, my mistake then.

*snip*
[...] AND logic (which is what && is for).
[...] and && when I mean logical logical AND. smile.png


[...] you're faking multiple logical ANDs

I presume you mean logical OR ([font=courier new,courier,monospace]operator ||[/font]), correct?


and using more lines to do so

Depends on how you format your code. I'd probably break the [font=courier new,courier,monospace]if[/font] condition into multiple lines if it was that long anyway. But that's me.

I don't think I'd use a switch for only two code paths (like in this example), but I might use it if there are more (or if I was switching on strings and the switch was done by hashes and [font=courier new,courier,monospace]operator ==[/font] was not, and I cared about that).
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

[quote name='Servant of the Lord' timestamp='1342486937' post='4959823']
*snip*
[...] AND logic (which is what && is for).
[...] and && when I mean logical logical AND. smile.png


[...] you're faking multiple logical ANDs

I presume you mean logical OR ([font=courier new,courier,monospace]operator ||[/font]), correct?[/quote]

</facepalm> Yes, logical OR. wacko.png


and using more lines to do so

Depends on how you format your code. I'd probably break the [font=courier new,courier,monospace]if[/font] condition into multiple lines if it was that long anyway. But that's me.[/quote]

Certainly, I typically write longer comparisons like this:
if(blah || blah || blah
|| blah || blah)
{
//...
}


...and, depending on the logic of the function, may even group the options into boolean variables.
bool logicalEvaluationA = (blah || blah || blah);
bool logicalEvaluationB (blah || blah);
if(logicalEvaluationA || logicalEvaluationB)
{

}


...but switch statements just have more visible clutter (to me). Furthermore, the name 'switch()' implies switching, and past usage and experience teaches your mind that that is what those kinds of statements do.

When you read code, you have certain expectations from blocks of code before you even read it. while() implies a loop, as does for(). for() usually implies an iteration or a fixed number of loops, whereas while() usually implies a continuous loop until some condition is meant. if() usually implies conditional logic, if-else() multiple branches, and switch() usually implies a large number of branches.
When these "first glance" expectations are then turned on their head following a closer inspection, my mind has to do a double take, and reevaluate the whole block of code.

Doing things like:
do
{

}
while(false); //Hahah, not actually a loop!


Or:
switch(option)
{
case :
case :
case :
case :
case :
{

} break;
default: //Jokes on you, I'm actually a if-else() statement in disguise!
{

} break;
}


...increase the time it takes (at least for me) to understand code, because my mind has to then backpedal and throw out some previously made common assumptions about the code that is usually true, but in this case is not.

Often times when reading through code, you don't actually have to read the fine details of the code, you can just look at the general picture and understand what it's doing. This is really useful. If the code does what it is expected to do, and looks like it should do, that's good. If you have to manually mentally walk through a piece of code to find out what it actually does, because it breaks expectations, that's not good (but is acceptable if that's what is required - for example, a heavily optimized algorithm).

Reading code (from top of the page downward), you start to build an idea of what the code does.
for(int i = 0; i < myVector.size(); i++)

"...looking at the lady in the red dress? Look again, Neo."
for(int i = 0; i < myVector.size(); i++)
{
//...code...
if((myVector % 2) == 1)
{
i++;
}
//...code...
}


Additional logic that controls the flow of the entire loop is buried in the body of the loop?!

A 'break', 'return', or even 'continue' is fine, because your mind easily parses those keywords and can argument it's understanding of the code very rapidly. It'll take a few moments longer for your mind to recognize the 'i++' alters the flow of the code (and even longer if it's hidden away admist other code), and it may even have to throw out parts of its previous understanding that your mind has already built up, causing even more mentally delay and extra mental, "Let me double check this" processing as it encounters unexpected deviations from the norm.

I don't think I'd use a switch for only two code paths (like in this example), but I might use it if there are more (or if I was switching on strings and the switch was done by hashes and operator == was not, and I cared about that).
[/quote]
Well sure, I'm not at all saying switch()s are bad. I'm not even saying case fall-through is bad. When asked about it originally, I was trying to explain that using a switch() when you really want a single if() or if-else() is undesirable as a default thing to go to, because it makes your code less understandable at-a-glance, and departs from the norm of what is expected that a switch() statement does.

For multiple branches of logic, switch() statements are excellent. For other situations, switch() statements are less desirable. 'Less desirable' may be a fine tradeoff if something else is needed in its place, like speed or memory optimization, but if you are decreasing readability and not gaining anything at all, that's not a good tradeoff - so as a default (but I'm not saying "never" or "always" - there are exceptions), one should go for the most commonly expected solution, so code does what one expects it to do.

An extreme example of such a valid optimization vs code expectation tradeoff would be Duff's Device.
Do you understand that code? Being honest with yourself, how many times did you have to read through it carefully (the first time you ever saw it) before you understood it?

Now this, on the other hand:
int sum = 0;
for(iterator = numbers.begin(); iterator != numbers.end(); iterator++)
{
sum += *iterator;
}


...you barely even had to read. You already knew, in general, what it did before you even read the fine details of it... and even reading the fine details, you understood it without any mental hiccups or backpedalling, and so having understood it, you continued onward to reading this paragraph of my post - if you were reading real code, you would have continued on reading code further down the page, and the above for() loop wouldn't have interrupted your reading in the least, and certainly wouldn't have caused your understanding of the inner workings of the function to come to a crashing halt like a more extreme example of code-convolution might have.

Using a switch() to choose between multiple hashes of a string? Certainly, because you're switching between multiple code branches. When you see a switch() statement, this is your instant expectation from your prior experience with switch statements.
Using a switch() to imitate "if(optionA OR optionB OR optionC)" won't cause too much mental backpedaling, but it will take a bit longer to process because you are failing to take advantage of the instant mental expectation of if()s which are normally used for that purpose... so by default, one should prefer the more common "if( OR OR )" with its built-in mental benefits and syntactical simplicity.
I agree with you in general, but not concerning switch. There's not much cognitive difference between this:
switch(myString){
case "--option1":
case "-o1":
case "o1":

...
break;
default:
...
}

And this:
switch(hash(myString)){
case hash("--option1"):
case hash("-o1"):
case hash("o1"):
...
break;
default:
...
}


Or doing the same thing with a single character. Not having to write myString== a bunch of times reduces code size, and so clarifies what's going on; it's only comparing values to a single variable. To each his own I guess.

I'm confused about what you are disagreeing with.

Are you saying that this...

if(name == "person mcperson" || name == "Person Mcperson" || name == "Person McPerson"
|| name == "PERSON MCPERSON" || name == "person MCPERSON" || name == "PERSON mcperson" || ...etc... )
{
//...
}


...is better than this:
std::string name = "Person McPerson";
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
if(name == "person mcperson")
{
//...
}


Or are you just saying to cache the lowercase name when possible, so you don't have to convert it every function call?
Neither, but it appears you're likely got things in reverse.
What I'm saying is that the whole notion of string (upprer/lower case) permutations is flat out insane.The difference is conceptual, even before we start thinking about comparing strings, so many things have gone wrong I can hardly believe.

  1. there should be input sanitization forcing a coherent format... but let this pass.
  2. everyone thinking about storing or even computing those permutations is on the wrong track: this is clearly not the way to do things (very special bonus for elaborations about working on strings loaded from a file you know nothing about!). But what the heck, let this pass as well.
  3. everyone saying that toupper is to be used "to save space" is not saying it as (s)he should. What (s)he should say is "you have to use the proper function becouse everything else is flat out broken and if you have come so far you're really better take a step back and rethink everything you have done so far"!

Original OP question is: why my string comparisons do fail? Because of operator precedence and syntax rules.
But the problem he is having, behind the scenes is he does not understand the basic of string comparisons in this specific context (as much as having two variables [font=courier new,courier,monospace]varx[/font] and [font=courier new,courier,monospace]VARX [/font]might make sense, I hardly believe the difference between Person McSurname and Person MCSurname is meaningful in most cases).
All posts regarding permutations are madness. And should be eradicated. Some people reading this might actually believe working with the permutation is somewhat ... maybe encouraged? Think of the children!

If a string is so important permutations have to be checked... it probably is not a string!

I don't know if I'm being able to explain myself.

Previously "Krohm"

I think I should point out that neither of King Mir's snippets is valid: You can't use `switch' on strings, and you can't have non-constant values in the case clauses.

You can use a hash map (`unordered_map') to convert a string into an enum and then switch on the enum. In one case I used a trie instead of a hash map because speed was critical, but you generally won't need that.
...
...

I don't know if I'm being able to explain myself.


I think I get what you're saying, and those are some good points. Let me try to summarize what I think you are saying:
1) For comparisons, strings are not what should be used - if you are using a string to frequently compare to other values, it shouldn't be a string.
2) If you have to compare strings (because they come from user input - like parsing files) they should be sanitized when received, not when compared.

Am I missing anything?

I think I should point out that neither of King Mir's snippets is valid: You can't use `switch' on strings, and you can't have non-constant values in the case clauses.

I don't know if you saw this. If you did, sorry for being redundant. That's what Servant of the Lord pointed out, but King Mir was responding to kunos's question if any languages allowed the syntax he quoted. Since then, the thread kind of derailed into non-C++ land. Yes, it's worth pointing out that this can't be done in C++, but it's also worth pointing out that this can be done in some other languages.

@Servant of the Lord: I wasn't saying you implied all switches were bad. The primary point of my post was the operator mix up :) The other points were just small addendum; I didn't think you'd write such an epic reply ha. I think I'm more used to seeing switch statements used in ways similar to Duff's Device, though. That's probably due to my work in C with FFmpeg, where things like that are common. Whether it's clear or not to someone I think depends on both the person and the situation. And whether or not code like that is a "good idea" is something else too :)
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
@Cornstalks: I lack succinctness. happy.png
My posts are usually too repetitive, reiterating previous points multiple times. dry.png

This topic is closed to new replies.

Advertisement