How not to parse your command line arguments...



  • public static void  main (String args[])
    {
        // Get a hash value for the first argument
        int hash = getHashValue(args[0].toCharArray());

        switch(hash)
        {
            case 972346: // The first argument was "help"
                ...
                break;
            case -91058: // The first argument was "single"
                ...
                break;
            case -4830672: // The first argument was "multi"
                ...
                break;
            // etc
        }
    }



  • Holy crap.  How in God's name did someone come up with that scheme?

    If that doesn't deserve to make the front page, I don't know what does.



  • Ugh...  I've done this WTF myself except I did not hash them -- I cast the first two bytes of the string into a 16-bit integer and fed that into the switch.  This of course limited argument types to things like "-fsomething" "-qsomething", etc.

    It's a shame because it's a nice idea in principle -- it LOOKS like a switch should do it! -- but how is one supposed to do a compile-time hash?
     



  • [quote user="Corona688"]

    Ugh...  I've done this WTF myself except I did not hash them -- I cast the first two bytes of the string into a 16-bit integer and fed that into the switch.  This of course limited argument types to things like "-fsomething" "-qsomething", etc.

    It's a shame because it's a nice idea in principle -- it LOOKS like a switch should do it! -- but how is one supposed to do a compile-time hash?
     

    [/quote]

    #define option_value(a,b) (((a) << 8) | (b))

    All the usual macro caveats apply, starting with "never do this".



  • [quote user="Angstrom"]#define option_value(a,b) (((a) << 8) | (b))

    All the usual macro caveats apply, starting with "never do this".[/quote] Doesn't work with strings.  You could do

    case FOUR_CHAR_OPTION('a','b','c','d')

    ...

    case FIVE_CHAR_OPTION('a','b','c','d','e')

    ...

    But that's just as inelegant as converting to integer values.  The only sane way to do this in a compiled language, I think, would be to build your own sort of pre-pre-processor to convert strings to hashes.



  • WhyTF would you use a hash at all in this situation?



  • Switch statements make processing command line arguments much easier, but Java does not allow string comparisons when using switch statements, which is a WTF in itself. 



  • [quote user="Corona688"]

    It's a shame because it's a nice idea in principle -- it LOOKS like a switch should do it! -- but how is one supposed to do a compile-time hash?

    [/quote]

    With gperf, or something like it. This is not a WTF. This is software-generated code. It's the easiest way to automatically generate an efficient string matcher from a table. It was more common years ago, when computers were slow enough to care... nowadays you don't see it so much, except in legacy code, because nobody worries about the performance of their string lookup tables any more.

    I'm not really sure why somebody bothered to implement one for Java. 



  • [quote user="Avenger"]Switch statements make processing command line arguments much easier, but Java does not allow string comparisons when using switch statements, which is a WTF in itself. [/quote]

     

    I suppose, but can't you fall back on the old trick of (syntax approximate, I'm not a Java guy)

     

    switch (true) {

      case arg[0].equals("-foo"); foo(); break;

      case arg[0].equals("-bar"); bar(); break;

    }

     



  • [quote user="emurphy"]

    I suppose, but can't you fall back on the old trick of (syntax approximate, I'm not a Java guy)

     

    switch (true) {

      case arg[0].equals("-foo"); foo(); break;

      case arg[0].equals("-bar"); bar(); break;

    }

    [/quote]

    Now that would be a WTF...
     



  • [quote user="asuffield"]

    With gperf, or something like it. This is not a WTF. This is software-generated code. It's the easiest way to automatically generate an efficient string matcher from a table. It was more common years ago, when computers were slow enough to care... nowadays you don't see it so much, except in legacy code, because nobody worries about the performance of their string lookup tables any more.

    I'm not really sure why somebody bothered to implement one for Java. 

    [/quote]

    Command line parsing is a one time task in the life of an application. I don't really think you would get a real gain by adding lookup tables.

     On the other side, if you have to compare strings many times and you are concerned by performance, you should take a look at
    java.text.CollationKey.

     



  • [quote user="Avenger"]Switch statements make processing command line arguments much easier, but Java does not allow string comparisons when using switch statements, which is a WTF in itself. [/quote]

    What?

    Ok, switch might make dealing with different integers easy, but as soon as you start performing all sorts of voodoo to convert your strings into numbers, it's no longer easy, especially when it comes to maintainence. How the hell is anyone supposed to add extra commandline options to this code?

    Just use a bunch of if statements, for christs sake, it's not that much harder, and it's not like it's run often, or is hard to debug or anything.



  • [quote user="emurphy"]

    I suppose, but can't you fall back on the old trick of (syntax approximate, I'm not a Java guy)

     
    switch (true) {

      case arg[0].equals("-foo"); foo(); break;

      case arg[0].equals("-bar"); bar(); break;

    }

     [/quote]

    No; Java doesn't allow switching on booleans either. See this page for a discussion of what you can and can't switch on in Java. There aren't many times I wish I could switch on Strings (like in C#), when I do wish I could, I really wish I could...



  • [quote user="acne"]Command line parsing is a one time task in the life of an application. I don't really think you would get a real gain by adding lookup tables.[/quote]

     

    Has nobody here heard of getopt? That is so much simpler. And it is table lookup. You put your options in a table, call getopt, et voila: no more need to write lengthy comparisons...



  • [quote user="gremlin"][quote user="emurphy"]

    I suppose, but can't you fall back on the old trick of (syntax approximate, I'm not a Java guy)

     

    switch (true) {

      case arg[0].equals("-foo"); foo(); break;

      case arg[0].equals("-bar"); bar(); break;

    }

    [/quote]

    Now that would be a WTF...
     

    [/quote]

     

    I reckon it's more of a WTF?...O,NIGI.HTKON!WAM,DIDWAA.

    (What the fuck?...Oh, NOW I get it. Hey that's kind of neat! Wait a moment,damn it doesn't work after all)



  • [quote user="SpoonMeiser"]

    [quote user="Avenger"]Switch statements make processing command line arguments much easier, but Java does not allow string comparisons when using switch statements, which is a WTF in itself. [/quote]

    What?

    Ok, switch might make dealing with different integers easy, but as soon as you start performing all sorts of voodoo to convert your strings into numbers, it's no longer easy, especially when it comes to maintainence. How the hell is anyone supposed to add extra commandline options to this code?

    Just use a bunch of if statements, for christs sake, it's not that much harder, and it's not like it's run often, or is hard to debug or anything.

    [/quote]I'm pretty certain the idea was this:

    switch (args[0].ToLowerInvariant()) {
        case "-something":
            // Stuff
            break;
        case "-wotsit":
            // Stuff
            break;
        case "-other":
            // Stuff
            break;
    }

    Perfectly valid in C#.



  • [quote user="acne"][quote user="asuffield"]

    With gperf, or something like it. This is not a WTF. This is software-generated code. It's the easiest way to automatically generate an efficient string matcher from a table. It was more common years ago, when computers were slow enough to care... nowadays you don't see it so much, except in legacy code, because nobody worries about the performance of their string lookup tables any more.

    I'm not really sure why somebody bothered to implement one for Java. 

    [/quote]

    Command line parsing is a one time task in the life of an application. I don't really think you would get a real gain by adding lookup tables.

    [/quote]

    I certainly can't think of any good reason for doing this in this particular case - but pointlessness is not in itself a WTF.

    (gperf itself is more commonly used for parsing text files. Notably, it's used by gcc to lex source code - much faster than flex and other regexp-based lexers.) 



  • FYI, for Java, the Apache Commons CLI library is the way to go.



  • [quote user="asuffield"]

    With gperf, or something like it. This is not a WTF. This is software-generated code. It's the easiest way to automatically generate an efficient string matcher from a table. It was more common years ago, when computers were slow enough to care... nowadays you don't see it so much, except in legacy code, because nobody worries about the performance of their string lookup tables any more.

    I'm not really sure why somebody bothered to implement one for Java. 

    [/quote]

    This code was definately written by hand, and has comments above it explaining how it was written, how they tested what hardcoded magic numbers to use, and etc:

     
          /*
          Case values determine by args[0] a psuedo hash code algorithm on the
          args string. (Doesn't use regular old hashcode because that might
          be VM dependent)

             helpCase: 89747534
             multiCase: -964127032
             singleCase: -919304285
             ...

          This code figures them out:

          System.out.println("getHashValue(-help) " +getHashValue("-help".toCharArray()));
          System.out.println("getHashValue(-multi) " +getHashValue("-multi".toCharArray()));
          System.out.println("getHashValue(-single) " +getHashValue("-single".toCharArray()));
          ...
          */

     

    The hash codes might be VM dependant so we should write our own hash algorithm! Brilliance. 



  • [quote user="SnakeChomp"]

    This code was definately written by hand, and has comments above it explaining how it was written, how they tested what hardcoded magic numbers to use, and etc:

     
          /*
          Case values determine by args[0] a psuedo hash code algorithm on the
          args string. (Doesn't use regular old hashcode because that might
          be VM dependent)

             helpCase: 89747534
             multiCase: -964127032
             singleCase: -919304285
             ...

          This code figures them out:

          System.out.println("getHashValue(-help) " +getHashValue("-help".toCharArray()));
          System.out.println("getHashValue(-multi) " +getHashValue("-multi".toCharArray()));
          System.out.println("getHashValue(-single) " +getHashValue("-single".toCharArray()));
          ...
          */

     

    The hash codes might be VM dependant so we should write our own hash algorithm! Brilliance. 

    [/quote]

    Huh, okay, that's pretty silly. My bet is that the author had previously (recently) seen some code that had been generated by gperf or one of its clones, failed to comprehend what they were looking at, and did a bit of classic cargo-cult programming. The algorithm is way too similar to be a coincidence. 



  • Okay, I get that someone couldn't resist the desire to use 'switch', but seriously, there is nothing at all wrong with this:

     

    if (arg[0].equals("-help")) {
        showHelp();
    } else if (args[0].equals("-single")) {
        processSingle();
    } else if (args[0].equals("-multi")) {
        processMultiple();
    }

    Simplest is usually best.



  • [quote user="emurphy"]WhyTF would you use a hash at all in this situation?[/quote] It's a workaround to let one do a switch statement on strings in a language which doesn't support this directly.  It actually works quite well but is hard to extend and maintain.



  • I can understand why switch on strings isn't supported in C - a simple switch statement translates into a rather large chunk of asm code and moreover, you lose total control over what your program is doing, because it involves running nontrivial predefined routines that cannot be changed in the code - except by rewriting the compiler, using some implementation-dependent pragma trick or ignoring the built-in routines entirely and writing your own. But in Java, where you have no control whatsoever over what your code is actually doing on the machine level, I don't see why this wasn't implemented.



  • [quote user="Tweenk"]But in Java, where you have no control whatsoever over what your code is actually doing on the machine level, I don't see why this wasn't implemented.
    [/quote]

    Java was originally designed to be easy to implement, not easy to write code with. Successive versions of the language have been trying to make it easier, but the design vision was fundamentally missing the concept of "a really good language for writing software in", and that's not something you can easily patch in later. Most questions of the form "Why doesn't Java ...?" are answered by this.

    (It's always fascinating to look at the design intentions of a language. C was designed to be a good language for implementing a portable version of UNIX - and that's exactly what it is. C# was designed to be a good language for Microsoft to take control of the market, so it's focussed on looking good to people who use other languages, to try and get them to convert. SQL was designed to be a universal interface to any foreseeable relational database, so it's hugely complicated and no database vendor implements the entire language. None of these were the sole design imperative - but all of them are very visible in the resulting language, if you look for them)



  • [quote user="VGR"]

    Okay, I get that someone couldn't resist the desire to use 'switch', but seriously, there is nothing at all wrong with this:

    if (arg[0].equals("-help")) {
        showHelp();
    } else if (args[0].equals("-single")) {
        processSingle();
    } else if (args[0].equals("-multi")) {
        processMultiple();
    }

    [/quote]

    I like to do it like this:

    if ("-single".equals (args[0])) {

    This way a NullPointerException will not occur. 

     



  • [quote user="VGR"]

    Okay, I get that someone couldn't resist the desire to use 'switch', but seriously, there is nothing at all wrong with this:

    if (arg[0].equals("-help")) {
        showHelp();
    } else if (args[0].equals("-single")) {
        processSingle();
    } else if (args[0].equals("-multi")) {
        processMultiple();
    }

    [/quote]

    I like to do it like this:

    if ("-single".equals (args[0])) {

    This way a NullPointerException will not occur.



  • [quote user="SnakeChomp"][quote user="asuffield"]

    With gperf, or something like it. This is not a WTF. This is software-generated code. It's the easiest way to automatically generate an efficient string matcher from a table. It was more common years ago, when computers were slow enough to care... nowadays you don't see it so much, except in legacy code, because nobody worries about the performance of their string lookup tables any more.

    I'm not really sure why somebody bothered to implement one for Java. 

    [/quote]

    This code was definately written by hand, and has comments above it explaining how it was written, how they tested what hardcoded magic numbers to use, and etc:


          /*
          Case values determine by args[0] a psuedo hash code algorithm on the
          args string. (Doesn't use regular old hashcode because that might
          be VM dependent)

             helpCase: 89747534
             multiCase: -964127032
             singleCase: -919304285
             ...

          This code figures them out:

          System.out.println("getHashValue(-help) " +getHashValue("-help".toCharArray()));
          System.out.println("getHashValue(-multi) " +getHashValue("-multi".toCharArray()));
          System.out.println("getHashValue(-single) " +getHashValue("-single".toCharArray()));
          ...
          */

     

    The hash codes might be VM dependant so we should write our own hash algorithm! Brilliance. 

    [/quote]

    SnakeChomp, you're still leaving out how MANY command line options there are. if there are only three, then... yah, it's silly (and possibly copied from somewhere else). But if there are tons of options, then the previous post i made (in the original csod post) holds true. %programname% /hackpentagon might be a valid option, but you don't want every tom, dick, and harry to know that. Spell toLower("BACK DOOR")!

    :-)


Log in to reply