Choosing between Events and Functions
Blurred boundaries
I remember when I started out as a PowerBuilder 4.0 programmer; the distinction between user events and functions used to be a favorite question in every job interview - "If you need to implement an object method, what will you use - a user event or a user function?". And the answer was usually easy  considering the most obvious differences between the two -
  • Events do not accept parameters
  • Functions cannot be posted

These two difference made it easy to choose between the two when designing an object. If you required parameters, you had to go with functions. If you needed the ability to 'post', then you used events. For better or for worse, this is no longer true. Since the release of PowerBuilder 5.0, PowerSoft has blurred the distinction between user events and functions. Now, events can accept parameters and functions can be posted. Does that mean that events and functions are interchangeable techniques in all situations? Apparently not. There are still some subtle, but important, technical differences between events and functions. And, there are some 'aesthetic' issues too, that should be considered when choosing between the two. These technical differences and aesthetic considerations should be used as a guide to choosing between events and functions.

Technical Differences
Inspite of many similarities, there are some important technical difference between events and function that can limit your choice to one or the other.
  1. Events are always PUBLIC. Functions can be defined as PUBLIC, PRIVATE or PROTECTED. This is an important consideration when it comes to encapsulation. If you do not want to expose the method to other objects, then you should use a function and make it PRIVATE or PROTECTED.
  2. PowerBuilder will generate a system error when a dynamically called Function does not exist at run time. But, it won't crash if a dynamically called Event does not exist. Ideally, a good design should pre-empt the possibility of calling a non-existent method. However the fact that a call to a non-existent event won't crash PowerBuilder can be used for those 'quick-n-dirty' fixes.
  3. Events cannot be overloaded like Functions. This can be a real showstopper if you initially decided to implement a method as a user Event and then realized that you need to overload the method. It can't be done. Hence, this limitation should be given due attention before you make a decision.
  4. In case of visual user objects, you cannot override/extend the functions after it has been placed on a Window. However, you can extend/override it's events. Take for example an event like ue_validate in a datawindow user object. This event is expected to be coded when it is placed on a Window.  Hence, for ue_validate events are the only way to go
  5. The Event to be called can be determined at run time using TriggerEvent() and PostEvent() functions. Calling an Event using these functions is different than using the 'Dynamic' keyword. When you use the 'Dynamic' keyword to call an event you still have to know the name of the event -

    my_object.Event Trigger Dynamic ue_myevent()

    These functions allow you to specify the name of the Event to be called as a string. This means that you actually 'construct' the name at run time-

    ls_event = "ue_myevent"
    my_object.TriggerEvent( ls_event )

    This technique has the limitation that you can't specify the parameters to be passed if the Event you are calling accepts user defined parameters.
Design Aesthetics
In most cases the technical difference highlighted above will be sufficient grounds for making a choice. However, there are a few other considerations that can be used to make a choice when the technical difference are not relevant to the situation. To me, these decisions fall into the realm of design philosophy, opinion and taste.
  • An Event is a occurrence and multiple events should be used to model the flow of program logic. Consider the Window save sequence that you will find in almost every PowerBuilder class library. Usually the window save sequence is a group of events at distinct points in the sequence -

    ue_presave -> ue_save -> ue_postsave

    ue_presave will typically call events like ue_validate on each datawindow in the window. Each event is a part of the flow and is usually never invoked separately. What is the advantage of using events to code the sequence? Most of these events will be empty in the ancestor window and will be extended in the descendant. It's easy to visualize the 'occurrence' of these events in the descendant within the flow controlled by the ancestor as in the case of the save sequence.
  • Functions are like the buttons on a device. When you click a button, the device is expected to perform a task. Similarly, a function should initiate some processing in the object. It might even initiate and control a sequence of events.
  • When you inherit one object from another by default the descendant Events are Extended, while Functions are Overridden. This is more of a PowerBuilder feature than a limitation since you can easily reverse the default behavior. To override an Event just the check the option from the Design menu in the Event painter ??is it called the event painter. To extend a Function, just call the ancestor function using the "super::<name>" syntax.
  • IDE limitations:
    • In the script painter if the event contains script in the ancestor, PowerBuilder shows the event with a different icon in the event drop down. This feature does not exist for functions.
    • You view this ancestor code by choosing 'Display Ancestor' from the design menu. Again, you can't do this with functions

    As result of these IDE limitations, Events are easier to work with in the descendant objects.

     

Home

-Jiggy 30, Jan 1999

1