That's a very vague title but I couldn't think of a better way to word it. But, just as an example, think about the direction that a character in a game is moving in. It just feels kind of wrong to be using a string and then doing things like if(character.direction == "left"). It seems to me that it leaves too much room for silly errors, like accidentally using Left or l or whatever instead of left. Are my suspicions correct? If so, what's the preferred way of achieving something like this?
- 9,823
- 377
- 2
- 4
7 Answers
If the language you are using supports the use of enums, I'd use them. It allows you to limit the number of options available for a given type. e.g. in Java:
public enum Direction {
LEFT,
RIGHT,
UP,
DOWN
}
- 1,391
It's terrible practice to use literal strings (or magic numbers) in code.
Enums are good, or at very least use constants (enums of course are just a wrapper type for one or more related constants).
const string LEFT = "left"
if (someThing == LEFT) { doStuff(); }
This simple switch has so many advantages I wouldn't even know where to start to explain them (at least not without some more coffee). Read up on magic numbers, it's the same exact concept, only applied to a number value instead of a string value.
Here's one quick ref, I'm sure there's hundreds more: https://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad
Short answer: Yes, strings are not ideal for any task other than storing and accessing a sequence of textual characters, and even if the underlying bits of an abstraction are strings, there are benefits to referencing them as variables or constants.
Long answer: most languages offer types that are closer to the domain of your problem, and even if they don't, they probably have some method by which you can define left as an entity that is different from right (etc etc). Turning it into a string by using "left" is simply forfeiture of the language and IDE's helpful functionality such as error checking. Even if you have to use
left = "left";
or something equivalent, it has advantages to using the string when you refer to it across your code. For example,
if (player.direction == Left)
would be detected as a compile-time error (best case, java and such) or be flagged by any IDE worth its bits as wrong (worst case, basic and such).
In addition, having the notion of left as a referenceable entity will help you accommodate whatever direction you decide to go with the direction type. By using "left", direction is committed to being a String. If you find or create a better abstraction for the type, you need to go hunting through your entire code body changing every instance of "left". A constant or variable will not require any changes if the type is elaborated.
The type you really want is particular to your domain. What is your code planning to do with your left? Perhaps you will want to mirror the x axis of a texture or sprite that is facing left or moves forward; if so, you might want to make left an object with a property or method that reflects that behavior, with your right object having the opposite non-mirrored result. You could do that logic in an object that represents the sprites or textures, in which case again you will suffer for using "left" instead of left for reasons stated above.
In Java (and probably other languages I don't yet know), enum is a good alternative because in Java, enum is as useful a final class with a finite set of instances. You can define behaviors if you need them, and you can switch to an open class without any hassles outside of the file that declares the enum, but many languages see an enum as a primitive type or require special syntax to use. That leaks the enumhood to code that has no business with it and may need to be corrected later. Make sure you understand your language's concept of an enum before you consider the option.
- 219
You didn't specify your language, but to give a generic answer, you should use strings when you actually need the text, not to represent something. The example you gave for example would simply not be acceptable in production software.
Every language has various basic data types and you should use the one most appropriate for the task. To use your example, you could use numeric constants to represent different states. So left could have a value of zero and right would be one. Besides the reason you mentioned, numerical values take up less space (memory) and it's always faster to compare numbers than it is to compare multiple character strings.
As it's been suggested, use enumerations if your language allows. In your specific example, it's clearly the better choice.
- 121
Just use the data type that makes sense in your situation.
The usage of the string type as an underlying inter/intra-application communication isn't inherently a problem. In fact, sometimes it's preferable to use strings: If you have a public API, it can be desirable for the values going in and out of the API to be human-readable. It's makes it easier for folks using your API to learn and debug.
The real problem with your code lies in repeating the value.
Don't do this:
if (direction == 'left') {
goLeft();
}
If you made a typo in one of these conditionals or other uses of "left" somewhere, you might be unable to effectively perform a codebase-wide search for it, because you've mistyped it!
Instead, code against an enumeration or a constant -- depending on which supports the data type you need in the language(s) you're using.
That means LEFT should be assigned-to once and only once in your application. And, the rest of your code should leverage those enums or constants:
const string LEFT = "left";
if (direction == LEFT) {
goLeft();
}
This also allows you to more easily change the data type you use for your directions later, if you so choose.
- 15,252
Is it bad practice?
Probably yes, but it depends on exactly what you are doing, and also on the programming language you are using.
In your example, we can infer that there is a small and fixed-for-ever set of values that a direction could take. In this case, there are no advantages in using a string, and some definite disadvantages. For this example:
- An
enumtype would be preferable, if your programming language supports this. - Otherwise, named integer constants are the way to go, with a single definition for the constants.
But the answer may be different if the set of values is dynamically modifiable, or needs to evolve over time. In most languages, changing an enum type (e.g. to add or remove a value) requires a complete recompile. (For example, removing an enum value in Java breaks binary compatibility.) And the same applies for named integer constants.
In scenarios like this another solution may be required, and using strings is one of the options. (And you could combine string literals and named constants ... if the scenario entails a fixed core with dynamic extensions.)
If you are implementing in Java, character.direction == "left" is bad practice for another reason. You should not use == to compare strings, because it is testing object identities rather than string equality. (It would work if you could guarantee that all instances of the "left" string have been interned, but that requires whole-of-application analysis.)
- 25,388
- 6
- 66
- 89
As suggested, you should use Enums. However, just using the Enum as a replacement for the Strigns is not sufficient IMHO. In your particualr example, the player velocity should actually be a vector by means of physics:
class Vector {
final double x;
final double y;
}
This vector should then be used to update the player position each tick.
You can then combine that with an enum for higher readability:
enum Direction {
UP(new Vector(0, 1)),
RIGHT(new Vector(1, 0)),
DOWN(new Vector(0, -1)),
LEFT(new Vector(-1, 0));
private Vector direction;
Direction(Vector v) {
this.direction = v;
}
public Vector getVector() { return this.direction; }
}
- 4,638