Please enable JavaScript to view this site.

KOL/MCK - User Guide

Any object, except for methods, fields and properties, can also have some "events". An event is (for an object) a field of type a pointer to a function, procedure, or method. (Events outside objects may also exist, then it is just a global variable of the type of a pointer to a procedure, function or method). Most often, events are declared as properties (which allows you to work with them using a consistent syntax, regardless of whether assigning a handler to an event requires a special method call, or a pointer can be assigned as a regular field).

 

Most events are method pointers, i.e. their type is declared as procedure ... of object or function ... of object. For programmers, this means that this field is not just a pointer that stores the address of a procedure that will be called when an "event" occurs, but contains two pointers (occupying 8 bytes in memory): one points to an instance of an object that handles the event, and the other - on his method.

 

Handlers for such events should (but not necessarily) not be simple procedures and functions, but methods. For example, the TObj object type already contains an OnDestroy event that fires when the object begins to degrade. When an event is fired, it checks for the presence of an assigned event handler (that is, the nil inequality of a pointer to a procedure), and if there is one, the assigned method is called. The OnDestroy event for TObj objects is of type TOnEvent, declared as follows:

type TOnEvent = procedure (Sender: PObj) of object;

 

From the above description of this type of event, it follows that any method declared (in the body of the declaration of some object) as follows is allowed as an OnDestroy handler:

procedure ObjDestroying (Sender: PObj); (names are in italics, which can always be replaced with your own). If you try in your code to assign an ordinary procedure (i.e. not a method) to this event as a handler, or a method whose description differs more than using other names instead of ObjDestroying and Sender, the compiler will not compile such code, issuing error message.

 

Fortunately, the Pascal language, in spite of its seeming strictness, allows to perform the so-called "data type casting". Operation type_name (...) tells the compiler that what is written in parentheses is of a data type type_name, no matter what data type the expression is being cast. (Of course, you cannot convert any data type to any other in this way, and the main criterion for the possibility of converting one data type to another is that the sizes of the variable before and after the casting must be the same).

 

Thus, there is a legal opportunity to bypass the requirement that the event handlers are always methods, and not simple procedures and functions. KOL has a special function MakeMethod that allows you to "construct" a method from two pointers - an object pointer (which can be nil, and a simple procedure or function pointer). In order for a method of type procedure of object constructed in this way to be assigned as an event handler, the same OnDestroy, it is enough to cast it to the event type when assigned. For example:

 

MyObj.OnDestroy: = TOnEvent (MakeMethod (nil, @ MyObjDestroying));

 

Note that in order to remove the event handler, in any case, it is enough to assign the value nil to the event property - the compiler perfectly understands such an operator as assigning a nil value to both a pointer to a method and a pointer to an object in the event field.

 

Of course, in this code the compiler will no longer check the correspondence between the procedure type MyObjDestroy and the event type. On the one hand, this is good, as it allows you to compile such code. On the other hand, this is not good at all, since anything can be passed as a procedure pointer. The programmer must now ensure the correct operation of the event handler.

 

pointing-up-finger

Pay Attention!

But not all programmers know how a simple procedure (or function) differs from a method (this is bad, but it's never too late to learn). The essential difference between a method and simple procedures and functions is that when the method is called, it receives one more parameter. Namely, the pointer of the object itself is passed as the (first, and this is important) invisible parameter, which can be accessed in the method code either explicitly using the reserved name Self, or implicitly, simply by referring to the methods, fields and properties of the object to which it belongs this method.

 

The conclusion from the above is the following: in order for a simple procedure to be used as an event handler instead of a method, it needs to add the first parameter of type PObj. You can call it whatever is convenient, for example, _Self_, or Dummy (this name is often used to indicate that the parameter is not actually used, and is only needed so that other parameters are passed each in its place).

 

That is, the following description of the MyObjDestroying procedure will be erroneous:

procedure MyObjDestroying (Sender: PObj);

 

while the description would be correct:

procedure MyObjDestroying (Dummy: PObj; Sender: PObj);

 

In the first case, when calling the procedure, instead of the Sender parameter, nil, specified when constructing the method as an object, would be passed, and the pointer to the object (Sender) for which the event occurred is lost. Whereas in the second case, it is transmitted correctly. The program, however, is executed, and there is no problem with the violation of the stack pointer, because in Pascal, by default, the first three parameters are passed not through the stack, but through the processor registers. However, if the event handler tries to use Sender, then in the first case it will always "see" the value nil. Looks discouraging, doesn't it?

 

Let me finish with this educational program, and I hope that if you want to use a simple procedure as an event handler, then you will act correctly.

 

KOL / MCK User Guide - Created by Carl Peeraer - Diamant Soft, based on the work of Vladimir Kladov - Artwerp.be

  

Keyboard Navigation

F7 for caret browsing
Hold ALT and press letter

This Info: ALT+q
Nav Header: ALT+n
Page Header: ALT+h
Topic Header: ALT+t
Topic Body: ALT+b
Exit Menu/Up: ESC