Wednesday 18 June 2014

Converting a form to a service and vice versa

I discovered something new and rather interesting yesterday.  And by new, I mean new to me, apparently it's been there "forever"!

I was trying to do some testing for my earlier post on handles, and wanted to run an operation on a mapped server.  However, the operation was on a form, and not a service, which it needs to be to run mapped.  I was just about to create a new service and copy the operation code when I mentioned this off hand in conversation with a colleague of mine, and he mentioned that it was actually very easy to convert a form into a service.

I thought he was about to show me some really clever, well hidden little trick.  Alas, it's right there in the "File" menu, and always has been...



So all you have to do is click that and compile, job done!  You learn something new every day.

Summary: It's really easy to convert a form into a service, or many other things, and vice versa, which you might need to do if you want to run an operation on a mapped server.

Thanks to Mark R for pointing this out for me.

Tuesday 17 June 2014

What are handles and should I be using them?

The Uniface manuals describes a handle as...
A handle is a reference to an object, such as a component instance, entity, occurrence, or field. Handles can be used to call operations on the referenced object, or to pass these objects as variables and parameters.

If you're used to pointers, you may at first glance think that these are the same, but they're not.  A pointer contains the address of an item in memory and is therefore fixed, whereas a handle is an abstract reference, which means the address can be changed without breaking the reference.  This makes them very useful.

In Uniface you can have "public" or "partner" handles, which allow you to define which types of operations can access them.  They are also datatypes available for local, component and global variables, depending on the scope required.  I'm not going to discuss either of these points in detail, but I think it's handy to know.

As the description in the manual states, you can create a handle that references most Uniface objects, and there are different methods for creating these handles:  Component instances ($instancehandle), entity collections ($colhandle), entity occurrences ($occhandle), fields ($fieldhandle) and also OCX controls ($ocxhandle).  

I'm going to focus on component instances.  More specifically, I'm going to focus on creating new component instances, using newinstance and handles.  

As you might expect, creating a new instance of a form has a little lead time.  Using a handle doesn't stop this lead time, but what it does do, is mean that it only has to happen once.  This means that using a handle for a single form activation is not going to give you any advantage (unless you just love handles!) but when calling operations on the same form multiple times, handles could give you a performance improvement.

This is something like how you could activate a form...

  activate "TEST_FORM".test_oper("Test")


In fact this does an implicit newinstance as well (if it can't already find an instance with the same name as the form) and so explicitly your code could look like this...


  newinstance "TEST_FORM","TEST_FORM"
  activate "TEST_FORM".test_oper("Test")


If you were to replace this with a handle then you may use something like this...


  newinstance "TEST_FORM",theHandle
  theHandle->test_oper("Test")


Notice that in this case we have used a handle instead of an instance name in the newinstance call, and then we can use this handle in place of the activate command.  The -> is referred to by Uniface as the "dereference" operator, and is processed with a precedence of 2 (with only field indirection being higher).

So let's try these two different ways of activating an operation (in this case a very simple operation that simply returns out immediately).  The newinstance command is done before the loop, and the activate (or equivalent handle call) is done inside the loop, 200,000 times...


  • Using activate: 2.56, 2.61, 2.60 (about 2.6 seconds)
  • Using a handle: 2.39, 2.35, 2.39 (about 2.4 seconds)


As you can see, using a handle is marginally quicker, although you'd have to be making a lot of calls before you really noticed the difference.  

I thought that this would be even more useful when the handle references a component instance that is running on another server, such as when a form is mapped to run elsewhere, as the I thought the initial creation of the new instance would take longer here.  So I ran the same operation 20,000 times (after mapping the form)...


  • Using activate: 13.39, 14.35, 12.99 (about 13.5 seconds)
  • Using a handle: 13.56, 13.12, 12.91 (about 13.0 seconds)

Not much difference here either.  Having said that, maybe on a chatty network the difference would be greater.

Please note:  You must return out of the operation that you call, if you exit out then this will destroy the handle and future calls to the operation will fail with a $status of -1.  To clean up a handle you can either set it to 0 or "" (empty string). 


Summary: Handles are abstract references to pretty much any Uniface object.  They can be useful, especially if you want to call the same object multiple times, but they don't seem to have the performance benefits that I was expecting, not when it comes to component instances anyway.

Saturday 7 June 2014

Sendmessage versus postmessage

If you wanted to send a message from one form to another, you could simply use sendmessage.  This was deprecated in favour of using activate, a command which has become pretty much a catch-all for all sorts of earlier commands, including run, perform, and spawn.  These all still work in Uniface 9.6, but as they were deprecated in Uniface 9.1, it's well worth trying to write these out of your code.

One example of this might be if you have retrieved multiple records in one form, and also have a second form open with related records in it; when you scroll through the occurrences in the first form you might want to post the primary key details through to the second form, so that only the records related to the current occurrence in the first form are displayed.

In order to do this, the first form would need to have code in the "Occurrence Gets Focus" <OGF> trigger, something like this...


  sendmessage "SECOND_FORM","PKEY","FIELD1.ENT=%%FIELD1.ENT%%%"

As you can see, because sendmessage is now deprecated, it is not highlighted as a reserved word.  You also get a compile warning like this...

  warning: 1000 - Deprecated statement 'sendmessage' used

You then need to have some code to receive this message in your second form, which needs to be in the "Asynchronous Interrupt" <ASYS> trigger, something like this...


  the_result = $result ;will be "message"
  message_id = $msgid ;will be "PKEY"
  message_data = $msgdata ;will be "FIELD1.ENT=xxx"

When using sendmessage or postmessage, $result will always be set to "message".  The second value that you define will become the $msgid and then third value will become the $msgdata.  

Please note:  If the <ASYS> trigger in the called component is blank then the application <ASYS> trigger will be called, as defined in the start-up shell.

So what's the difference between sendmessage and postmessage?  Can you simply go through and replace every sendmessage with a postmessage, or should you be using activate instead?

Well the difference is that sendmessage is synchronous and postmessage is asynchronous, which means that potentially there's a delay before the message will be received and processed with a postmessage.  Using an activate would be synchronous but you'd need to rewrite your code, probably moving the code in the <ASYS> trigger into an operation and then calling that from the <OGF> trigger.

Is this potential delay likely to cause a problem though?  Well for starters, can we see it in practice?  The answer to this is "yes", by putting sending code like this somewhere in a form (I went with the <EXEC> trigger)...


  putmess "Before sendmessage"
  sendmessage "TEST_PERF","MESSAGE","SENDMESSAGE"
  putmess "After sendmessage"

  putmess "Before postmessage"
  postmessage "TEST_PERF","MESSAGE","POSTMESSAGE"
  putmess "After postmessage"

And then putting the receiving code in the <ASYS> trigger, like this...


  putmess "In ASYS: ID=%%$msgid%%%, DATA=%%$msgdata%%%"

We can then run the form and view the message buffer...

  Before sendmessage
  In ASYS: ID=MESSAGE, DATA=SENDMESSAGE
  After sendmessage
  Before postmessage
  After postmessage
  In ASYS: ID=MESSAGE, DATA=POSTMESSAGE

As you can see, the sendmessage happens between the "before" and "after" (synchronously), whereas the postmessage happens at the very end (asynchronously).  This means that you have to be very careful about changing any sendmessage statements into postmessage statements - the code order will change, and you need to be aware of this and check this will not cause a problem.

As far as my testing has gone, the messages are always received and processed in the order that they were posted, as you may expect from a message queue.  Having said that, I've not found anything in the manuals that states explicitly that this order is enforced, so writing code that relies on the messages being processed in a particular order might not be wise.


Summary: The deprecated sendmessage command was sychronous whereas the postmessage command is asychronous, so you must be careful if you replace one with the other.  However, this is likely to be more straight forward than replacing with the activate command, as the manual suggests.

Friday 6 June 2014

The new Uniface


I read an interesting article today, so I thought I'd post a link...


The new Uniface

David NorfolkBy: David Norfolk, Practice Leader - Development, Bloor Research
Published: 30th May 2014
Copyright Bloor Research © 2014
Logo for Bloor Research
Link to article: http://www.it-director.com/blogs/The_Norfolk_Punt/2014/5/the-new-uniface.html

Also mentioned in this article is the new Uniface branding, which if you follow Adrian Gosbell's twitter account you will see looks like this...




Summary: Life after Compuware is looking good so far for Uniface.



Monday 2 June 2014

Do comments affect compile time or form size?

A while ago, someone asked on UnifaceInfo.com whether it takes longer to compile a form that has a lot of comments in it than one that doesn't, and Theo Neesksens suggested that maybe I should take a look.  A colleague of mine emailed me the post and I filed it away to respond to when I had a moment.  Well, what can I say, I've been busy!  (And I forgot about it!)

There's an easy way to compile a form programmatically (so that I can wrap timing code around it) and that's using $ude, something like this...

  $result = $ude("compile","form","TEST_FORM")

First I selected an existing form with minimal comments, and compiled it a number of times, noting the size.  Then I added lots of comments and noted those times and sizes as well...


  • Original form (93526 bytes): 41.38, 44.84, 42.03 (average of 42.75 secs)
  • 1000 comment lines (93526 bytes): 44.92, 45.88, 46.61 (average of 45.80 secs)
  • 2000 comment lines (93526 bytes): 46.40, 44.34, 47.76 (average of 46.17 secs)
  • 3000 comment lines (93526 bytes): 47.28, 48.85, 49.31 (average of 48.48 secs)
  • 4000 comment lines (93526 bytes): 49.30, 49.25, 49.19 (average of 49.25 secs)
  • 5000 comment lines (93526 bytes): 49.39, 50.07, 49.96 (average of 49.81 secs)
  • 10000 comment lines (93526 bytes): 54.64, 53.98, 55.16 (average of 54.59 secs)

So as you can see, the size of the compiled form is always the same, so the comments are stripped out, and this process of striping out the comments does take some time.  

I'm not aware of a way to get the individual timings out for each phase, but it seems to me that the comments are removed during the first phase, as this seems to take slightly longer as more comments are added.

On a personal note, I think adding extra comments into your code is a good thing, if it makes it more readable, but better yet, have readable code that doesn't need many comments!  

Summary: Unless you put thousands of lines of comments in, it's not going to have much of an impact on your compile time, but it's certainly not going to have an impact on your compiled file size.

Thanks to Theo Neesksens and Mark R for pointing me in the direction of this one.

Sunday 1 June 2014

Reducing your memory footprint

One common use for the while loop is to loop through a set of retrieved records.  This can also be done with a for loop, as I discussed in a previous post about types of for loops.  The example I gave was something like this...

  setocc "ent",1
  while $status > 0 )
    ;do something
    setocc "ent",$curocc(ent)+1
  endwhile 

This is nice and simple, and also pretty efficient.  There is one big downfall with it though, and that's memory.  In order to improve performance when you do a retrieve, Uniface works out what the "hitlist" is, but doesn't actually pull all of the retrieved records into memory.  As you loop through, more and more of the hitlist is completed, and the records are pulled into memory.  

To demonstrate this, I retrieved 600 records and then looped through them, using Process Manager to track the memory of the "uniface.exe" program...

  • Initial value: 14.56Mb
  • 600 records retrieved: 14.64Mb (+0.08Mb)
  • Looped to occurrence 100: 14.91Mb (+0.27Mb)
  • Looped to occurrence 200: 15.30Mb (+0.39Mb)
  • Looped to occurrence 300: 15.70Mb (+0.40Mb)
  • Looped to occurrence 400: 16.10Mb (+0.40Mb)
  • Looped to occurrence 500: 16.54Mb (+0.44Mb)
  • Looped to occurrence 600: 16.93Mb (+0.39Mb)

As you can see, retrieving the hitlist is just the first step, and a small one at that, the data is not read in until you loop through the occurrences.

If you had retrieved a rather large amount of data, looping through it like this would continue to hold all of that data in memory.  In the situation where you're processing records one by one, you often no longer need the record after it's been processed, so it's a good idea to discard the record, to free up the memory.  

Each time you discard a record, it removes it from the hitlist and then does an implicit setocc to the next record, which becomes the new current record.  Another thing that discard does is set $status to be the occurrence number, or 0 if there are no records left in the hitlist, just like setocc does.  This allows us to build a very similar loop to the one we had before...

  setocc "ent",1
  while $status > 0 )
    ;do something
    discard "ent",$curocc(ent)

  endwhile

An alternative that I often see is something more like this...

  setocc "ent",1
  while $hits("ent") > 0 )
    ;do something
    discard "ent",1

  endwhile

I'm not a fan of this one though, as $hits can sometimes have performance problems of it's own, caused by it's tendency to complete the hitlist in order to return the count.  

So, let's check how these different methods stack up against each other performance-wise, using the same 600 records as before...

  • Original loop: 6.37, 6.02, 5.90 (around 6 seconds)
  • Discard loop with $curocc: 5.95, 5.95, 5.86 (just under 6 seconds)
  • Discard loop with $hits: 5.95, 6.00, 5.89 (just under 6 seconds)

As you can see, there isn't that much difference in the approaches as far as performance goes.  In this case $hits hasn't caused a problem, but if I remember correctly, it's environment and/or database specific, so that's probably why.  


Summary: Using discard with a large record set is a good idea, because it reduces the memory footprint of the userver, and at no noticeable cost to processing time.