Someone didn't know about case statments..



  • Hi All,

    I was looking through some example code for .NET GIS libary and came acros this:

    If cmd = "" Then
        Return
    Else
                        If System.String.Compare(cmd, 0, "#", 0, 1, True) = 0 Then
                            Return
                        Else
                            If System.String.Compare(cmd, 0, "select ", 0, 7, True) = 0 Then
                                DoSelect(cmd)
                            Else
                                If System.String.Compare(cmd, 0, "insert ", 0, 7, True) = 0 Then
                                    DoNonQuery(cmd)
                                Else
                                    If System.String.Compare(cmd, 0, "update ", 0, 7, True) = 0 Then
                                        DoNonQuery(cmd)
                                    Else
                                        If System.String.Compare(cmd, 0, "delete ", 0, 7, True) = 0 Then
                                            DoNonQuery(cmd)
                                        Else
                                            If System.String.Compare(cmd, 0, "ExecuteScalar ", 0, 14, True) = 0 Then
                                                DoExecuteScalar(cmd)
                                            Else
                                                If System.String.Compare(cmd, 0, "open ", 0, 5, True) = 0 Then
                                                    DoOpen(cmd)
                                                Else
                                                    If System.String.Compare(cmd, 0, "close ", 0, 6, True) = 0 Then
                                                        DoClose(cmd)
                                                    Else
                                                        If System.String.Compare(cmd, 0, "help", 0, 4, True) = 0 Then
                                                            DoHelp()
                                                        Else
                                                            If System.String.Compare(cmd, 0, "set ", 0, 4, True) = 0 Then
                                                                DoSet(cmd)
                                                            Else
                                                                If System.String.Compare(cmd, 0, "prepare ", 0, 8, True) = 0 Then
                                                                    DoPrepare(cmd)
                                                                Else
                                                                    If System.String.Compare(cmd, 0, "schema", 0, 6, True) = 0 Then
                                                                        DoGetSchemaTable()
                                                                    Else
                                                                        If System.String.Compare(cmd, 0, "path ", 0, 5, True) = 0 Then
                                                                            DoSetPath(cmd)
                                                                        Else
                                                                            If System.String.Compare(cmd, 0, "pack ", 0, 5, True) = 0 Then
                                                                                DoPack(cmd)
                                                                            Else
                                                                                _output.WriteLine(("Unknown command: " + cmd))
                                                                            End If
                                                                        End If
                                                                    End If
                                                                End If
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If

    I don't think they knew how to use a Case statment, I know that the above code will do the same as a Select Case but a least case statments make your code a hell of a lot easier to read.

    Happy coding

    Nathan



  •  Most languages don't allow anything but basic types for the switch condition, so strings are out. I know the .NET languages allow strings too, but most people used to other languages are probably not aware of that. Apparently internally the compiler creates pretty much the above code anyway, except for a large number of strings when it's faster to hash the strings and go back to the "normal" numerical switch. That'd also be multi-language solution, but maintaining hashes of strings seems kinda painful :)



  • I know that the above code will do the same as a Select Case but a least case statments make your code a hell of a lot easier to read.
    Even using elseifs would make it look much better :P


  • @Daniel15 said:

    Even using elseifs would make it look much better

    As an immediate fix, I agree that ElseIf would've cleaned this up. I'm sure there's something else that can be done, though, but I can't think of it at the moment.



  • In most programming languages, there is no such thing as an "else if". In C/C++/Java and all languages that define elseif as "else" followed by "if", there is only an "if" with an optional else. The "else if" construct is just another if nested inside the else clause. In those languages (and maybe also the one used there), the only thing that makes a difference between an "else if" and an else with a nested if is the way you layout your code. 



  • @Nandurius said:

    Most languages don't allow anything but basic types for the switch condition, so strings are out.
     

     

    One possible trick to get around this is (pseudocode)

     

    switch (true)

    case s == "foo":

    // do stuff

    break;

    case s == "bar":

    // do stuff

    break;

    default: 

    // do stuff

    end switch

     



  • @emurphy said:

    @Nandurius said:

    Most languages don't allow anything but basic types for the switch condition, so strings are out.
     

     

    One possible trick to get around this is (pseudocode)

     

    switch (true)

    case s == "foo":

    // do stuff

    break;

     

    This will not work in C/C++ or Java (IIRC).  The case labels have to be integer constants or constant expressions. 



  • @LordOfThePigs said:

    In most programming languages, there is no such thing as an "else if".

    That doesn't matter. The issue at hand is .NET, which does have an "ElseIf".



  • Yeah, the title is wrong, as the fix is elseif, not case.  Or at least the indenting could have been done in a saner way so it doesn't creep to the right.  Imagine adding a few new features - before long, the code will be off the side of the screen. 



  • @AbbydonKrafts said:

    @Daniel15 said:
    Even using elseifs would make it look much better

    As an immediate fix, I agree that ElseIf would've cleaned this up. I'm sure there's something else that can be done, though, but I can't think of it at the moment.

     

    If the language has a map data structure and first-class functions (or at least function pointers or Java's anonymous classes), you can use a dispatch table.



  • @ailivac said:

    If the language has a map data structure and first-class functions (or at least function pointers or Java's anonymous classes), you can use a dispatch table.
    Or use a Real Language (*cough*Ruby*cough*) that allows anything in a switch statement.  I mean, can your precious language of choice do this?



  • @AbbydonKrafts said:

    That doesn't matter. The issue at hand is .NET, which does have an "ElseIf".

    I'm completely unfamiliar with the language used here, but why is it calling out to the string compare function?  Does == not work with strings or something? 



  • @morbiuswilters said:

    I'm completely unfamiliar with the language used here, but why is it calling out to the string compare function?  Does == not work with strings or something?
    Worse.  VB.NET doesn't even have a == operator.



  • @bstorer said:

    Or use a Real Language (*cough*Ruby*cough*) that allows anything in a switch statement.  I mean, can your precious language of choice do this?

    You know, I wish somebody would just "fix" case.  The implicit breaks in Ruby are nice, but that "overload the array operator" hack seems really gross.  Why not just something like myah:

     

    switch (string) {
        case "foo":
            do_x();
        case "bar", "baz":
            do_y();
        default:
            print("omg errorz!\n");
            exit(1);
    }


  • @bstorer said:

    Worse.  VB.NET doesn't even have a == operator.

    Now you're just fucking with me. 



  • @morbiuswilters said:

    @bstorer said:

    Worse.  VB.NET doesn't even have a == operator.

    Now you're just fucking with me. 

    LMAO... no. VB doesn't use "==". It uses "=" for assignment AND comparison. However, the other languages in .NET do have "==".



    Also, I use string.Compare in C# instead of ==. Dunno why.



  • @AbbydonKrafts said:

    LMAO... no. VB doesn't use "==". It uses "=" for assignment AND comparison. However, the other languages in .NET do have "==".

    Also, I use string.Compare in C# instead of ==. Dunno why.

    Ahh, well that's not as bad.  In fact, it's arguably better than == for comparison because at least you would avoid junk like "if (x = y)" from C.



  • @morbiuswilters said:

    You know, I wish somebody would just "fix" case.  The implicit breaks in Ruby are nice, but that "overload the array operator" hack seems really gross.  Why not just something like myah:
    You can do that.  See:

    a = "fish"
    case a
      when "cat"
        puts "cat"
      when "dog", "fish"
        puts "dogfish"
      when *["Bob","Joe","Steve"]
        puts "Howdy!"
      else
        puts "No dice!"
    end 

    This outputs "dogfish".  Also, note the case under that: this works, too, without overloading any operators.



  • @morbiuswilters said:

    Ahh, well that's not as bad.  In fact, it's arguably better than == for comparison because at least you would avoid junk like "if (x = y)" from C.
    Python does the same thing.



  •  VB has object.Jam(it), right?



  • @bstorer said:

    This outputs "dogfish".  Also, note the case under that: this works, too, without overloading any operators.

    Ahh, that's awesome, then.  I guess I misunderstood what you linked to because I didn't understand why you'd even need an array if you could just use a comma-separated list.  Ruby has some nice features but I'm not terribly fond of languages that use keywords instead of parens/braces/etc.. to separate blocks.  I like learning new languages but I have pretty much everything I need between PHP and C and at this point I know them so well inside-and-out that I can be much more effective than in a new language. 



  • @morbiuswilters said:

    @bstorer said:

    This outputs "dogfish".  Also, note the case under that: this works, too, without overloading any operators.

    Ahh, that's awesome, then.  I guess I misunderstood what you linked to because I didn't understand why you'd even need an array if you could just use a comma-separated list.

    If you read further down on the link I posted, somebody corrects the OP about it.  But I just needed a good example of the things Ruby lets you do, and that one had the bonus of introducing a major WTF.

    @morbiuswilters said:

    Ruby has some nice features but I'm not terribly fond of languages that use keywords instead of parens/braces/etc.. to separate blocks.  I like learning new languages but I have pretty much everything I need between PHP and C and at this point I know them so well inside-and-out that I can be much more effective than in a new language. 
      I always liked Smalltalk, and Ruby steals many of Smalltalk's better features and mixes them with Perl.  It's very freeing in some ways.  But it can also be extremely frustrating, just like any other language.



  • @NathanW said:

    I don't think they knew how to use a Case statment, I know that the above code will do the same as a Select Case but a least case statments make your code a hell of a lot easier to read.

    And I don't think you know how to read APIs:
    The variation of System.String.Compare used here compares to substrings of given length starting at the given positions in the compared strings. Switches in .NET only allow constant expressions to be used as case labels, so while .NET does allow constant strings, there's no way besides an 'elseif' construct to handle this problem.

    The real WTF is the use of System.String.Compare when System.String.StartsWith should have been used.



  •  What about catfish?



  • @Ragnax said:

    The real WTF is the use of System.String.Compare when System.String.StartsWith should have been used.

    Why not just take the first 5 characters and lowercase them? 



  •  Obviously this is a perfect opportunity for the Enterprise compliant Switch Pattern.

     

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;


    public abstract class Switch
    {
      List<Case> cases = new ArrayList<Case>();
     
      public Switch()
      {
        configureCases();
      }
     
      protected abstract void configureCases();


      public void switchString(String cmd)
      {
        if( cmd == null)
          return;
       
        for( Case c : cases)
        {
          if(cmd.startsWith(c.getName()))
          {
            c.run(cmd);
            return;
          }
        }
       
        DoUnknown(cmd);
      }
     
      protected abstract void DoUnknown(String cmd);
     
      void addCase(Case c)
      {
        cases.add(c);
      }
     
      abstract class Case
      {
        private String name;
       
        public Case(String name)
        {
          this.name = name;
        }
       
        public abstract void run(String cmd);

        public String getName()
        {
          return name;
        }
      }
     
      public static void main(String[] args) throws Exception
      {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        Switch sqlSwitcher = new Switch(){
          @Override
          protected void configureCases()
          {
            addCase(new Case("select"){public void run(String cmd){ DoSelect(cmd); }});
            addCase(new Case("insert"){public void run(String cmd){ DoNonQuery(cmd); }});
            addCase(new Case("update"){public void run(String cmd){ DoNonQuery(cmd); }});
            addCase(new Case("delete"){public void run(String cmd){ DoNonQuery(cmd); }});
            addCase(new Case("ExecuteScalar"){public void run(String cmd){ DoExecuteScalar(cmd); }});
            addCase(new Case("open"){public void run(String cmd){ DoOpen(cmd); }});
            addCase(new Case("close"){public void run(String cmd){ DoClose(cmd); }});
            addCase(new Case("help"){public void run(String cmd){ DoHelp(cmd); }});
            addCase(new Case("set"){public void run(String cmd){ DoSet(cmd); }});
            addCase(new Case("prepare"){public void run(String cmd){ DoPrepare(cmd); }});
            addCase(new Case("schema"){public void run(String cmd){ DoGetSchemaTable(cmd); }});
            addCase(new Case("path"){public void run(String cmd){ DoSetPath(cmd); }});
            addCase(new Case("pack"){public void run(String cmd){ DoPack(cmd); }});
          }
          protected void DoNonQuery(String cmd) {
            System.out.println("DoNonQuery: " + cmd);
          }
          protected void DoSelect(String cmd) {
            System.out.println("DoSelect: " + cmd);
          }
          protected void DoExecuteScalar(String cmd) {
            System.out.println("DoExecuteScalar: " + cmd);
          }
          protected void DoOpen(String cmd) {
            System.out.println("DoOpen: " + cmd);
          }
          protected void DoClose(String cmd) {
            System.out.println("DoClose: " + cmd);
          }
          protected void DoHelp(String cmd) {
            System.out.println("DoHelp: " + cmd);
          }
          protected void DoSet(String cmd) {
            System.out.println("DoSet: " + cmd);
          }
          protected void DoPrepare(String cmd) {
            System.out.println("DoPrepare: " + cmd);
          }
          protected void DoGetSchemaTable(String cmd) {
            System.out.println("DoGetSchemaTable: " + cmd);
          }
          protected void DoSetPath(String cmd) {
            System.out.println("DoSetPath: " + cmd);
          }
          protected void DoPack(String cmd) {
            System.out.println("DoPack: " + cmd);
          }
          protected void DoUnknown(String cmd) {
            System.out.println("Unknown command: " + cmd);
          }
        };
       
        while(true)
        {
          sqlSwitcher.switchString(in.readLine());
        }
      }
    }

    For even better extendability, add XML. 


Log in to reply