Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best replacement for a char?

I am porting over some Java code to JavaScript. I have a lot of member elements that are a char. Is it more efficient to make those a number or a string (where the string will always be a single character)?

Update: The way it's presently used in Java is I have:

/** alignment is left. */
public static final char TAB_STOP_LEFT = 'l';

/** alignment is center. */
public static final char TAB_STOP_CENTER = 'c';

/** alignment is right. */
public static final char TAB_STOP_RIGHT = 'r';

private char tabStop;

And then I have lots of places where I either assign one of the TAB_STOP_* values to tabStop or test the value of tabStop against specific values. There is no need for it to be l/c/r, I just used those to make it easier to read in the debugger (this code is from Java 1.3, long before enums).

The cleanest way to do this is to make them enums and then tabStop is a number. However, if it's faster & uses less memory if each is a 1 character string, I can do that instead.

Update 2: A big thank you to Juan Mendes & JLRishe - really good detail. What I've decided to do is go with enums (ie numbers) because the difference between the two is minimal and enums make everything a lot clearer.

like image 656
David Thielen Avatar asked May 22 '14 16:05

David Thielen


2 Answers

Well, the first thing to bear in mind here is that "premature optimization is the root of all evil", and unless you have a legitimate concern that this will impact the efficiency of your application, then this is unlikely to be a bottleneck in its performance.

If your objective is to provide enumeration-like functionality, then I think this is even more reason that number vs. string is unlikely to be an issue, but to further assuage those concerns, if you are referencing them consistently throughout your application, then you can always switch back and forth at any future time to test which is more efficient and then use the one that's best.

As in Java, strings and other objects in JavaScript are stored by reference, so in your situation the memory footprint of a one-character string is largely irrelevant and the question becomes how much a reference to that string costs. I'm unable to find any conclusive information on this, but I would strongly suspect that this is at most 64-bits, as that is the largest address size on typical modern machines.

So the issues on the table are:

  1. Memory usage
  2. Efficiency of comparing two values
  3. Ease of debugging

Strings, numbers, and objects should all be equal on #1 because a number takes up 64-bits, and a reference takes up 64 bits.

On #2 again, they're pretty evenly matched, because we can pretty safely assume that the JavaScript engine designer will do a reference equality check on two strings before comparing their values, so if two variables reference the same instance of a string, this should be comparable to comparing two numbers.

On #3, string has a slight advantage over numbers because you can just print them, whereas you need a conversion step to convert a number to an intelligible value.

So I recommend sticking with strings in the short term and then re-evaluating if you encounter some performance concerns. If you write the code well, it should be easy to switch off. And as mentioned above, if you're using references to a small set of strings, then the actual size of those strings is largely insignificant. So feel free to use "left", "center", "right" as the actual values if that makes your debugging more intelligible.

like image 74
JLRishe Avatar answered Sep 21 '22 05:09

JLRishe


There are no chars in JavaScript. You can use 1 character strings. If you wanted to use integers to save memory, you'd have to call String.fromCharCode whenever you needed and that would be creating a String anyway so I find it hard to believe that you would get any benefits from storing integers.

Here's a test where I use an int to stand for 'a' and create a longer string using both strings and the int http://jsperf.com/using-ints-as-chars

Setup code

var x = "a";
var y = 97;

Creating from ints (383 ops/sec)

var str = '';
for (var i = 0; i < 100000; i++) {
   str += String.fromCharCode(y);
}

Creating from 1 char strings (592 ops/sec) FASTER

var str = '';
for (var i = 0; i < 100000; i++) {
   str += x;
}

If you're trying to emulate enums in JS, here's one simple way, using strings so it's easier to debug. The strings are compared using pointers so there's no performance penalty

function Enum(key1, key2, ...) {
    for (var i = 0; i < arguments.length;; i++) {
        this[arguments[i]] = arguments[i];
    }
}

var Planets = new Enum('Earth', 'Mars', 'Venus');
//
if (someValue == Planets.Earth) {
    // console.log(Planets.Earth) -> outputs "Earth"
}

Ideally, you can't test the enum against a string, if you have a string and you want to compare with an enum, you'd need to convert it into an enum first (to make sure it's one of the valid strings). The following is a safer enum.

function EnumInstance(value) {  
    this.getValue = function() { // debug only
        return value;
    }
}

function Enum(enumValues) {
    for (var i = 0; i < arguments.length; i++) {
        this[arguments[i]] = new EnumInstance(arguments[i]);
    }
}

Enum.prototype.fromString = function(enumValue) {
    if ( !this[enumValue] ) {
        throw new Error('Invalid enum value: ' + enumValue);
    }
    return this[enumValue];
};


var Planets = new Enum('Earth', 'Venus', 'Mars');
// This outputs false, you can't compare the strings directly    
console.log("Are Planets.Earth and 'Earth' equal?", Planets.Earth == 'Earth');
// This outputs true, first convert into an enum
console.log("Are Planets.Earth and Planets.fromString('Earth') equal?",
    Planets.Earth == Planets.fromString('Earth'));
// If you try Planets.fromString('Pluto'), an exception will be thrown
try {
    var enumValue = Planets.fromString('Pluto')
} catch(e) {
    console.log(e);
}



console.log("Are Planets.Earth and 'Earth' equal?", Planets.Earth == 'Earth');
// This outputs true, first convert into an enum
console.log("Are Planets.Earth an 'Earth' equal?", 
    Planets.Earth == Planets.fromString('Earth'));

Update

As noted by https://stackoverflow.com/users/1945651/jlrishe, string comparison is not doing using address comparison, like regular Objects, so equality test is going to scan the string. Therefore, the micro optimization would be to use a number instead of a string if you're going to test equality on the string a lot. Note that if you use the "almost-type-safe" enums I showed above, then the equality check would only be for a pointer. See http://jsperf.com/string-comparison-versus-number-comparison and Is JavaScript string comparison just as fast as number comparison?

like image 42
Juan Mendes Avatar answered Sep 22 '22 05:09

Juan Mendes