Quantcast
Channel: Uniface
Viewing all 45 articles
Browse latest View live

The new Uniface

$
0
0

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.




Sendmessage versus postmessage

$
0
0
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.

What are handles and should I be using them?

$
0
0
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.

Converting a form to a service and vice versa

$
0
0
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.

Generating random numbers (again)

$
0
0
A couple of years ago I wrote a post about generating random numbers.  I talked about three different ways of generating a random number (in absence of a $random function in Uniface)...

1) Use a perform to call a DLL (or shared object) that returns a random number.
2) Use $uuid to generate a random number in Uniface.
3) Use a DIY Linear Congruential Generator, built in Uniface.


I found that the perform was the best for performance, and I also stated that it gave a better randomness as well, but I failed to back this up (sorry). 

This issue has raised it's head again, as we're currently trying to get rid of all our own external libraries (DLL/SO) in order to improve maintainability and interoperability.

This time I'm going to test over 1,000,000 iterations (instead of 2,000,000 as before), as there's a little more code inside the loop to store the generated numbers.  Each method will be generating numbers between 0 and 99, and I will then plot the number of times each of these numbers is generated, and report the standard deviation as well - this should give a good idea of the spread.

1) perform: 35.98 seconds (0.036ms per value) - standard deviation: 28.870


2) $uuid42.8 seconds (0.048ms per value) - standard deviation: 28.869


3) DIY: 56.54 seconds (0.057ms per value) - standard deviation: 28.894


As you can see from these charts, and the standard deviation of the numbers generated, all three of these methods have a similarly decent spread.  The time difference hasn't been quite as drastic this time, although that's likely to be due to the extra code in the loop that stores the values for the spread analysis.  Unless you're planning to generate a million random numbers, it's not likely to have a noticeable effect on performance though.

One thing to note though, if you're only concerned with Windows environments, then you don't have a problem, and as long as your DLLs (or shared objects in Unix) are equivalent, then you don't have a problem.  However, the $uuid method does not work as well in Unix environments...

4) $uuid in Unix: (time is not comparable) - standard deviation: 28.833



As you can see, the spread is not uniform at all.  This is because UUID is not sufficiently random in Unix - the first 5 characters seem to be time based, then 3 random characters, then the rest remains constant within the same userver (presumably based on the machine itself and the process ID).  

Summary: As before, perform is the quickest method, but if you're supporting multiple environment configurations then it's likely that building your own random number generator (possibly using $uuid on Windows) is going to make your life much easier.

Additional: There's now a blog post about this on Uniface.info, if you're interested... http://unifaceinfo.com/random-number-generator-uniface/

New Uniface, a roadmap

$
0
0

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

New Uniface, a roadmap


Photo of David Norfolk
Written By: 
Published: 
Content Copyright © 2014 Bloor. All Rights Reserved.

Link to article: http://www.bloorresearch.com/blog/the-norfolk-punt/2014/9/new-uniface-a-roadmap/


This matches up pretty well with what I was told at a User Event back in January, but with the welcome addition of Uniface 9.7 to the roadmap.

The main themes for Uniface 10 are...

  • Advanced development environment (a brand new IDE, written in Uniface itself!)
  • Agile development methodology
  • Mobile deployment (dedicated team for mobile development)
  • Cloud deployment (this will come later, not in 10.01 or 10.02)

We'll have to wait until Uniface 10.02 for a migration path from earlier versions though, which should be sometime next year.

Summary: Life after Compuware is still looking good for Uniface.

Rosetta Code

$
0
0
Recently I was pointed an interesting website, or at least, I thought it was interesting.  And that's Rosetta Code.  I'll let them describe what it's all about...

Rosetta Code is a programming chrestomathy site. The idea is to present solutions to the same task in as many different languages as possible, to demonstrate how languages are similar and different, and to aid a person with a grounding in one approach to a problem in learning another. 

Surprise, surprise; Uniface was nowhere to be seen.  So I've rectified that problem, and added Uniface to the list of programming languages.

I didn't have a lot of time on my hands, so I cheated and copied the contents from Wikipedia, in order to create the base page.  Some of the content is out of date, as it still lists Uniface as a Compuware product, but it's a start.

The idea now is to go through and complete some of the tasks not yet implemented in Uniface, which is currently all of them!  I plan to devote a little bit of time to this myself, but I guess this is a bit of a call out to Uniface developers - go forth and complete tasks!

Summary: Rosetta Code looks like an interesting site for comparing different languages, but Uniface examples are non-existent.
 

Fetching web content

$
0
0
I've been working on fetching web content recently, mostly for building authentication workflows, using the likes of Facebook and Google to act as authentication services.  I'm going to go into detail about how I've done those, not in this post at least, but more simply how I made the requests from my Uniface service form, out to those external services. 

There are a number of different HTTP methods.  Generally speaking, when you are retrieving data only then the method is "GET", whereas if you are sending data that may perform an action as well then the method is "POST".  There are others, but I'm going to stick with these two for now, as they are more commonly used.

In fact, I'm going to start with "GET" first.  

The first thing you need to do is consider the character set.  Your system may be set in different character sets, but you need to make sure the character set of your request matches the service you are calling, in my case it was UTF-8...

  vCharSet = $sys_charset ;backup current setting for later
  $sys_charset "UTF8"  ;set to the character set we need

We then want to create a new instance of the "UHTTP" component - this is the Uniface component that is going to do most of the hard work for us...

  newinstance "UHTTP",vHandle
  if $status < 0 & $procerror < 0 )
    $sys_charset = vCharSet ;restore character set
    return -101             ;error handling!
  endif

Once you've got your instance, the next step is to define how the component responds to mismatched or expired certificates, and how it calculates the content length.  By default it will error if there is a certificate error and you have to manually calculate the content length yourself.  It's a binary switch, so to switch them all off we do the following...

  activate vHandle.SET_FLAGS(7)
  if $status < 0 & $procerror < 0 )
    $sys_charset = vCharSet ;restore character set
    return -102             ;error handling!
  endif

We're now ready to make the request.  In this example, I'm just going to grab the Google homepage...

  activate vHandle.SEND("http://www.google.co.uk","GET","","","",vContent,vResponse)
  if $status < 0 & $procerror < 0 )
    $sys_charset = vCharSet ;restore character set
    return -103             ;error handling!
  endif

The parameters are:

  1. URL (string : in) - the URL you're sending the request to.
  2. Method (string : in) - the method being used (this is not checked by "UHTTP").
  3. Username (string : in) - if you're using a secure URL, you may need to populate this.
  4. Password (string : in) - again, you may need to populate this.
  5. Headers (string : inout) - the HTTP request headers in and the response headers out.
  6. Content (string : inout) - in the case of a "GET" this is out only and the page contents.
  7. Response (string : out) - the HTTP response headers.
The $status should be set to 200 for a successful response (to match the HTTP status code for success) or it may be set to 1.  If it is set to 1 then this means that the content was larger than the parameter limit (10Mb) and therefore you will need to get the rest of the content from the buffer, like this...


  while $status = 1 )
    activate vHandle.READ_CONTENT(vExtra)
    if $status < 0 & $procerror < 0 )
      $sys_charset = vCharSet ;restore character set
      return -104             ;error handling!
    endif
    vContent = "%%vContent%%vExtra%%%"
  endwhile


You now have the full page contents, but don't forget to restore the character set...

  $sys_charset = vCharSet ;restore character set

Doing a "POST" is very similar, except for a couple of differences:
  1. To replicate a web browser "POST", which you are usually doing, you need to make sure the 5th parameter of the SEND call is populated with the following header.. "Content-Type=application/x-www-form-urlencoded"
  2. The 6th parameter of the SEND call needs to be populated with the data that you are sending in your request.  If this is larger than 10Mb then you will need to have a WRITE_CONTENT loop (similar to the READ_CONTENT loop) before the SEND, in order to populate the buffer with the full contents.
This all works rather well.  However, I've found two major limitations along the way.

Firstly, it was not possible to send a request to a URL which had a colon (:) character after the protocol.  For example, when trying to get a user's LinkedIn ID you would use the following URL...

  "https://api.linkedin.com/v1/people/~:(id)?oauth2_access_token=%%vToken%%%"

The colon (:) character after "/people/~" broke the URL.  Luckily I'm using the past tense here, this was fixed in patch X504 (for Uniface 9.6.05).  This works fine now we've installed the patch.

Secondly, the observant of you may have noticed the 6th parameter of the SEND call is defined as a string.  This is great for grabbing HTML page source from a website, or even doing most webservice calls, as these tend to return either XML and JSON strings of data.  However, it makes creating something like a Dropbox interface impossible, or at least very limited.  You can grab text files, but nothing else!  No images, no Office documents, no PDFs.

Unfortunately there's no word from Uniface on when this second issue might be resolved.

Summary: It's possible to use the "UHTTP" component to request text data, either from a web page or a webservice.  Just don't expect it to work with binary files, yet!

Syntax strings versus literal strings

$
0
0
There are a number of very important differences between syntax strings and literal strings, which I will attempt to highlight for you here.

Firstly, the Uniface definition of a syntax string...
Uniface enables you to determine if the data in a string value matches a desired pattern using syntax strings.  A syntax string is a group of characters and syntax codes enclosed in single quotation marks (').
So that's the first big difference right there, literal strings are in double quotes (") and syntax strings are in single quotes (')...

  literalString = "Literal string"
  syntaxString = 'Syntax string'

A syntax string is used for pattern matching, but they are much more simplistic than the regular expressions that you might be used to in other languages.  The syntax codes are quite straight forward...

  • # - one digit (0-9)
  • & - one letter (A-Z, a-z)
  • @ - one letter, digit or underscore (A-Z, a-z, 0-9, _)
  • ~& - one extended letter
  • ~@ - one extended letter, digit or underscore
  • ? - one ASCII character
  • A-Z - that letter, in uppercase
  • a-z - that letter, in uppercase or lowercase

On top of these are a few other syntax codes of note...

  • If you want to search for the literal version of a syntax code, eg. you want to search for the hash character (#) not a digit (0-9), then you can escape the syntax code using % before it.  Therefore, to search for a hash character it would be '%#' and to search for a percentage character it would be '%%'.
  • If you want to search for a unknown number of syntax code, eg. you want to search for 2 or more digits, then you can use * after it.  Therefore, to search for 2 or more digits it would be '###*' - in this case the first two hash characters represent one digit each, and the third hash character is part of the the syntax code '#*', which means zero or more (0-n) digits.
  • If you want part of the pattern to be optional (to match the pattern or blank) then you can put rounded brackets around it, using ( and ).  For example, '##(#)' would match with 2 or 3 digits (but not more than 3).
  • Any other character is treated literally as that character.  

Uniface also gives a handy function that can be used to convert a literal string into a syntax string, sensibly named $syntax...

  syntaxString = $syntax("Literal string")

This can be especially useful if you're storing the pattern in the database, or some other configuration.

Here are a few examples from the Uniface manuals...

Proc with Syntax String
Result
if('#'="123")
if('#*'="123")
FALSE
TRUE
if ('#*'=vValue)
if ('#*'="%%vValue")
TRUE
TRUE
if ('&###'="1234")
if ('@###'="1234")
FALSE
TRUE
if ('?'="A")
if ('??'="A")
if ('??*'="A")
if ('?'="ABC")
if ('??*'="ABC")
TRUE
FALSE
TRUE
FALSE
TRUE
if ('(#(-))&&&'="ABC")
if ('(#(-))&&&'="1ABC")
if ('(#(-))&&&'="1-ABC")
if ('(#(-))&&&'="12ABC")
TRUE
TRUE
TRUE
FALSE


I've had (occasionally heated!) discussions with developers before, when they have said that...

  if ( myVar = "Y")

...and...

  if ( myVar = 'Y' )

...are interchangable.  

Yes, I can see that the pattern 'Y' only matches with the string "Y" and nothing else, but they are entirely different ideas, and should not be used interchangeably.  If you want to only match with "Y", then use the literal string "Y", because that's what you mean.  

In my experience, developers who say that these are interchangable are developers who don't understand what the differences are.

Summary: Syntax strings are very useful for pattern matching, but very different than literal strings.  Know the difference, and know when to use which.

Syntax strings in different modes

$
0
0
Earlier I wrote a post about syntax strings versus literal strings, which involved me diving into the Uniface manuals to check my facts.  I talked about using $syntax to convert a literal string into a syntax string - very useful!  

However, what I didn't know before was that you can have different modes.  This is something that appears to have been added in Uniface 9.4.01, without me noticing.

There's a lovely table in the Uniface manuals to describe them, but I've tested their examples and I think there are some inaccuracies.  So I'm going to try and lay them out for you here...

Classic

This is the default behaviour, but is also represented by '%[X]'.  In this case, the usual pattern matching rules apply, with syntax codes being used as wildcards to represent patterns of characters.

  • Proc code: $syntax("D&G")
  • Syntax string: '%[X]%D&G'
  • Matches: "DOG", "DIG", "DUG", etc.

You can see the syntax string starts with the mode defined in this case, which is optional for classic mode, because this is the default.

Case Sensitive

In this mode, all characters will only match with characters of the same case.  Also, syntax codes will be treated as their literal characters, and not as wildcards.

  • Proc code: $syntax("D&G","CS")
  • Resulting syntax string: '%[CS]D%&G%[X]'
  • Matches: "D&G"

You can see the syntax string starts with the mode defined in this case, but it also ends with the exit mode, switching back to the default/classic mode.

The manuals suggest that in the proc code the mode is passed in without the double quotes, but I found this had to be a string for it to work.  They also suggest that the mode "S" can be used instead of "CS" for the same thing - I found that only "CS" works in proc code, but you can use '%[CS]' or '%[S]' in syntax strings you write yourself.


Case Insensitive

In this mode, all characters will match with characters of either upper or lower case.  Again, syntax codes will be treated as their literal characters, and not as wildcards.

  • Proc code: $syntax("D&G","CI")
  • Resulting syntax string: '%[CI]D%&G%[X]'
  • Matches: "D&G", "d&g", "D&g" and "d&G"

Again, I had to use a string to define the mode in the proc code, and only "CI" worked, but '%[CI]' and '%[I]' both worked in syntax strings I wrote myself.

NLS Locale

In this mode, all characters will match with characters of either upper or lower case, depending on the National Language Support (NLS) locale that the system is in (can be checked or set using $nlslocale).  Again, syntax codes will be treated as their literal characters, and not as wildcards.

  • Proc code: $syntax("i#B","NLS")
  • Resulting syntax string: '%[NLS]i%#B%[X]'
  • Matches: If your local is Turkish (tr_TR) then "i#B" and "İ#b", but not "I#B"

Once more, I had to use a string to define the mode in the proc code, and only "NLS" worked, but '%[NLS]' and '%[N]' both worked in syntax strings I wrote myself.

Mixing modes

You can also define a combination of modes in a single pattern, something like this...
  • Proc code: $syntax("%[CI]D%&%[CS]G%[X]")
  • Resulting syntax string: '%[CI]D%&%[CS]G%[X]'
  • Matches: "D&G" and "d&G"

There's a slight typo in the manuals with the proc code here, as they have missed the "%" from the beginning!  

Summary: You can use different modes in syntax strings, either specifying the case-sensitivity or relying on the NLS locale, but be careful if you're using $syntax because you'll lose the wildcards.

Indirection with dollar registers

$
0
0
Indirection in Uniface is a wonderful thing.  You can populate a local/component/global variable with a field name, and then use indirection to get the field value of the field that the variable references.  You can also use it to set the referenced field to a value, like this...

  fld1 = "fld2"
  @fld1 = "Test"
  if ( fld2 = "Test")
    ;this will be true
  endif

In this example, using the "@" character to indicate indirection, it's the field which is referenced by "fld1" and not "fld1" itself which is updated.

You can even do recursive indirection, which is very cool!  Not something I've had a need for myself, but very clever all the same.

However, today I was trying to populate a register the same way, using code something like this...

  reg50 = "$50"
  @reg50 = "Test"
  if ( $50 = "Test")
    ;this will be false!
  endif

In this example, the register was still blank (or whatever the register was before hitting this code).

To be fair, this is clearly stated in the Uniface manuals...

Only fields can be referenced indirectly; the name reached by the indirect reference cannot be a variable. The following example is incorrect because the indirection refers to a general variable rather than to a field:

$1 = "$99"

@$1 = "This string does not go to $99."


But I still wanted to be able to set registers in an indirect way, so I came up with this alternative...

  putitem/id list,"$50","Test"
  getlistitems/id list
  if ( $50 = "Test")
    ;this will be true
  endif

This works by populating a list with the register and the value, and then uses getlistitems to populate them.  The "/id" mode copies items from the associative list into one or more fields, or registers in this case.

For example, you could use a simple for loop to clear out all of the dollar registers...

  for count = 1 to 99
    putitem/id list,"$%%count%%%",""
  endfor
  getlistitems/id list

This would set each of the 99 dollar registers to blank.

Summary: Indirection works great for fields, but not for registers - however, you can use getlistitems to achieve the same outcome.

Undocumented feature - current assignment file

$
0
0
One great feature of Uniface is it's great flexibility and configurability, through the use of different assignment (.asn) files.  These are used to define paths to the different runtime files and server locations, etc.  The problem can then come though, especially with multiple environments, that you don't know which assignment file you're using!

I wrote a post a while ago about the undocumented $assignments function, which allows you to get access to the assignment file settings that you are currently using, but this doesn't help you get to the filename itself.

One suggestion I've seen before is to add a logical to each assignment file which specifies the name/location of the file.  However, it's way too easy for someone to move, copy or rename the file and neglect to update the logical, and then worse than not knowing, you think you do know but the information you're being given is inaccurate.

Luckily Uniface 9.6.06 has solved this problem with a new undocumented feature of $processinfo...


  putmess $processinfo("cmdline")

This will put the command line used to access the application into the message buffer.  For example...


  "\\server\location\uniface\bin\uniface.exe" /asn=\\server\location\adm\uclidev.asn /ini=\\server\location\ini\me.ini APPSHELL


As you can see, the assignment file and ini file are both specified in the command line, along with the application shell as well.  This should give you all the information you need, although you'll need to do some string manipulation to pull out the bit(s) you want.

This was recently discussed on the UnifaceInfo.com forums, so you can check there for more context, and sign up if you haven't already!

Summary: You can access the current assignment file location, but accessing the command line, as long as you're happy to use an undocumented/unsupported feature.

Modernising the client application - icons in the menu

$
0
0
A lot of the Uniface development that I do these days is actually web development, which means I spend a lot of time with Javascript and JQuery, and less time with Uniface procscript.  However, we still have client applications as well, and they can look tired and dated, so anything we can do to make them look more modern, can be a big win!

This is a simple little trick that appeared in Uniface 9.6.  It's actually been around for a while in dropdown menus, first as an undocumented feature, and then documented in Uniface 9.5 - I wrote a blog post on this almost three years ago.  However, the same trick now works in menus.

You can reference images in the menu items like this...


You might not be able to read the image clearly, so the three menu items are...

  1. ^U_REM_SELECT·!Cu%t
  2. ^U_SAVE·!Copy
  3. ^U_INS_SELECT·!Paste

In this case, the image is at the start, with a gold-not (or gold-exclamation-mark) as a delimiter, and the menu item text after that.

This appears in the client application this this...



As you can see - lovely icons!  Please note that you would need these glyphs in your system for it to work, these are not provided as part of Uniface itself.  

You can include icons in one of two ways...

  • ^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).

I would recommend the glyph option though, for performance and reliability.

You may also note that the percent character (%) can be used to denote which character should work when traversing the menu using the "Alt" key.  If you do not explicitly denote this, the first character will be used.

This is documented in the "Defining and Using Menus" section of the manuals, but can be hard to find unless you know what you're looking for!  It's worth reading this for more information though.

Summary:  It's possible to make the client application look a little more modern now by including icons in the menu bars.

Performance of getitem

$
0
0
I've previously posted about how scanning is slow, and I stand by that.  But I've recently discovered that in some situations, it can be less slow than using getitem.  

I was doing a code review of some old code and found that it was using $scan in a situation where I thought you'd usually use getitem, and wondered why someone would have done it this way.  But before I replaced it, I wanted to check the performance to see what difference I would be making by changing it, and I was surprised by the results!

The code was designed to check if a variable matched one of a reasonably large number of items.  For this example, if stuck with 10 items...

  if ( temp = "ONE"| temp = "TWO"| temp = "THREE"| temp = "FOUR"| temp = "FIVE"| temp = "SIX"| temp = "SEVEN"| temp = "EIGHT"| temp = "NINE"| temp = "TEN")
    ;testing condition
  endif

I could have used a line continuation marker, but you get the idea.

What the developer had done is replaced this set of conditions with a single $scan, like this...

  list = "|ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE|TEN|"
 
if ( $scan(list,"|%%temp%%%|") > 0 )
    ;testing condition
  endif

Note that this is not a Uniface list, a "bar" or "pipe" character has been used as the delimiter - this is placed at the beginning and end of the value to ensure it is not found as a sub-part of another longer value.  It This takes up a lot less space, and is perfectly readable, but I was concerned about performance.  

To test this, I wanted to make sure it was fair, so I decided to always check both the first and the last item in the list in each iteration.  I also wanted to test in a few different ways, and I came up with 4...

1) Set of conditions

  temp = "ONE"
  if ( temp = "ONE"| temp = "TWO"| temp = "THREE"| temp = "FOUR"| temp = "FIVE"| temp = "SIX"| temp = "SEVEN"| temp = "EIGHT"| temp = "NINE"| temp = "TEN")
    ;testing condition
  endif
  temp = "TEN"
  if ( temp = "ONE"| temp = "TWO"| temp = "THREE"| temp = "FOUR"| temp = "FIVE"| temp = "SIX"| temp = "SEVEN"| temp = "EIGHT"| temp = "NINE"| temp = "TEN")
    ;testing condition
  endif

2) $scan a bar delimited string

  list = "|ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE|TEN|"
 
if ( $scan(list,"|ONE|") > 0 )
    ;testing condition
  endif
  list = "|ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT|NINE|TEN|"
  if ( $scan(list,"|TEN|") > 0 )
    ;testing condition
  endif

3) getitem/id a Uniface list

  list = "ONE·;TWO·;THREE·;FOUR·;FIVE·;SIX·;SEVEN·;EIGHT·;NINE·;TEN"
  getitem/id temp,list,"ONE"
  if ( $status > 0 )
    ;testing condition
  endif
  list = "ONE·;TWO·;THREE·;FOUR·;FIVE·;SIX·;SEVEN·;EIGHT·;NINE·;TEN"
  getitem/id temp,list,"TEN"
  if ( $status > 0 )
    ;testing condition
  endif

4) $item a Uniface list

  list = "ONE·;TWO·;THREE·;FOUR·;FIVE·;SIX·;SEVEN·;EIGHT·;NINE·;TEN"
  if ( $item("ONE",list) != "")
    ;testing condition
  endif
  list = "ONE·;TWO·;THREE·;FOUR·;FIVE·;SIX·;SEVEN·;EIGHT·;NINE·;TEN"
  if ( $item("TEN",list) != "")
    ;testing condition
  endif


I wasn't really sure what I was expecting, but I thought the $scan would be the worst performance.  I tested over 2,000,000 iterations, and here's what I got...

1) Set of conditions: 37.30, 36.95, 37.83 = 37.36 secs
2) $scan a bar delimited string: 21.76, 21.97, 21.24 = 21.66 secs
3) getitem/id a Uniface list: 24.46, 24.22, 24.89 = 24.52 secs
4) $item a Uniface list: 22.65, 23.25, 23.47 = 23.12 secs

So the slowest was the set of conditions.  I didn't test it, but knowing that if statements shortcut I figure that if the item was always passing the first condition it would be quick, but because half of my test items were only passing the last condition, it would have to check each of the conditions in the set before it passed.

Although there wasn't a big difference, what surprised me is that the getitem/id and $item were actually slower than the $scan in this case.  I then remembered back to a conversation on the Uniface-L mailing list, which talked about how Uniface handles lists in the background.  The description there indicates that an array is built in the background, which means there is an upfront cost for calling getitem/id (or $item) once, but then if you're looping through it is much quicker to access the rest, because the array can be used.  However, because I'm rebuilding the list each time, that means the array needs to be rebuilt each time.  

This means that actually $scan can be used to improve the performance when checking that an item is in a list, as long as you're only checking this list once and it's not going to be re-used.  I expect there to be a point at which the number of times the list is re-used means that using getitem/id (or $item) would become better for performance.

Also, I've not tested different lengths of lists.  However, given the results and my reasoning for why the results ended up this way, I would have thought extending the list would simply emphasize the results.

Summary:  Checking if an item is in a list can be done a number of ways, and if it's being done a lot of times, performance can be eeked out by using a $scan, surprisingly!

WCG Online

$
0
0
I must apologise, this is not a Uniface-related post.  That said, please read on!

World Community Grid enables anyone with a computer, smartphone or tablet to donate their unused computing power to advance cutting-edge scientific research on topics related to health, poverty and sustainability. Through the contributions of over 650,000 individuals and 460 organizations, World Community Grid has supported 24 research projects to date, including searches for more effective treatments for cancer, HIV/AIDS and neglected tropical diseases. Other projects are looking for low-cost water filtration systems and new materials for capturing solar energy efficiently.

Active projects include... 
  • Outsmart Ebola Together
  • Uncovering Genome Mysteries
  • Mapping Cancer Markers
  • The Clean Energy Project - Phase 2
  • FightAIDS@Home.

If you're not already a member, you can sign up here.

I have just launched a companion site; WCG Online...



This site is designed to give you, a valued member of the community, access to some more detailed statistics, as well as some lovely pretty graphs.  It requires for username and a verifcation code, in order to fetch the relevant data.  Nothing is stored on my server, all data is stored in your brower's local or session storage.  This is then used to notify you of new milestones, such as badges earned.  It allows you to rename and hide devices, so if you've got multiple devices (two phones, a tablet, etc) you can give them more easily identifiable names, or hide them completely from the other pages.

The site is also designed to be fully responsive and mobile friendly, created from the ground up in jQuery Mobile.

The next part of the project is to create custom widgets that you can link to on your own site.  The offical site has widgets, but they use iframes and are rather basic.  So I'm hoping to create images, and give a lot more flexiblity.  Watch for those coming soon to WCG Online.

There is also a Play store app, which provides a shortcut to the website, and is free to download, if you're interested.

Where to put your code

$
0
0
There's an interesting blog post by Dennis Vorst gone up on the Uniface.info blog, titled Where to put your code.  As the title suggests, it's about which places are best for different types of code, based on their content.  

There are a number of options; conceptual at the entity or field level, locally at the entity or field level, within the component, a local procedure or a global procedure.  All of these have their merits.  

I've posted my response, defending the mighty global procedure, but why don't you have a read and add your opinion in the comments?

Summary: Check out this blog post... http://unifaceinfo.com/where-to-put-your-code

Modernising Uniface

$
0
0
Uniface have been putting a lot of work into the new Uniface 10 IDE, and this is something I'm looking forwards to getting my hands on, but it could be a while yet.  Good things come to those who wait, they say.

Well the good news is that the delays in Uniface 10 have led to the decision to release a Uniface 9.7.  Whilst they may be planning to put limited time into this, whilst focusing their efforts on Uniface 10, it looks like they have big plans to modernise.

In the first of a 10 part series, Theo Neeskens has outlined the objectives and the first set of changes - the start screen.

The objectives were straightforward enough...

  1. New start page - Windows 10-esque - big change.
  2. Change grey backgrounds to white backgrounds.
  3. Use trendy flat buttons.
  4. Fresh look and new colour scheme - something different.

Looks like they met the objectives, based on these screenshots...



Now that's a radical change!  I think changes like this will be very well received, and help stop people getting such a negative first impression of Uniface as a language.

The full blog post is definitely worth checking out... Modernizing Uniface 9.7 in 10 easy steps.

Summary: Uniface is modernising, and we're not going to have to wait for Uniface 10 to get in on the action.

Modernising Uniface - part 2

$
0
0
I posted last week about Modernising Uniface, which included my comments about Theo Neeskens post on UnifaceInfo.com.  I received some comments that I was talking purely about the IDE, and not the language itself.  So let me start by stating that this post of about the modernisation of the IDE, and not the language itself.

This time the post is all about the effort it took to make the seemingly simple move from grey backgrounds (which psychologically make software feel outdated) white clean, clear, white backgrounds, like this...

For both of these dialogs, the older grey version sits behind the newer white version.  You can also see the buttons have changed, but we've been promised more about those in the next blog post.


The main problems they hand with this change included...
  • Forms having index, foreground or background colour set
  • Painted entities having index, foreground or background colour set (and being painted at least 3 characters wide)
  • Entities having foreground or background colour set in the model
  • Grids not having borders
  • Multi-occurrence entities not having borders

A couple of these have been resolved by making new properties available, but all of them required fix programs to find the affected items and update them to the new properties.  All of the tools have been provided in a zip file, to be downloaded and modified if you wish, but not supported by Uniface and used at your own risk.

I've had my hands on Uniface 9.7 now (which I hadn't when I wrote the first post) and I can say that it definitely feels more up-to-date, and I agree that the white backgrounds and blue buttons are a large part of that.  We've actually been changing our web offering to a similar colour scheme over the past few months, so I can't disagree with their choice!

Again, the full blog post is definitely worth checking out... Modernizing Uniface 9.7, Part 2.


Summary: Uniface is modernising it's IDE, and we're not going to have to wait for Uniface 10 to get in on the action.

Modernising Uniface - part 3

$
0
0
Over the past couple of weeks I have posted about Modernising Uniface (and here), and this is the third and final post in this series.

The third post from Theo Neeskens was primarily concerning the new flat buttons, which look like this...



As you can see, the new flat blue buttons, on a white background, are on top of the old grey/grey.

The first thing they needed to do was categorise the different painted button types, and they came up with five...
  1. IDFButtonBottom - for the big buttons at the bottom of dialogs
  2. IDFButtonSide - for the big buttons at the right-hand side of dialogs
  3. IDFButtonSpecial - for the other buttons
  4. IDFButtonImage - for the small buttons without labels (eg. ">>")
  5. IDFButtonHeader - for the buttons which make up the header on simulated grids

So then there are a few jobs that needed to be done...
  • Change the properties in the configuration file for these widget types
  • Match modelled widgets with painted widgets
  • Set the properties on the painted buttons
  • Set the properties on the modelled buttons



Again, many of the these jobs were achieved with tools, and all of these have been provided in a zip file, to be downloaded and modified if you wish, but not supported by Uniface and used at your own risk.

The full blog post is definitely worth checking out, including the "Wishes" section at the end... Modernizing Uniface 9.7: The buttons


Summary: Uniface has successfully (in my opinion!) modernised it's IDE in version 9.7, meaning we don't have to wait for Uniface 10.

Drag and drop

$
0
0
Yesterday I read an interesting article about drag and drop in Uniface, aptly named Drop It Like It's Hot.  

It actually goes into plenty of detail about how to add drop areas into your own Uniface forms, which is something I'd definitely like to try some time.  But what really interested me was the opening paragraph...

What very little people know is that in the Import Repository Objects component there is a small section where you can drag your export files from Windows Explorer. After you drop them, the File name box is updated with the list of files that you dropped. The red section is where the drag-and-drop field is located.


I tried this today and it definitely works.  You learn something new every day!

Summary: You can drag and drop export files onto the Import Repository Objects popup, which is really quick and convenient.
Viewing all 45 articles
Browse latest View live