Thursday 31 May 2012

Undocumented feature - title in dialog

This is an undocumented feature which I believe is widely known, but I thought I'd write a quick post about it whilst I was thinking about undocumented features.


In Uniface it is very simple to prompt the user, either to show them a message which they must confirm, or ask them to select from a number of options by clicking on the relevant button.  It is done using the askmess command...


  askmess/warning "This is a warning","Ok"


The various switches can be used to control the icon and whether or not it beeps, etc - I won't go into these here as they are well documented.  This presents the user with a popup like this...




I've redacted the software name, but what you'll see if you try this, is that the title of the dialog matches the title of the application.  In many cases you will not want this, you'll want to specify your own title.  Luckily, this can be done, like this...


  askmess/warning "This is a warning~My own title","Ok"


Note that there is a tilda ("~") character in the middle of the first parameter, which separates the dialog text from the dialog title.  This presents the user with a popup like this...




A neat little trick and very simple.  If Compuware decide to take this out then we're going to have lots of dialogs with strange prompt text though!


It's worth noting when using the askmess command that this does not work in web forms, in fact it crashes the userver last time I tried it.  If you are created a web form that reuses some existing functionality from a client form, then do watch out for this.  In fact I'd recommend creating a global procedure which calls askmess and then always call this global procedure.  This allows you to put standard checks in for web forms (using $web) and handle this accordingly.  It should also allow you to fix all of your askmess statements in one go, should this undocumented feature be removed or changed in the future.


Thanks to Paul Koldijk for reminding me about this one... http://koldijk.com/uniface/askmess_titel.htm

Summary: It is possible to change the title of a dialog created with the askmess command.

Wednesday 30 May 2012

Undocumented feature - error stack

This is something which has previously never been documented by Compuware.  In the Uniface 9.5 manuals it is used in a code example, but isn't explained at all.   We first found it in 2008, when we were on Uniface 9.2.  I've called it an "error stack", because that's the context we use it in, but really it's accessing the process stack, so you can determine where you are within the code at runtime.  And it's as simple as this...

stack = $proccontext("STACK")

I could just leave it there, but that seems a little mean, so I'll continue :)

At this point the "stack" variable is populated with a Uniface list.  Each item in this list contains another list, which contains the following items...

  • TYPE - The type of item on the stack ("TRG" for trigger, for example)
  • INSNAM - The instance name of the form running (or application shell)
  • TRIG - The trigger of the form running ("execute", for example)
  • ENTITY - The entity name of the item (if you're in an entity or field trigger)
  • FIELD - The field name of the item (if you're in a field trigger)
  • MODEL - The model name of the item (if you're in an entity or field trigger)
  • MODNAM - The name of the item (the entry or global procedure name, for example)
  • LNR - The line number within the item
  • LIN - The line of code itself

So you can loop through this list (forwards if you want it like a stack, or backwards if you want it to be more readable) to determine how you managed to end up where you currently are, down to the line number.  This is really useful for outputting when errors occur, especially in global procedures, as you can see what form was running at the time, right back to the application shell.

Thanks to Mark R for telling me about this one!

Summary: It is possible to determine exactly where you are within code at runtime, which is really useful for error messaging.

Monday 28 May 2012

Useful links

For a few weeks before I started this blog, I looked around to try and find what Uniface resources there were available, such as blogs and forums.  The list wasn't long, but I've also been researching to find out how active they are.  Here is the list I've come up with...

Official Compuware links...

Social links...

Active sites...

Semi-active sites...

Inactive sites...

I hope you find these links useful - please post more in the comments if you have them.

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.

Thursday 24 May 2012

Copying text from webpage to text file

I warn you now, I think this is the most convoluted solution I've ever come up with.  I'm convinced there must be an easier way to do this, but this was certainly an interesting way of doing it.


I had a table of information in an HTML file which I was rendering in an OcxContainer of type "Shell.Explorer" within the client application.  In fact I was first using lfiledump to create the file, and then rendering it like this...

$OCXHandle$ = $ocxhandle("OCX.DUM1") ;create handle to OcxContainer
$OCXHandle$->NAVIGATE(url,-,-,-,-)   ;navigate to file path
show                                 ;update screen

Which gave me something like this...




I now needed to export this information to a text file, easy for customers to upload to our helpdesk, or even paste straight into their response.  Thinking back, I was creating the HTML myself so it was controlled, I probably could have search and replaced the source code to reformat the results the way I wanted them.  However, I ended up doing it this way...


$OCXHandle$->EXECWB(17,-,-,-) ;select all
$OCXHandle$->EXECWB(12,-,-,-) ;copy
$OCXHandle$->EXECWB(18,-,-,-) ;clear selection
fieldsyntax ocx,"HID"         ;hide OcxContainer
fieldsyntax clipboard,""      ;show EditBox
$prompt = "clipboard.dum1"    ;fire <FieldGetsFocus> trigger


Then in the <FieldGetsFocus> trigger I had the following code...


macro "^INS_SELECT^DETAIL"    ;paste the text and fire <Detail> trigger



Then in the <Detail> trigger I had this code...

fieldsyntax ocx,""            ;showOcxContainer
fieldsyntax clipboard,"HID"   ;hide EditBox
if ( clipboard != "" )        ;process the text
  list = $replace(clipboard,1,"%%^","·;",-1)
  delitem list,1
  cont = ""
  while ( list != "" )
    getitem temp,list,1
    delitem list,1
    if ( temp != "" )
      temp = $replace(temp,1," ","·;",-1)
      getitem name,temp,1
      getitem valu,temp,2
      len = ( $length(name) / 2 )
      if ( len = len[trunc] )
        name = "%%name%%%  . . . . . . . . . . . . . . . . . "
      else
        name = "%%name%%% . . . . . . . . . . . . . . . . . "
      endif
      cont = "%%cont%%name[1:40]%%% '%%valu%%%'.%%^"    
    endif
  endwhile
  filedump/append cont,fnam   ;create the file
endif


This resulted in the following text file...

plugins/javascript/jquery.js  . . . . .  '1.6.1'.
plugins/javascript/jquery-ui.js . . . .  '1.8.13'.
javascript/sits_ajax.js . . . . . . . .  '851.1'.
javascript/dmu.js . . . . . . . . . . .  '850.1'.
javascript/translationajax.js . . . . .  '841.1'.
javascript/pod_bar.js . . . . . . . . .  '841.1'.
javascript/siw_elu.js . . . . . . . . .  '850.1'.
javascript/siw_elu_1.js . . . . . . . .  '850.1'.
javascript/siw_enl.js . . . . . . . . .  '850.1'.


As you can see, the result is exactly what I was after.  Having said that, the method is more than a little bit crazy, you don't need to tell me that!  I think it took me a whole day to come up with this solution, but I think it proves that sometimes you really have to think outside the box.  Hopefully I, nor anyone else, will ever need to use this in the future though!

For anyone using an OcxContainer of type "Shell.Explorer", I've found Microsoft's own MSDN site to be very useful, especially these links...


Summary: Sometimes solving a problem takes a spark of inspiration, sometimes it takes a lot of hard work with trial and error, and sometimes it takes plenty of both!

Tuesday 22 May 2012

Reserved operation names

This is something which is well documented by Compuware, but which I always forget, and it always drives me a little insane trying to figure out what's going on!  


Uniface has some reserved (or "predefined") operation names...

  • init - executed when a component instance is created (newinstance or activate).
  • cleanup - executed when a component instance is removed (deleteinstance or exit or completion of <accept> or <quit>).
  • attach - executed when a contained DSP is attached to a parent DSP.
  • detach - executed when a child DSP is detached from its parent.
  • exec - executed when a component is activated (activate or run).
  • accept - executed when an "accept" request is invoked on the current component (<accept>).
  • quit - executed when a "quit" request is invoked on the current component (<quit>).


EDIT:  The following operation names have been reserved for future use...
  • abort
  • complete

This means that you cannot have an operation defined with this name in the operations (<oper>) trigger, unless you are using it for this purpose specifically.  If you do then this operation will be fired when you call it, and in the above situation as well.  

I had an AJAX operation on a SVC called "init" which I simply could not figure out why it was firing twice.  In this case, it was firing once as the form was being activated (by calling the operation) and then again because I had called the operation.  This baffled me for some time!

Summary: Do not accidently use reserved operation names for your operations, or you may get some unexpected behaviour!

Monday 21 May 2012

Undocumented feature - images in dropdowns

As with any language, Uniface has some undocumented features.  Sometimes these are features that were developed but never fully supported for one reason or another, or sometimes the documentation was just forgotten along the way.  It can be risky using these features sometimes, as you never know if the functionality might be completed, changed or removed, and as it's not documented, you don't really have a leg to stand on.


Having said that, here is a nice but non-essential undocumented feature in Uniface - images in dropdowns.  The client application can be a little old-fashioned looking at times, although a lot can be done to improve this is the you have the time to fiddle with the settings.  Images in dropdowns do make it look a little more user-friendly though, I think.


It's easy to do in Uniface, but definitely "hacky".  When you set the valrep of the dropdown you might currently do it something like this...


$valrep(field) = "val1=Rep 1·;val2=Rep 2"


...which will display a dropdown list with two values in, "Rep 1" and "Rep 2".  If you want to add images, then you simply need to add the image at the beginning of each list item, but delimited with a gold-not instead of a gold-semi, like this...


$valrep(field) = "^img1·!val1=Rep 1·;^img2·!val2=Rep 2"


...and hey presto, images will appear.  These images can be in any of the following formats...

  • ^glyph - glyphs need to be compiled into UOBJ (always available and performs well).
  • @filename - images loaded from a fileserver (not always available and performs badly).
  • #fieldname - images loaded from a BLOB field in the database (always available and performs ok).
  • &url - images from the web (only works in server pages - not applicable for this).

Here is an example, just to prove it...


Summary: It is possible to display images in a dropdown in the client application, but it is undocumented and therefore unsupported.

99 bottles of beer

I saw this today and thought it was rather cool, so I thought I'd share it here...

http://99-bottles-of-beer.net/language-uniface-932.html 


As Theo Neeskens has pointed out, there is an alternative version here as well...


http://99-bottles-of-beer.net/language-uniface-9.3-2287.html

Friday 18 May 2012

Performance of list processing

As mentioned in my previous posts, performance is a key factor.  The lovely Uniface list is effectively string a delimited string, as you know, which means we're back to string manipulation, which we know is costly.  Unfortunately there are no arrays or similar available, so we make do.


As far as I can see, there are four ways to process a list....

  1. getitem with a counter

    count = 0
    $status = 1
    while ( $status > 0 )
      count = count+1
      getitem temp,list,count
    endwhile

  2. getitem/id with a counter

    count = 0
    $status = 1
    while ( $status > 0 )
      count = count+1
      getitem/id temp,list,count
    endwhile

  3. getitem with a destructive list

    count = 0
    while ( list != "" )
      count = count+1
      getitem temp,list,1 
      delitem list,1
    endwhile

  4. getitem with a reverse destructive list 

    count = 0
    while ( list != "" )
      count = count+1
      getitem temp,list,-1
      delitem list,-1
    endwhile
These loops all use local variables and the list is pre-built with 20,000 items like...

"1= ABCDEFGHIJKLMNOPQRSTUVWXYZ 01234567890 abcdefghijklmnopqrstuvwxyz 01234567890"

  1. 00:06.58, 00:06.54, 00:06.69 (just under 7 seconds)
  2. 00:06.85, 00:06.89, 00:06.84 (just under 7 seconds)
  3. 01:02.16, 01:01.87, 01:01.91 (just over 1 minute)
  4. 00:06.61, 00:06.63, 00:06.72 (just under 7 seconds)
There is obviously a clear loser here, never do a destructive list!  I think the main reason for this is that the getitem must have to scan through the string, but the delitem is then causing the whole list to be rebuilt - very costly!  

Now I shall try again but with a pre-built list of 200,000 items, the same as those before...

  1. 01:06.55, 01:06.38, 01:05.99 (just over 1 minute)
  2. 01:19.22, 01:19.88, 01:19.36 (around 1.3 minutes)
  3. -
  4. 01:05.38, 01:06.59, 01:05.45 (just over 1 minute)
This shows that the next worst is the getitem/id, whereas the remaining two are pretty close.  The reason I think the reverse destructive list works fairly well is that the list is being shortened each time, which means there is a smaller string to scan.  However, finding the first item must be quicker than finding the last, implying that the scan always happens from the first character.  What this probably means, although the numbers are too close to really prove this, is that the reverse destructive starts to perform better for really really long lists, but the plain getitem performs just as well for shorter lists.

Summary: When processing a list it is best to use either a getitem with a counter or a reverse destructive list, as these both perform well for normal sized lists.

Wednesday 16 May 2012

Performance of string manipulation - part two

In part one I looked at the different ways of storing a string during string manipulation, and found that using a variable was by far quicker than using a field.  In this next part, I'm going to look at the different ways of building up the string.  I can think of only two different ways...

  • Concatenation (using $concat)
  • Indirection (eg. "%%string1%%string2%%%")

So I put these to the test with the following four strings...

"ABCDEFGHIJKLMNOPQRSTUVWXYZ "
"01234567890 "
"abcdefghijklmnopqrstuvwxyz "
"01234567890 "

...holding the value in a local variable and iterating 20,000,000 times...

  • Concatenation = 01:03.08, 01:03.71, 01:03.t64 (just over 1 minute)
  • Indirection = 01:02.01, 01:01.74, 01:01.98 (just over 1 minute)

The difference is almost negligible, as I had to go to so many iterations before it could be detected.  Indirection does pip concatenation to the post though, by a whisker.

I then decided to try building up a larger string, by starting with the first string and adding the other three, then taking that string and adding the other three again, and so on.  This time I also used a local variable but iterating only 20,000 times...

  • Concatenation = 00:56.41, 00:56.02, 00:56.37 (just under 1 minute)
  • Indirection = 00:55.61, 00:56.96, 00:56.92 (just under 1 minute)

Again the difference is pretty negligible, proving that in this case, size really doesn't matter.

Summary: Using concatenation or indirection doesn't really make a difference.

Performance of string manipulation - part one

One thing that every developer fights with (or should!!) is performance.  It's ok writing an application that works well for one developer sat messing about on a development server that only he is using, but it is very different when it's thousands of users all hitting the same server, under realistic but heavy load.


One particularly costly task is string manipulation.  Building up a string can use a relatively large chunk of memory and take a surprising amount of processor power.  So I decided to perform some performance tests to see how this could be improved.


The first test I did was comparing the use of a local variable against a non-database field.  I did this test by taking the following string...


" ABCDEFGHIJKLMNOPQRSTUVWXYZ 01234567890 abcdefghijklmnopqrstuvwxyz 01234567890"


...and then using putitem/id with a counter to add this 20,000 times, with the following results...

  • Non-database field = 02:42.14, 02:44.64, 02:43.44 (almost 3 minutes).
  • Local variable = 00:00.22, 00:00.23, 00:00.22 (less than 1 second).
  • Component variable = 00:00.22, 00:00.22, 00:00.22 (less than 1 second).
  • Global variable = 00:00.22, 00:00.22, 00:00.23 (less than 1 second.


As you can see, when manipulating a string you should never use a field to hold the string.  Having said that, it doesn't seem to make any difference which type of variable you use.  I continued testing the different types of variables with 200,000 and 2,000,000 iterations, without seeing the times deviate from each other.

Summary: Use a variable (any kind of variable) but not a field.

Tuesday 15 May 2012

Hello and welcome

I have been a Uniface developer for the past 7 years, starting with Uniface 8.x and now currently working with Uniface 9.4.  


One thing that can be difficult about working with Uniface is that Google is often not very helpful, you get stuck and there really isn't anywhere to turn.  I have decided it's about time this changed, and this blog is my own small way of doing this.  


Over the next few months I plan to think back over my 7 years so far, and try to write a few articles detailing the tricks and tips that I have come up with, or stolen from colleagues.


I hope someone out there, someday, finds this blog useful.  You never know, it might be me!