Records, comparing

Record variables are references to records, not the records themselves. This means that there are two different ways in which you might want to compare two record variables:

  1. You might want to compare their identity: do the two variables refer to the same record?
  2. You might want to compare their value: do the two records have the same value?

To discover if two different record variables reference the same record, you use the reference equality operator, ==:

  declare type point
   field integer x
   field integer y
  
  process
     local point alpha
     local point omega
  
     set omega to alpha
  
     do when omega == alpha
        output "Alpha and omega refer to the same record.%n"
     else
        output "Alpha and omega refer to different records.%n"
     done

To discover if two records have the same values you can do one of the following:

  1. Compare the field values of the two record individually
  2. Write a function to compare the values of the records
  3. Overload the OmniMark comparison operators to compare the values of the records

The following example compares two records by comparing the field values directly:

     set alpha:x to 2
     set alpha:y to 4
  
     set omega:x to 3
     set omega:y to 9
  
     do when omega:x = alpha:x & omega:y = alpha:y
        output "The two records describe the same point.%n"
     else
        output "The two records describe different points.%n"
     done

The next example defines a function to compare points:

  define switch function same-point
   (value point a,
    value point b
   ) as
     return a:x = b:x & a:y = b:y
  
  process
     ...
     do when same-point (alpha, omega)
        output "The two records describe the same point.%n"
     else
        output "The two records describe different points.%n"
     done

The function name "same-point" is somewhat ugly. What we really want is to use the "=" sign to test whether two points are the same. We can do this by overloading the "=" operator:

  define overloaded switch infix-function
   value point a = value point b
   as
     return a:x = b:x & a:y = b:y
  
  process
     ...
     do when alpha = omega
        output "The two records describe the same point.%n"
     else
        output "The two records describe different points.%n"
     done

Note that there are several possible meaning that could be associated with the idea that two records are "equal" to each other. The example above uses the most obvious one, that all the fields contain the same values. However, other interpretations of the idea of equality are possible. For example, consider a record type for a place, which contains the name of the place and its latitude and longitude:

  import "omfloat.xmd" unprefixed
  
  declare record place
   field float latitude
   field float longitude
   field stream name

Suppose we have two place records:

  process
     local place ottawa
     local place capital
  
     set ottawa:latitude to 45.417
     set ottawa:longitude to -75.700
     set ottawa:name to "Ottawa, Ontario"
  
     set capital:latitude to 45.417
     set capital:longitude to -75.700
     set capital:name to "the Capital of Canada"

What is the correct way to compare these two records? A straight field by field comparison will say that they are not equal, since the name fields do not match. However, the latitude and longitude values are the same, and the two different name values are actually two different names for the same place.

In comparing two place records, therefore, we may want to compare the latitude and longitude values and ignore differences in the name field. This may be a very useful function, because it will enable us to discover if two place names are actually the name of the same place:

  define overloaded switch infix-function
   value place a
   =
   value place b
   as
     return a:latitude = b:latitude & a:longitude = b:longitude
  
  process
     ...
     output ottawa:name
         || (ottawa = capital -> " is " | " is not ")
         || capital:name
         || "%n"