The Other String



  • I'm often in a situation where there are two possible values for something, but they aren't booleans. They're strings like the combination 'red'/'cyan', or 'plus.gif'/'minus.gif'.

    Often I have to use them in some sort of boolean inversion way. If it's one, then use the other; if it's the other, then use the one.

    If they were actual booleans, I'd just do !bool, of course, but I have strings, and you can't !string. :)

    My question is twofold:

    1. Are there commonly accepted constructions that will allow me to simply invert the string variable and have it contain the other string, without the use of if-kludge like:
    [code]if (varry == 'this') varry = 'that';[/code]

    2. My solution at first was to put the two in an array, reverse, and always take index [0]. Then I thought of a lighter method:

    [code]theIndex = Math.abs(theIndex - 1);[/code]

    which always switches between 0 and 1.
    (the Math.abs is a trick because it's javascript, in which all Numbers are Signed 32 bit. Simply doing a bitwise NOT, [code]~theIndex[/code], would cause 0 to become -2. Sigh.)

    Would you feel that that's a hacky trick? A """clever""" way? Should I give up and use the ifs?



  • You can use varry = (varry == "this")?"that":"this" but whether this is sane or not really depends on the context; in many cases the code will probably be clearer if you use boolean or numerical (with suitable constants) values, until it's actually time to use the strings for something. Using a conditional expression can then look pretty nice: (isPositive?"plus.gif":"minus.gif")



  • I'm not really into JS, but I think it "features" automatic type casting?
    So if your index var was a boolean, would it be converted to 0 for false and 1 for true?
    Not that this would be a clean solution anyway.



  • @TDC said:

    I'm not really into JS, but I think it "features" automatic type casting?
    So if your index var was a boolean, would it be converted to 0 for false and 1 for true?
    Not that this would be a clean solution anyway.


    You're right.

    heh.
    That would look so cool.

    arrizzy[0 + boolvalue];



  • Just use ifs, man, it's what they were designed for. If you want to use a bool, then do this:

    <snip>
    boolean b; // gotta love variable naming

    ... later ...

    outputString = b?'firstval':'secondval';
    b = !b;
    </snip>

    The 'array switching around' nonsense you are considering are orders of magnitude slower than just using an if. If conditionals are good enough for assembler, they're good enough here.




  • You're right.

    I've devised a bad solution to an non-existent problem.

    I just have a thing against comparing against strings with an if.
    For some reason.



  • Well, this problem calls for an Enterprise-worth solution!




    public class StrBool {
        String [] values;
        int index = 0;
       
        public StrBool(String ... values) {
            this.values = values;
        }
       
       
        /**
         * @return the next String in the series
         */
        public String get() {
            if( values == null ) {
                return null;
            }
           
            index %= values.length;
            return values[index++];
        }
       
        public static void main(String [] args) {
            StrBool color = new StrBool("white","gray");
            System.out.println(color.get());
            System.out.println(color.get());
            System.out.println(color.get());
            System.out.println(color.get());
        }
    }



  • I love it!



  • It looks like you're mixing presentation with business logic.  What if you decide to sell your software to another outfit that wants a different colour scheme?

    Really you should evaluate the condition independently and convert it into the presentation aspect as required.  You need to look at the reason for chosing the different items.  It looks like you want a variable "hasGoneUp" - image = hasGoneUp ? "plus.gif" ? "minus.gif";

    This is software development 101 really (although the array method has a pervy niceness about it).



  • @dhromed said:


    [code]theIndex = Math.abs(theIndex - 1);[/code]

    which always switches between 0 and 1.
    (the Math.abs is a trick because it's javascript, in which all Numbers are Signed 32 bit. Simply doing a bitwise NOT, [code]~theIndex[/code], would cause 0 to become -2. Sigh.)

    Whats wrong with [code]theIndex = 1 - theIndex[/code]?

    But, and I'm sure someone else has mentioned this, the right way to do it would be to have a bool, and use it to set the proper string value.


    [code]

    function getNewValue() {   
       selector = !selector;
       return selector ? value1 : value2
    }
    

    [/code]



  • Dhromed, it looks like you're toying with javascript and mostly switching states of displayed objects explicitely in your 'application' logic (switching two images, or the colors of elements).

    If that is so, I'd recommend pulling all the display part into the CSS (the colors and image paths thingies) and using JS to switch (or add/remove) classes dynamically via simple functions, then use CSS selectors to impact these class modifications.

    Let's take a simple example: let's say that you have a simple table, with a checkbox in the first column, and when you select the checkbox the whole row should change it's background to show... uh... that amazing things are happening.

    What you'll do there is create your table in the HTML, then setup CSS rules to stripe your table (cause stripped tables are just more readable) and then add another rule in case your row is selected. Something along the lines of:

    table tr.even {
        background-color: white;
    }
    table tr.odd {
        background-color: #ffd;
    }
    table tr.selected {
        background-color: #f00;
    }

    Then all you need to do is setup a few lines of JS, something looking like that:

    window.onload = function () {
        setupCoolTable();
    }
    

    function setupCoolTable() {
    var tables = document.getElementsByTagName('TABLE');

    // Filter your tables here if you don't want to modify them all,
    // use whatever criteria you want, usually classes.
    
    for(var i=0; i&lt;tables.length; ++i) {
        var rows = tables[i].getElementsByTagName('TR');
        for(var j=0; j&lt;rows.length; ++j) {
            var row = rows[j];
            // You could also parse the children elements to get the checkbox
            // But I'm damn lazy, so I won't.
            var checkbox = row.getElementsByTagName('INPUT')[0];
            if(checkbox) {
                checkbox.onclick = function () {
                    // Grab the row element from our checkbox: need to go 2 levels upwards in the DOM tree
                    var row = this.parentNode.parentNode;
    
                    // No idea for Safari, but MSIE, Firefox and Opera all call "onclick" after the clicking has happened
                    // which means that the box is already in it's final checked/unchecked state when the event fires
    
                    if(this.checked) {
                        // If we checked the box, we have to select the row
                        row.className += ' selected'
                    } else {
                        // If we unchecked the box, we have to remove every single
                        // occurence of "selected" in the classes list.
                        // Gets rid of potential duplicate class bugs, too
                        row.className = row.className.replace(/\bselected\b/g, '');
                    }
                }
            }
        }
    }
    

    }

    This way, the burden of changing the display itself is on the browser's CSS engine (which is often much more optimized and much faster than your JS routines would be even if JS was actually fast) (and it's not), and you can setup extremely complex display modifications on deep trees (I used this technique as a language filter on lists of links, it was more or less instantaneous even with high numbers of links) (didn't work under MSIE though, mostly cause I used the "lang" attribute instead of bothering with more classes, and IE6 doesn't know about Attribute Selectors).

    The point? Leverage the power of your browser's CSS engine, limit the number of Javascripted manipulations (which can get expensive and extremely leaky when you play with the DOM, especially MSIE's), separate your 'application' logic from the pure display logic (you give hint to the browser via the use of classes and attributes instead of telling it what it should to via the use of inline styles)

    And inline styles are bad anyway, better use classes and separated styles when you can, it's cleaner and clearer.

    <script type="text/javascript"> window.onload = function () { setupCoolTable(); }

    function setupCoolTable() {
    var tables = document.getElementsByTagName('TABLE');

    // Filter your tables here if you don't want to modify them all,
    // use whatever criteria you want, usually classes.
    
    for(var i=0; i<tables.length; ++i) {
        var rows = tables[i].getElementsByTagName('TR');
        for(var j=0; j<rows.length; ++j) {
            var row = rows[j];
            // You could also parse the children elements to get the checkbox
            // But I'm damn lazy, so I won't.
            var checkbox = row.getElementsByTagName('INPUT')[0];
            if(checkbox) {
                checkbox.onclick = function () {
                    // Grab the row element from our checkbox: need to go 2 levels upwards in the DOM tree
                    var row = this.parentNode.parentNode;
    
                    // No idea for Safari, but MSIE, Firefox and Opera all call "onclick" after the clicking has happened
                    // which means that the box is already in it's final checked/unchecked state when the event fires
    
                    if(this.checked) {
                        // If we checked the box, we have to select the row
                        row.className += ' selected'
                    } else {
                        // If we unchecked the box, we have to remove every single
                        // occurence of "selected" in the classes list.
                        // Gets rid of potential duplicate class bugs, too
                        row.className = row.className.replace(/\bselected\b/g, '');
                    }
                }
            }
        }
    }
    

    }
    </script>

    <style type="text/css"> </style>

    Exemple of a table that could work. Worked offline, probably won't work once posted in TDWTF...

    Foo Bar Baz duh
    <input type='checkbox' name='foo' value='0'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='1'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='2'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='3'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='4'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' checked="checked" name='foo' value='5'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='6'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='7'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' checked="checked" name='foo' value='8'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='9'> Foo Bar Baz Some other very complicated and fairly long text
    <input type='checkbox' name='foo' value='10'> Foo Bar Baz Some other very complicated and fairly long text

    At the ends of this post, I realize that I didn't answer your question at all. Well, if it was me I'd probably just extract the stuff in a separate function and call the function when I want to do the switching, I hate being clever because I often end up not being able to read my own code. Being lazy's much better imo.



  • Well, didn't work indeed, you can see the script in action there (warning: it's butt-ugly)



  • @masklinn said:

    CSS+JS 101


    Preaching to the reverend, Sir, preaching to the reverend. ;)


Log in to reply