Wednesday 30 April 2014

Casting in an if statement (equality versus identity)

Uniface is a tightly typed language - this means that when we declare variables, we also declare the datatype, such as string or numeric, like this...

variables
  string s
  numeric n
endvariables

This is very different from a loosely typed language, such as javascript, which does not require variables to even be declared, let alone declare them with a datatype.

As mentioned in previous posts about operators (part one and part two), Uniface uses a single equals (=) as the assignment operator and either single (=) or double (==) equals as the relational operator.  So for equality, you can use either = or == interchangeably.  

Both of these will automatically cast values/variables in order to check their equality.  For example...

s = "1"
n = 1
if ( s = n )
  putmess "True!"
endif
if ( s == n )
  putmess "Also true!"
endif

In both cases, Uniface is saying that the string "1" and the numeric 1 are equal to each other, because it is casting the variables to the same type and then saying that they equal each other.  This is fine, and can be very useful.

Originally I assumed that Uniface would be casting both of the variables to string, but in this case I believe it is actually casting them both to numeric, because this example also works...

s = "001"
n = 1
if ( s = n )
  putmess "True!"
endif

There is a specific section in the manuals about this...

Numeric Data, Empty Strings, and Relational Operators
In general, when two operands are compared using a relational operator and one of those operands is numeric (that is, data type Numeric or Float), the other operand is usually converted into numeric data (for the purpose of the comparison only). There are, however, special considerations when a numeric operand is an empty string ("") or contains a space.

In javascript (for example) there is another operator, a triple equals (===) which can be used to check identity.  In this case, no casting takes place, so the if statement would return false, because the types do not match.  Unfortunately, Uniface does not support this operator, you get a compile error when you try...


Because of this, if you want to check identity in Uniface, you need to be very explicit about making the types the same.  Here are a few examples...

if ( s = $string(n) )
  ;string = string
endif
if ( s = "%%n%%%" )
  ;string = string
endif
if
( $number(s) = n )
  ;numeric = numeric
endif
if ( s*1 = n )
  ;numeric = numeric
endif

Summary: Uniface checks equality but not identity, so you need to be careful about the types of your variables to ensure that the condition behaves the way you expect.