Showing posts with label operator. Show all posts
Showing posts with label operator. Show all posts

Thursday, 8 May 2014

Boolean values in an if statement

Last week I wrote a post about casting in if statements, focusing on the difference between equality and identity.  Well that post started out in my mind as being about boolean values, but then I found I needed to cover that ground first.

Boolean is a rather interesting datatype in Uniface.  The description in the manuals goes like this....

The Boolean data type is interpreted as either TRUE or FALSE. An empty value, and the values 0, F, f, N, and n are interpreted as FALSE. All other values are interpreted as TRUE. 

The Uniface default packing code for boolean stores the value as "T" or "F", but a number of different packing codes can be used...


  • B - Optimum DBMS Boolean default
  • B1 - ASCII Boolean (0 or 1)
  • B2 - ASCII Boolean (F or T) *Uniface default
  • B3 - ASCII Boolean (N or Y)
  • B4 - Binary Boolean (0 or 1)
  • B5 - Binary Boolean (0 or -1)


This means that it is always safest to reference a boolean in an if statement without a relational operator, like this...

  variables
    boolean b
  endvariables

  if ( b )
    putmess "b is True"
  endif
  if ( !b )
    putmess "b is False"

  endif

As empty values are interpreted as false, this example would output "b is False".

This is fine, as long as you know that you've got a boolean datatype.  However, I've seen developers get into trouble when they use this type of if statement (without a relational operator) but with other datatypes.

For example, to check a blank string in javascript, you could easily do something like this...

  var s = "";
  if(!s) {
    alert "s is blank";

  }

If you translate this directly into Uniface, then you get something like this...

  variables
    string s
  endvariables

  s = ""
  if ( !s )
    putmess "s is blank"

  endif

And this works, no problem here.  Empty string is interpreted as false and you get the same result.

Consider this though; what if s is set to "0"?  

In javascript, we would not get the alert - this is because the string is not blank, so quite right!  However, in Uniface we do get the message saying that s is blank, even though it's not.  This is because "0" is interpreted as false.

Summary: In an if statement, if you've got a boolean datatype then don't use a relational operator, but if you've got any other datatype then do use one.

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.

Monday, 17 September 2012

Order of operations - part two

It's been pointed out to me that I overlooked a whole page in the Uniface manuals which details the order of precedence for operators - how did I miss that?  Luckily it agrees with my findings, and adds in a few of the Uniface specific functionality (such as indirection)...

Type
Operator
Description
Precedence
Indirection
@
Field Indirection
1
Dereference
->Identifier
{ }
Struct Dereference and Operation Activation
Struct Index
2
Extraction
[ ]
Extraction
3
Indirect dereference
->"SubstitutionString"
Dereference with string substiution
4
Arithmetic Operators
*
/
%
Multiplication
Division
Modulus
5
+
-
Addition
Subtraction
6
Relational Operators
<
<=
!=
=
==
>=
>
Less than
Less than or equal to
Not equal to
Equal to
Equal to
Greater than or equal to
Greater than
7
Logical Operators
!
Logical NOT
8
&
Logical AND
9
|
Logical OR
10


Thanks to Dave R for pointing this out to me.

Summary: Check the manuals before spending hours writing a blog post :)

Order of operations

I was recently asked about the order of operations (or "operator precedence") in Uniface, and I couldn't really answer the question with an certainty, so I thought I'd investigate and prove or disprove my assumptions.  It relates primarily to mathematical expressions, but also to logical conditions, and defines in what order the various components are processed. 

Take for example the following mathematical expression...

x = 10 * 5 + 1

Operator precedence states that multiplication is done before addition, therefore x is 51, not 60.

Wikipedia states that the following order of operations should be true for most programming languages, so my question is, does Uniface comply?


1()   []   ->   .   ::Grouping, scope, array/member access
2 !   ~   -   +   *   &   sizeof   type cast ++x   --x  (most) unary operations, sizeof and type casts
3*   /   %Multiplication, division, modulo
4+   -Addition and subtraction
5<<   >>Bitwise shift left and right
6<   <=   >   >=Comparisons: less-than, ...
7==   !=Comparisons: equal and not equal
8&Bitwise AND
9^Bitwise exclusive OR
10|Bitwise inclusive (normal) OR
11&&Logical AND
12||Logical OR
13 ?:Conditional expression (ternary operator)
14=   +=   -=   *=   /=   %=   &=   |=   ^=   <<=   >>=Assignment operators
15,Comma operator

I think it's going to be easiest to prove these in reverse order, so let's take them one by one...

15 - Comma operator

Uniface doesn't have comma operators, you cannot put multiple lines of code on the same line with any separator, as far as I'm aware.

14 - Assignment operators

I wrote a previous post on assignment operators, the arithmetic ones (+= -= *= /= %=) all work in Uniface, but the logical ones (&= |= ^= <<= >>=) do not.  The simplest assignment operator (=) is also used as the comparison operator, there is no differentiation in Uniface.  This means that the comparison operator takes precedence, which be proved with a simple if statement...


x = 0
if ( x = 1 )
  ;if assignment took precedence
endif
askmess "x=%%x%%%" ;shows "x=0"



13 - Conditional expression

This is not valid syntax in Uniface either, you have to do it the long way.  I never really liked this syntax in javascript though anyway, less readable in my opinion.


11/12 - Logical and/or

The logical operators in Uniface are singular (& and |), although the double versions (&& and ||) also work the same way, as I discovered in an earlier post.  I tried to combine these with the assignment operators in order to determine the precedence, but all I got was compile errors.  It seems that assignment operators cannot be used inline.


8/9/10 - Bitwise and/xor/or

Uniface does not have bitwise operators, as previously discussed.  The singular "and" and "or" operations are the logical operators.


6/7 - Comparison

As mentioned above, the equals comparison operation (=) is the same as the simplest assignment operator, and the comparison takes precedence.  It also takes precedence over the logical operators, as this if statement proves...


x = 0
if ( x = 1 | 1)
  x = 1 ;if ((x = 1) | 1)
else
  x = 0 ;if (x = (1 | 1))
endif
askmess "x=%%x%%%" ;shows "x=1"



5 - Bitwise shift

Uniface still doesn't have bitwise operators :)


4 - Addition/subtraction

It's simple enough to show that the addition (+) and subtraction (-) operators take precedence over the comparison operator (=), using another if statement...


x = 0
if ( x = 0 + 1 )
  x = 1 ;if (x = (0 + 1))
else
  x = 0 ;if ((x = 0) + 1)
endif
askmess "x=%%x%%%" ;shows "x=0"



3 - Multiplication/division/modulo

It's also simple to show that the multiplication (*), division (/) and modulo (%) operators take precedence over the addition and subtraction operators...


x = 6 * 1 - 1
;(6 * 1) - 1 = 5
;6 * (1 - 1) = 0
askmess "x=%%x%%%" ;shows "x=5"



2 - Unary/type cast

Uniface doesn't support all the unary operators, in fact I'm not sure what all of them do.  The not (!) operand is easy enough to test though...


x = ! 0 + 1
;(! 0) + 1 = 2
;! (0 + 1) = 0
askmess "x=%%x%%%" ;shows "x=0" but would have expected "x=2"



Surprisingly this one comes up with the opposite result than was expecting, indicating that addition (+) actually takes precedence over not (!).  We know that Uniface is good at type casting though, and will always try to cast a string as a numeric when doing arithmetic operations...


x = "1" * 2
askmess "x=%%x%%%" ;shows "x=2"



We can also show the negative unary operator (-) takes precedence over the subtraction operator (-), despite these being the same, like this...


x = -1 - 2
;(-1) - 2 = -3
;-(1 - 2) = 1
askmess "x=%%x%%%" ;shows "x=-3"



1 - Grouping

Uniface doesn't have arrays or members, and scope is handled explicitly with end statements.  It does however use brackets for grouping, as we've seen through these examples, they can be used to change the order of precedence, as they are always done first.


Summary: It seems that Uniface is a relatively simple in the sense that it doesn't do complicated inline nesting, nor any bitwise operations.  With the exception of the not operator (!), it seems to follow the standard order of operations though.  Personally I prefer to use lots of brackets in order to make the order of precedence more obvious and easier to read, without having to remember these rules.

Monday, 2 July 2012

Assignment operators

This is sort of an undocumented feature, certainly not one that I knew about until today, but as I discovered it in the documentation, I couldn't really label it as undocumented.  It's used in an example in the for loop section (which I'm investigating for a future blog post!) but not in the operators section, where I would have expected it.


In javascript there are three ways of incrementing a numeric value...

  • c = c + 1
  • c += 1
  • c++

The first is probably the most obvious at first glance, but the other two make sense once you know what they mean.  Both + and ++ are referred to as "arithmetic operators" whereas += is referred to as an "assignment operator".

Whilst I've known this in javascript for many years, I had no idea that you could also use the following assignment operators in Uniface as well...

  • Addition: c += 1 (which is the same as c = c + 1)
  • Subtraction: c -= 1 (which is the same as c = c - 1)
  • Multiplication: c *= 1 (which is the same as c = c * 1)
  • Division: c /= 1 (which is the same as c = c / 1)
  • Modulus: c %= 1 (which is the same as c = c % 1)

Interestingly in javascript if you attempt to do += with string values then it concatenates the two strings, but Uniface will always treat this as a numeric operator and attempt to cast the strings as numerics.

I've checked the performance of these shorthand operators with their longhand equivalents and they seem to perform identically, which possibly indicates that the compiler interprets them in the same way.  This means it is really a personal choice over which style the developer prefers.

It's worth noting that the arithmetic operators ++ and -- do not work - these cause compile errors.

Summary: There are shorthand numeric assignment operators available in Uniface, if you prefer this style of syntax.

Friday, 25 May 2012

Are "if" statements breaking or non-breaking?

An interesting feature in Javascript is the ability to improve the performance of your "if" statements using a technique known as breaking, or sometimes shortcutting.  This is where you have multiple parts to the condition, which are specifically ordered.  You can use the "&" and "|" (bitwise) operators which do not shortcut, or "&&" and "||" (logical) operators which do shortcut.  For example...


    a = 1;
    b = 2;
    c = 3;
    d = 4;
    if ( a==b & c==d ) alert("true"); //bitwise
    if ( a==b && c==d ) alert("true"); //logical


The first "if" statement is working out that a does not equal b and thinking of this as 0, then working out that c does not equal d and thinking of this as 0, then working out that 0 and 0 is 0, therefore false and no alert appears.  


The second "if" statement is working out that a does not equal b and thinking of this as false, then stopping.  I knows that if the first part of the condition is false then anything after that is always going to result in false, so it breaks (or "shortcuts") and no alert appears.


I won't go into the difference between bitwise and logical, because this is a Uniface blog and not a Javascript one.  Suffice to say, in this situation they almost always behave the same, because 0 equates to false and 1 equates to true.  The important thing to note is the difference in whether they shortcut or not. 


A question I've wanted to know for a long time but never stopped to work out... Does Uniface shortcut when processing "if" statements?  Time to find out!


First I tested to see if there was a difference between "&" and "&&" in Uniface.  I'd noticed that both worked the way I expected logically, but never determined the difference.  The way I did this was with the following two blocks of code...

  • &
      count = 0
      total = 10000
      while ( count < total )
        count = count + 1
        if ( 1 = 0 & $itemnr(-1,list_field.dummy) = "" )    
          ;testing the condition itself
        endif
      endwhile

  • &&
      count = 0
      total = 10000
      while ( count < total )
        count = count + 1
        if ( 1 = 0 && $itemnr(-1,list_field.dummy) = "" )    
          ;testing the condition itself
        endif
      endwhile

I then populated the non-database "list.dummy" field with a list of 20,000 items.  As you may have read in one of my earlier posts, accessing the last item in a large string held in a non-database field is a relatively costly thing to do, certainly compared with referencing a numeric value.  This means that I expect the first part of the condition to process much quicker than the second part of the condition.

I won't give you the timings, it was quite boring, they both behaved exactly the same.  There was no difference between the timings, even when I upped the number of iterations from 10,000 to 1,000,000.  

I then moved on to trying to determine whether or not the second part of the condition was being processed or not, by also testing the following blocks of code...

  • False
      count = 0
      total = 10000
      while ( count < total )
        count = count + 1
        if ( 1 = 0 & $itemnr(-1,list.dummy) = "" )    
          ;testing the condition itself
        endif
      endwhile

  • True
      count = 0
      total = 10000
      while ( count < total )
        count = count + 1
        if ( 1 = 1 & $itemnr(-1,list.dummy) = "" )    
          ;testing the condition itself
        endif
      endwhile

Now these results I did find interesting...

  • False = 01:07.31, 01:08.92, 01:07.30 (just over a minute)
  • True = 01:49.12, 01:50.31, 01:49.52 (almost 2 minutes)

This means that Uniface is definitely shortcutting, which is great!  This means that performance can be gained by ordering the parts of the condition carefully.  Of course you could argue that you could split this up to achieve the same affect, like this...

      if ( 1 = 0 )    
        if ( $itemnr(-1,list.dummy) = "" ) 
          ;testing the condition itself
        endif    
      endif

I wouldn't have a leg to stand on, you'd be right.  However, what about "or" instead of "and"?  In this case, if the first part is true then there's no need to process the second part, because you already know that the final result will be true also.  Again, you could split it up like this...

      if ( 1 = 0 )    
        ;testing the condition itself
      elseif ( $itemnr(-1,list.dummy) = "" ) 
        ;testing the condition itself
      endif

...but this would mean duplicating whatever code was inside the "if" statement, and it's not nearly as readable as a single "if" statement.  So I tried again, but this time with "|" instead of "&"...

  • False = 01:49.51, 01:49.08, 01:49.84 (almost 2 minutes)
  • True = 01:07.02, 01:08.22, 01:07.19 (just over a minute)

Again, this means that Uniface is definitely shortcutting, which is great!  I expected the results to be opposite (true to be faster than false) because the logic of "and" and "or" are opposite (well, sort of, technically "and" and "exclusive-or" are, but we won't go into that!). 

Of course, if you had three or four or five parts, this could mean even greater performance gains could be achieved by thinking carefully about which part you put first.  Any function which you might use in a condition, like $length or $scan should always be used in later parts if possible.

Summary: There is no difference between "&" and "&&" or "|" and "||" as far as I can tell, but Uniface does shortcut when there are multiple parts to the condition in an "if" statement, therefore you should think careful about the order of the parts.