Jump to content

  • Log In with Google      Sign In   
  • Create Account


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


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
35 replies to this topic

#21 King Mir   Members   -  Reputation: 1948

Like
0Likes
Like

Posted 16 July 2012 - 06:40 PM



C++ switch statements only work with some data types (mostly ints) - not with std::strings. Even so, that's pretty ugly syntax. Posted Image

Which is why I said "some languages" and not "c++ and some languages"

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.

Why do you think switches are ugly?

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. Posted Image

Totally don't agree here. Switching on a variable is what switches are for.

Sponsor:

#22 Servant of the Lord   Crossbones+   -  Reputation: 18491

Like
0Likes
Like

Posted 16 July 2012 - 07:02 PM

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.


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.


Ah, my mistake then.

Edited by Servant of the Lord, 16 July 2012 - 07:15 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#23 Cornstalks   Crossbones+   -  Reputation: 6974

Like
1Likes
Like

Posted 16 July 2012 - 07:14 PM

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

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

I presume you mean logical OR (operator ||), correct?

and using more lines to do so

Depends on how you format your code. I'd probably break the if 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 operator == was not, and I cared about that).
[ 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 ]

#24 Servant of the Lord   Crossbones+   -  Reputation: 18491

Like
1Likes
Like

Posted 16 July 2012 - 10:18 PM


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

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

I presume you mean logical OR (operator ||), correct?


</facepalm> Yes, logical OR. Posted Image


and using more lines to do so

Depends on how you format your code. I'd probably break the if condition into multiple lines if it was that long anyway. But that's me.


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).

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.

Edited by Servant of the Lord, 16 July 2012 - 10:48 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#25 King Mir   Members   -  Reputation: 1948

Like
1Likes
Like

Posted 16 July 2012 - 11:07 PM

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.

#26 Krohm   Crossbones+   -  Reputation: 3049

Like
2Likes
Like

Posted 17 July 2012 - 03:49 AM

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.
  • there should be input sanitization forcing a coherent format... but let this pass.
  • 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.
  • 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 varx and VARX 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.

#27 Álvaro   Crossbones+   -  Reputation: 12912

Like
0Likes
Like

Posted 17 July 2012 - 06:10 AM

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.

Edited by alvaro, 17 July 2012 - 06:12 AM.


#28 Servant of the Lord   Crossbones+   -  Reputation: 18491

Like
1Likes
Like

Posted 17 July 2012 - 12:09 PM

...
...

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?

Edited by Servant of the Lord, 17 July 2012 - 12:10 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#29 Cornstalks   Crossbones+   -  Reputation: 6974

Like
2Likes
Like

Posted 17 July 2012 - 12:29 PM

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 :)
[ 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 ]

#30 Servant of the Lord   Crossbones+   -  Reputation: 18491

Like
0Likes
Like

Posted 17 July 2012 - 12:50 PM

@Cornstalks: I lack succinctness. Posted Image
My posts are usually too repetitive, reiterating previous points multiple times. Posted Image
It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#31 King Mir   Members   -  Reputation: 1948

Like
0Likes
Like

Posted 17 July 2012 - 11:26 PM

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.

The examples were not C++. It was a divergent discussion on the elegance of using switch statements to compare a value to series of literals when there are only two possible branch paths. In fact the same question arises when using int, so the discussion is relevant to C++, though the examples aren't.

#32 Krohm   Crossbones+   -  Reputation: 3049

Like
0Likes
Like

Posted 18 July 2012 - 12:47 AM

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?

Almost there.
3) If you do not sanitize and need to work on strings, at least make sure you're understanding the real meaning of the data you're looking at. Compare them case-insensitive for this specific case using toupper.

#33 TMKCodes   Members   -  Reputation: 271

Like
0Likes
Like

Posted 18 July 2012 - 08:56 AM


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?

Almost there.
3) If you do not sanitize and need to work on strings, at least make sure you're understanding the real meaning of the data you're looking at. Compare them case-insensitive for this specific case using toupper.


About point one. So if I can't use username in the database and username given by the user as a input to compare if the user gave the correct input then what the fuck I should compare? Better example yet is searching for a username in the database without knowing the users id. String comparisons happen every day everywhere, so why they should not be used? Even when you log in to gamedev.net. We would not have compilers if we would not compare strings...

Edited by TMKCodes, 18 July 2012 - 09:00 AM.


#34 BinaryPhysics   Members   -  Reputation: 294

Like
0Likes
Like

Posted 18 July 2012 - 11:25 AM

"Saves space" is pushing it though, overhead of calling method is likely to outweight space saving but of course this is irrelevant and space saving is hardly the reason to use this approach.


I did have this in the back of my mind by I was, for some bizarre reason I can't currently recall, thinking more in terms of space in the actual source file. Having 30 lines to catch a single string is pretty ugly...

It's also more human-friendly. It allows the program to recognise a string however someone wants to write it.

#35 Williamcrdv   Members   -  Reputation: 106

Like
1Likes
Like

Posted 18 July 2012 - 12:48 PM

you can use the string::find() member function as I do below to check if the string contains "tiffany" which would remove all of the other superfluous checks. You could search for the minimal accepted permutation of the name, even just "tif" (just in case she can't spell her name correctly).


#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main(void)
{
string username;
cout << "Hello \n";
cin.get();
cout << "What is your name? ";
getline (cin, username);
cout << "Your name is: " << username;
cin.get();

transform(username.begin(), username.end(), username.begin(), ::tolower);
if (username.find("tiffany") != username.npos)

{
cout << "Your name is Tiffany... \n The Creator has a message for you: \n I love you Cupcake";
cin.get();
}
else
{
cout << "Your name is not Tiffany.";
cin.get();
}
}

#36 Sarmon   Members   -  Reputation: 103

Like
0Likes
Like

Posted 21 July 2012 - 03:30 AM


if (username == "Tiffany" || "tiffany" || "Tiffany McClure" || "tiffany McClure" || "Tiffany Mcclure" || "tiffany mcclue")



Am I the only one thinking that looks pretty elegant? Is there any language that implements this way of checking the same variable for different boolean cases?

Regular expressions can match a specified pattern, every language will have at least one implementation of a regex language.

EDIT: Although that's not exactly what you're asking, the effect is to want to test your variable against a range, which for strings is equivalent to a pattern.

Edited by Sarmon, 21 July 2012 - 03:32 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS