Relational operator

In computer science, a relational operator is a programming language construct or operator that tests or defines some kind of relation between two entities. These include numerical equality (e.g., 5 = 5) and inequalities (e.g., 4  3).

In programming languages that include a distinct boolean data type in their type system, like Pascal, Ada or Java, these operators usually evaluate to true or false, depending on whether the conditional relationship between the two operands holds or not. In languages such as C, relational operators return the integers 0 or 1, where 0 stands for false and any nonzero value stands for true.

An expression created using a relational operator forms what is known as a relational expression or a condition. Relational operators can be seen as special cases of logical predicates.

Equality

Usage

Equality is being used in many programming-language constructs and data types. It is used to test whether an element already exists in a set, or to access to a value through a key. It is used in Switch statements to dispatch the control flow to the correct branch, and during the unification process in logic programming.

One of the possible meaning of equality is that "if a equals to b, then we can use either a or b interchangeably in any context without noticing any difference". But this statement does not necessarily hold, particularly when taking into account mutability together with content equality.

Sameness (object identity) vs. content equality

Sometimes, particularly in object-oriented programming, the comparison raises questions of data types and inheritance, equality and identity. It is often necessary to distinguish between:

In many modern programming languages, objects and data structures are accessed through references. In such languages, there becomes a need to test for two different types of equality:

  • Structural equality (e.g. their contents are the same). which may be either shallow (testing only immediate subparts) or deep (testing for equality of subparts recursively). A simple way of achieving this is through reesentational equality - checking that the values have the same representation.
  • Some other tailor-made equality, preserving the external behavior. For example, 1/2 and 2/4 are considered equal when seen as a rational number. A possible requirement would be that "A = B if and only if all operations on objects A and B will have the same result", in addition to reflexivity, symmetry and transitivity.

The first type of equality usually implies the second (except for things like NaN which are unequal to themselves), but the converse is not necessarily true. For example, two string objects may be distinct objects (unequal in the first sense) but contain the same sequence of characters (equal in the second sense). See identity for more of this issue.

Real numbers, including many simple fractions, cannot be represented exactly in floating-point arithmetic, and it may be necessary to test for equality within a given tolerance. Such tolerance, however, can easily break desired properties such as transitivity, whereas reflexivity breaks too: the IEEE floating point standard requires that Nan ≠ NaN holds.

Other programming elements such as computable functions, may either have no sense of equality, or that equality is itself not computable. For these reasons some languages define an explicit notion of "comparable", in the form of a base class, an interface, a trait or a protocol, which is used either by explicit declaration from the programmer's side or implicitly through the structure of the type involved.

Comparing values of different types

In JavaScript, PHP and a few other dynamically types languages, the standard equality operator evaluates to true if two values are equal, even if they have different types, making the number 4 compare equal to the text string "4", for instance. A typed equality operator is often available as well, in such languages, returning true only for values with identical or equivalent types (in PHP 5, 4 === "4" is false although 4 == "4" is true).[1][2] For languages where the number 0 may be interpreted as false, this operator may simplify things such as checking for zero (as x == 0 would be true for x being either 0 or "0" using the type agnostic equality operator).

Ordering

"Greater than" and "less than" comparison of non-numeric data is performed according to a sort convention (such as, for text strings, lexicographical order) which may be built into the programming language and/or configurable by the programmer.

When it is desired to associate a numeric value with the result of a comparison between two data items, say "a" and "b", the usual convention is to assign 1 if a < b, 0 if a = b and 1 if a > b. For example, the C function strcmp performs a three-way comparison and returns 1, 0, or 1 according to this convention, and qsort expects the comparison function to return values according to this convention. In sorting algorithms, the efficiency of comparison code is critical since it is one of the major factors contributing to sorting performance.

Comparison of programmer-defined data types (data types of which the programming language itself has no in-built understanding) may be carried out by custom-written or library functions (such as strcmp mentioned above), or, in some languages, by "overloading" a comparison operator – that is, assigning a programmer-defined meaning that depends on the data types being compared. Another alternative is using some convention such as memberwise comparison.

Logical equivalence

Though perhaps not obvious at first, like the boolean logical operators XOR, AND, OR, and NOT, relational operators can be designed to have logical equivalence, such that they can all be defined in terms of one another. The following four conditional statements all have the same logical equivalence E (either all true or all false) for any given x and y values:


E = \begin{cases}
x < y \\
y > x \\
x \ngeq y \\
y \nleq x
\end{cases}

This relies on the domain being well ordered.

Standard relational operators

The most common numerical relational operators used in programming languages are shown below.

Common relational operators
Convention equal to not equal to greater than less than greater than
or equal to
less than
or equal to
In print = > <
FORTRAN[note 1] .EQ. .NE. .GT. .LT. .GE. .LE.
ALGOL 68 [note 2] = > <
/= >= <=
eq ne gt lt ge le
APL = > <
BASIC-like[note 3] = <> > < >= <=
MUMPS = '= > < '< '>
Lua = ~= > < >= <=
Pascal-like[note 4] = <> > < >= <=
C-like[note 5] == != > < >= <=
Bourne-like shells [note 6] -eq -ne -gt -lt -ge -le
Batch file EQU NEQ GTR LSS GEQ LEQ
MATLAB[note 7] == ~= > < >= <=
eq(x,y) ne(x,y) gt(x,y) lt(x,y) ge(x,y) le(x,y)
Fortran 90[note 8] == /= > < >= <=
Mathematica[3] == != > < >= <=
Equal[x,y] Unequal[x,y] Greater[x,y] Less[x,y] GreaterEqual[x,y] LessEqual[x,y]
  1. Including FORTRAN II, III, IV, 66 and 77.
  2. ALGOL 68: "stropping" regimes are used in code on platforms with limited character sets (e.g. use >= or GE instead of ), platforms with no bold emphasis (use 'ge'), or platforms with only UPPERCASE (use .GE or 'GE').
  3. Including Visual Basic .NET, OCaml, SQL, Standard ML, and others.
  4. Including Algol, Simula, Modula-2, Delphi, OCaml, Standard ML, Eiffel, APL and others.
  5. Including C, C++, C#, Go, Java, JavaScript, Perl (numerical comparison only), PHP, Python, Ruby, and R.
  6. Including Bourne shell, Bash, Korn shell, and Windows PowerShell. The symbols < and > are usually used in a shell for redirection, so other symbols need to be used. Without the hyphen, is used in Perl for string comparison.
  7. MATLAB, although in other respects using similar syntax as C, does not use !=, as ! in MATLAB sends the following text as a command line to the operating system. The first form is also used in Smalltalk, with the exception of equality, which is =.
  8. Including FORTRAN 95, 2003, 2008 and 2015.

Other conventions are less common: Common Lisp and Macsyma/Maxima use Basic-like operators except for inequality, which is /= in Common Lisp and # in Macsyma/Maxima. Older Lisps used equal, greaterp, and lessp; and negated them using not for the remaining operators.

Syntax

Relational operators are also used in technical literature instead of words. Relational operators are usually written in infix notation, if supported by the programming language, which means that they appear between their operands (the two expressions being related). For example, an expression in Python will print the message if the x is less than y:

if x < y:
    print("x is less than y in this example")

Other programming languages, such as Lisp, use prefix notation, as follows:

(>= X Y)

Operator chaining

In mathematics, it is common practice to chain relational operators, such as in 3 < x < y < 20 (meaning 3 < x and x < y and y < 20). The syntax is clear since these relational operators in mathematics are transitive.

However, many recent programming languages would see an expression like 3 < x < y as consiting of two left (or right-) associative operators, interpreting it as something like (3 < x) < y. If we say that x=4, we then get (3 < 4) < y, and evaluation will give true < y which generally does not make sense. However, it does compile in C/C++ and some other languages, yielding surprising result (as true would be represented by the number 1 here).

It is possible to give the expression x < y < z its familiar mathematical meaning, and some programming languages such as Python and Perl 6 do that. Others, such as C# and Java, do not, partly because it would break away from the way most other infix operators work in C-like languages. The D programming language do not do that since it maintains some compatibility with C, and "Allowing C expressions but with subtly different semantics (albeit arguably in the right direction) would add more confusion than convenience".[4]

Some languages, like Common Lisp, use multiple argument predicates for this. In Lisp (<= 1 x 10) is true when x is between 1 and 10.

Confusion with assignment operators

Early FORTRAN (1956–57) was bounded by heavily restricted character sets where "=" was the only relational operator available. There were no "<" or ">" (and certainly no ≤ or ≥). This forced the designers to define symbols such as .GT., .LT., .GE., .EQ. etc. and subsequently made it tempting to use the remaining "=" character for copying, despite the obvious incoherence with mathematical usage (X=X+1 should be impossible).

International Algebraic Language and ALGOL (1958 and 1960) therefore introduced ":=" for assignment, leaving the standard "=" available for equality, a convention followed by CPL, Algol W, BCPL, Simula, Algol 68, SETL, Pascal, Smalltalk, Modula2, Ada, Standard ML, OCaml, Eiffel, Delphi, Oberon, Dylan, VHDL, and several other languages.

B and C

This uniform de facto standard among most programming languages was eventually changed, indirectly, by a minimalistic compiled language called B. It was a language with the sole intended application as a vehicle for a first port of (a then very primitive) UNIX, but it also evolved into the very influential C language.

B started off as a syntactically changed variant of the systems programming language BCPL, a simplified (and typeless) version of CPL. In what has been described as a "strip-down" process, the and and or operators of BCPL[5] were replaced with "&" and "|" (which would later become "&&" and "||", respectively.[6]). In the same process, the Algol style := of BCPL was replaced by = in B. The reason for all this being unknown.[7] As variable updates had no special syntax in B (such as let or similar) and were allowed in expressions, this non standard meaning of the equal sign meant that the traditional semantics of the equal sign now had to be associated with another symbol. Ken Thompson used the ad hoc "==" combination for this.

As a small type system was later introduced, B then became C. The popularity of this language along with its association with UNIX, led to Java, C#, and many other languages following suit, syntactically, despite this unnecessary conflict with the mathematical meaning of the equal sign.

Languages

Assignments in C have a value and since any non-zero scalar value is interpreted as true in conditional expressions,[8] the code "if (x = y)" is legal, but has a very different meaning from "if (x == y)". The former code fragment means "assign y to x, and if the new value of x is not zero, execute the following statement". The latter fragment means "if and only if x is equal to y, execute the following statement".[9]

  int x = 1;
  int y = 2;
  if (x = y) {
      /* This code will always execute if y is anything but 0*/
      printf("x is %d and y is %d\n", x, y);
  }

Though Java and C# have the same operators as C, this mistake usually causes a compile error in these languages instead, because the if-condition must be of type boolean, and there is no implicit way to convert from other types (e.g. numbers) into booleans. So unless the variable that is assigned to has type boolean (or wrapper type Boolean), there will be a compile error.

In Algol-like languages such as Pascal, Delphi and Ada (in the sense that they allow nested function definitions) as well as in Python and many functional languages, among others, assignment operators cannot appear in an expression (including if clauses), thus precluding this class of error. Some compilers, such as GCC, will provide a warning when compiling code that contains an assignment operator inside an if statement, though there are some legitimate uses of an assignment inside an if-condition. In those cases the programmer would need to explicitly wrap the assignment in an extra pair of parentheses to avoid the warning.

Similarly, some languages, such as BASIC use just the "=" symbol for both assignment and equality, as they are syntactically separate (as with Pascal, Ada, Python, etc., assignment operators cannot appear in expressions).

Some programmers get in the habit of writing comparisons against a constant in the reverse of the usual order:

  if (2 == a) {   /* Mistaken use of = versus == would be a compile-time error */
  }

If the programmer accidentally uses =, the resulting code is invalid because 2 is not a variable. The compiler will generate an error message, upon which the proper operator can be substituted. This coding style is known as left-hand comparison, or Yoda conditions.

The following table lists the different mechanisms to test for these two types of equality in various languages:

Language Physical equality Structural equality Notes
ALGOL 68 a :=: b or a is b a = b when a and b are pointers
C, C++ a == b *a == *b when a and b are pointers
C# object.ReferenceEquals(a, b) a.Equals(b) The == operator defaults to ReferenceEquals, but can be overloaded to perform Equals instead.
Common Lisp (eq a b) (equal a b)
Go a == b reflect.DeepEqual(*a, *b) when a and b are pointers
Java a == b a.equals(b)
JavaScript a === b a == b when a and b are two string objects that contain equivalent characters, the === operator will still return true.
OCaml, Smalltalk a == b a = b
Pascal a^ = b^ a = b
Perl $a == $b $$a == $$b when $a and $b are references to scalars
PHP5 $a === $b $a == $b when $a and $b are objects
Python a is b a == b
Ruby a.equal?(b) a == b
Scheme (eq? a b) (equal? a b)
Swift a === b a == b when a and b have class type
Visual Basic .NET [inequality 1] a Is b or object.ReferenceEquals(a, b) a = b or a.Equals(b) Same as C#.
Objective-C (Cocoa, GNUstep) a == b [a isEqual:b] when a and b are pointers to objects that are instances of NSObject
  1. Patent application: On May 14, 2003, US application 20,040,230,959 "IS NOT OPERATOR" was filed for the ISNOT operator by employees of Microsoft. This patent was granted on November 18, 2004.

See also

Notes and references

  1. Contributors. "Comparing Objects". PHP Manual. PHP Group. Retrieved June 29, 2014.
  2. "PHP: Comparison Operators - Manual". Retrieved July 31, 2008.
  3. Relational and Logical Operators of Mathematica
  4. Alexandrescu, Andrei. The D Programming Language. Addison Wesley. p. 58. ISBN 978-0-321-63536-5.
  5. Used not only in Algol like languages, but also in FORTRAN and BASIC
  6. As some programmers were confused by the dual meanings (bitwise operator as well as logical connective) of these new symbols (according to Dennis Ritchie). Only the bitwise meaning of & and | were kept.
  7. Although Dennis Ritchie has suggested that this may have had to do with "economy of typing" as updates of variables may be more frequent than comparisons in certain types of programs
  8. A zero scalar value is interpreted as false while any non-zero scalar value is interpreted as true; this is typically used with integer types, similar to assembly language idioms.
  9. Brian Kernighan and Dennis Ritchie (1988) [1978]. The C Programming Language (Second ed.). Prentice Hall., 19
This article is issued from Wikipedia - version of the Saturday, January 30, 2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.