19

How can polymorphism replace an if-else statement or Switch inside of a loop? In particular can it always replace an if-else? Most of the if-thens I use inside of loops are arithmetic comparisons. This question is spawned from this question.

int x;
int y;
int z;

while (x > y)
{
     if (x < z)
     {
         x = z;
     }
}

How would this work with polymorphism?
NOTE: I wrote this in Java but am interested in this for any OOL.

Community
  • 1
  • 1
WolfmanDragon
  • 7,851
  • 14
  • 49
  • 61

5 Answers5

27

Polymorphism usually replaces switch statements when each case corresponds to a different type. So instead of having:

public class Operator
{
    string operation;

    public int Execute(int x, int y)
    {
         switch(operation)
         {
             case "Add":
                 return x + y;
             case "Subtract":
                 return x - y;
             case "Multiply":
                 return x * y;
             case "Divide":
                 return x / y;
             default:
                 throw new InvalidOperationException("Unsupported operation");
         }
    }
}

you'd have:

public abstract class Operator
{
    public abstract int Execute(int x, int y);
}

public class Add : Operator
{
    public override int Execute(int x, int y)
    {
        return x + y;
    }
}

// etc

However, for the comparison type of decision you provided, polymorphism really doesn't help.

Mudassir Hasan
  • 28,083
  • 20
  • 99
  • 133
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • How does creating the four classes make the decision as to which class to use? It appears you may still need a switch or if else. – Isa Sep 17 '21 at 17:09
  • @Isa: Because the calling code only needs to use Operator, and the right code is automatically executed based on the concrete type at execution time. It's "what type is the object" that makes the decision for what code to use. You'd still need something to create the instances of the right type, but that's at a separate place in the code (and may well already effectively have separate paths). – Jon Skeet Sep 17 '21 at 17:15
  • Jon, So am I correct in understanding that you need to use a switch or if-then in order to create the correct class? – Rsc Rsc Aug 29 '22 at 01:13
  • @RscRsc: No - the first part of my answer is *with* the switch statement; the second part of my answer is the inheritance-based approach which replaces it. – Jon Skeet Aug 29 '22 at 07:26
  • Oh I am missing something. Lets say there is a method that calls your class-based code in the second part of the answer. `CalculateMe("Add", 5, 2);` then how would the class-based code you wrote know to figure out to instantiate the 'Add' class? – Rsc Rsc Aug 30 '22 at 20:38
  • I couldn't edit my previous comment so writing a new one - I am giving a couple of hypothetical situations leading to this code. Say there is a file with a to do list like this `Add, 5, 2`. Or maybe there is a bunch of buttons on a calculator and the front end code is relaying the operator to the back end instead of figuring it out. In these situations, where the calling code is passing on the work of figuring out the operator to the called method, how would you instantiate the correct class? – Rsc Rsc Aug 30 '22 at 20:55
  • @RscRsc: That would be a different question, basically. If you want that question answered, you should ask that question - it's not the one that was asked back in 2009. – Jon Skeet Aug 31 '22 at 06:37
  • thanks for quick response. ok let me start a new question. – Rsc Rsc Aug 31 '22 at 15:10
3

Polymorphism is not really applicable in the example you provided.

See this SO answer.

Community
  • 1
  • 1
Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
3

Polymorphism can only replace if tests when the if test is basically dispatchi g to a variety of methods depending on the "type" of an object. Eg if object is type X invoke foo if it's a Y invoke bar and so. In this contrived example one would define an interface DoSonething with a method bad(). Both X and Y would implement Baz and have their respective baz() invoke foo() for X and bar() for Y. This simply calling baz() would eliminate the need for a if test.

mP.
  • 18,002
  • 10
  • 71
  • 105
3

In Smalltalk, "if" is actually a polymorphic method in Boolean. In the following example:

[ x>y ] whileTrue:  
  [   
    ( x<z ) ifTrue: [ x:=z ]        
  ]

The ifTrue:aBlock message is implemented in True as "execute this block" and in False as "ignore this block", so depending on what the (x<z) evaluates to, either implementation will be called.

So in Smalltalk polymorphism replaces every if-else construct by default :)

Rafał Dowgird
  • 43,216
  • 11
  • 77
  • 90
  • Disclosure: I have never used smalltalk. Is there not still a Boolean value here? If so is it just not a fancy IF-Then-Else statement wrapped in polymorphism? I'm just asking for clarification. – WolfmanDragon Feb 09 '09 at 22:40
  • Yes, there is a Boolean value and it is an if-then-else statement implemented via polymorphism. I am aware that this polymorphism happens at a different level than the one from the question, but I think that the mechanism is still interesting enough to justify this answer. – Rafał Dowgird Feb 10 '09 at 07:30
1

One pattern is to have objects which represent the result of the test, and objects which represent the block to execute. The result objects have overridden selection functions, so if Bool had a choose(T positive, T negative) then Bool.TRUE would return the positive argument and Bool.FALSE would return the negative. Naive implementations of smalltalk-family languages work like that.

To encode your while loop in that form, there needs to call the choose method on the result of comparing x and y to determine whether to call the block for the inside of the while loop, and that block also uses compare and choose to set the value of x. A more literal translation would be to choose either a block which sets x to z or one which does nothing; instead it just uses choose to set x back to the same value.

Obviously it's overkill and inefficient for this simple case.

public class WantonPolymorphism {

    static class Int32 {
        final int value;
        Int32 ( final int value ) { this.value = value; }

        Compare compare ( Int32 other ) {
            // Java runs out of turtles at this point unless you use
            // an enum for every value
            if ( this.value < other.value ) return Compare.LESS;
            if ( this.value > other.value ) return Compare.GREATER;
            return Compare.EQUAL;
        }
    }

    enum Compare {
        LESS {
            <T> T choose (T less, T equal, T greater) { return less; }
        },
        EQUAL {
            <T> T choose (T less, T equal, T greater) { return equal; }
        },
        GREATER {
            <T> T choose (T less, T equal, T greater) { return greater; }
        };

        abstract <T> T choose (T less, T equal, T greater) ;
    }

    interface Block { Block execute () ; }


    /**
     * Main entry point for application.
     * @param args The command line arguments.
     */
    public static void main (String...args) {
        Block block =  new Block() {
            Int32 x = new Int32(4);
            Int32 y = new Int32(3);
            Int32 z = new Int32(2);

            public Block execute () {
                System.out.printf("x = %d, y = %d, z = %d\n", x.value, y.value, z.value);

                return x.compare(y).choose(done, done, new Block () {
                    public Block execute () {
                        x = x.compare(z).choose(x,x,z);

                        return x.compare(y).choose(done, done, this);
                    }
                });
            }

            Block done = new Block () {
                public Block execute () {
                    System.out.printf("x = %d, y = %d, z = %d\n", x.value, y.value, z.value);
                    System.exit(0);
                    return this;
                }
            };
        };

        for(;;) 
            block = block.execute();
    }
}
Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171