Is there a functional difference between comparison operators such as "ne, eq, != and =="? What really is the difference between "ne" and "!="? What about "eq" and "=="? When should you use one versus the other? Is there a performance impact? Why or why not? What is happening behind the scenes when I choose one of these operators that makes them so different? These are the questions we're here to answer.

To explain what's happening, let's first discuss what these operators are, and how they work. First of all, yes, there is a difference between "eq" and "==" (and logically their counterparts "ne" and "!="). While logically they represent the same thing in the flow of your code, they behave very differently under the covers. To call them by name, "eq" is a string operator while "==" is a polymorphic operator. What is a polymorphic operator, you ask? Excellent question. A string operator always compares two strings. This means it will take whatever data you supply it with, convert it into a string, and perform the comparison. A polymorphic operator attempts to use the format it deems most appropriate (based on the value of the variable(s) involved in the comparison) to perform the comparison in question. Need more explanation? Okay.

Back in the early days of programming, when code was chiseled into stone tablets, you had to specifically set not only a variable's value, but also its type. You'd define integers as integers and strings as strings, and they would be treated as such regardless of the value that variable contained or the way it was referenced with operators. While you can still do this in many languages for performance gains, there are other languages that operate with flexibility in mind at the cost of some of that raw performance. In some of these languages, such as TCL, the value of the variable and the way you address that variable when calling it are what determine whether it is treated as a certain data type. You can have a single variable, with the same value treated as (in this case) either a string or an integer, based solely on the operator choice mentioned above. This is known as a type of "Polymorphism".

Polymorphism refers to the ability of a given section of code to be used with multiple types of values without having to re-define the variable types. The idea of Polymorphism in general is completely reliant on TCL's "Everything is a string"concept. This is a core TCL concept and I invite you heartily to read more about it, but I won't go into it in detail here. Basically, TCL views the world's data as interchangeable in format, and everything has some overlap, allowing "easy" comparisons. The word "Polymorphism" itself is derived from the Greek poly (meaning many) and morph (meaning form). Indeed the idea of polymorphism in coding allows you to use many forms of data interchangeably. This convenience, however, is not without a cost.

While there are many types of Polymorphism, the one we're most interested in is called "coercion". This is the most relevant in our TCL based environment. Every time you access a variable you have the ability to coerce that value into a given data type depending on the operation you're using it with. This means that the same variable can be interpreted differently in a series of different operations.

For instance, if I had a simple counter that I was incrementing in a loop structure, I would write it like this:

set x 0
foreach dir {[split [HTTP::uri] "/"]} {
  incr x
  if {$x == 4} {
    ...
  }
}

In this way I'm ensuring that the comparison is done between two integers. Since the "==" operator is the Polymorphic operator for an equals comparison, and the value of x is an integer (the incr command only deals with integers) the literal value "4" gets coerced into an integer so that the comparison can be done with like data types. This can be a performance improvement over using a string operator, like the below example, as comparing large integers as strings can be quite costly. As with anything in coding, the number of comparisons and the size of the data being compared greatly effects how much improvement you'll see from this, but the concept remains the same.

 

Had I chosen to use the "eq" or "equals" operators, the result would be the same, but the overhead would be different. This would look like:

set x 0
foreach dir {[split [HTTP::uri] "/"]} {
  incr x
  if {$x eq 4} {
    ...
  }
}

Note that the only thing that changed here is that the "==" operator was swapped out for the "eq" operator. Since "eq" is a string operator, you're assuring that the comparison will be done between two strings, thereby treating whatever data is held in x as a string, regardless of what that value is. This can be a time saver, if you know you're comparing strings, as a polymorphic comparison may try to convert the string out of the proper format before comparing, which eats precious cycles. In this case, however, we know we're comparing integers, so the string operator actually costs us more time, as it's going to convert the literal 4 into a string, then convert the value of x to a string, and perform a string comparison when an integer comparison would have been faster. These same concepts hold true for "ne" versus "!=", just with the logical value of the operators opposite the ones outlined above, obviously.

 

Hopefully this clears up when you'd want to use string operators versus polymorphic operators. This really ties into the idea of always keeping the type of data you're dealing with in mind, which is something that's important in all programming. Between using the right operator as discussed here, and learning how to use Expressions and Variables and the brackets braces and joy that go along with them as discussed in a couple of our other Tech Tips, you'll be well on your way to writing clean, optimized TCL code, resulting in iRules so fast you'll amaze your friends.

Get the Flash Player to see this player.