As explained before, named references should be restricted to debugging and reusable objects. A couple of problems related to their creation and usage can be identified:
Various alternatives to creating global objects have been tried. We will present some of the straight-forward approaches below and describe the (dis)advantages. Section 10.3.3 describes the pce_global/2 directive to solve this problem. We will use a particular fill-pattern (image) as an example.
Using a directive to create a reusable global object appears to be a logical way of dealing with them. This leads to the following code:
:- new(@stones_image, image(stones)). ..., send(Box, fill_pattern, @stones_image), ...
This code has a serious disadvantage. Whenever this file is reloaded after the Prolog code inside it has changed, the directive will be executed as well. The predicate new/2 will generate a warning on an attempt to create an object with an existing name.
Another common approach is to test inline. For the example, this would look like:
..., ( object(@stones_image) -> true ; new(@stones_image, image(stones)) ), send(Box, fill_pattern, @stones_image), ...
This approach is bad programming style. If @stones_bitmap is required at various places in the source files this construct needs to be repeated at various places.
This approach is based on exception-handling. If PCE translates a named reference into an internal reference and the named reference does not exist it will raise an exception. The pce_global/2 directive installs an exception handler dealing with a specific global reference. The example becomes:
:- pce_global(@stones_image, new(image(stones))). ..., send(Box, fill_pattern, @stones_image), ...
This directive
applies some heuristics to take care of redefinitions when the file is
reconsulted: if the definition is still the same it will not complain.
If the definition has modified and the object is already created it will
rename the object using `object
->
name_reference'. A later reference to the
object will trap the exception handler again, creating a new object
according to the current specification. The directive prints diagnostics
messages on redefinitions and other possible problems during
compilation. See
appendix D for details on pce_global/2.
Recogniser objects (see section 5.5) that make graphical objects sensitive to mouse events are often created with a global reference. Suppose an application requires box objects that can be moved, resized and that have a popup menu. The recogniser may be defined as:
:- pce_global(@mybox_recogniser, make_mybox_recogniser). make_mybox_recogniser(R) :- Gr = @arg1, new(P, popup), send_list(P, append, [ menu_item(cut, message(Gr, free)) ... ]), new(R, handler_group(new(resize_gesture), new(move_gesture), popup_gesture(P))).
This recogniser object may be attached to the graphical objects
either using `graphical->
recogniser'
or by redefining the `graphical->
event'
method. In the first case, the recogniser is an integral part of the
graphical object and cannot be changed easily during the lifetime of the
object. In the second case, the reference to the gesture is through the
Prolog implementation of the method and replacing the global object will
make all members of the class behave according to the new definition
immediately.
If the latter approach is taken and the recogniser is under development, you may wish to use free/1 to make sure the new definition is created:
:- free(@mybox_recogniser). :- pce_global(@mybox_recogniser, make_mybox_recogniser).