PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2024 → WinDev 7.1 Method Binding Policy
WinDev 7.1 Method Binding Policy
Débuté par Simon Grantham, 20 mai 2003 11:27 - Aucune réponse
Posté le 20 mai 2003 - 11:27
WinDev 7.5 dynamically binds a method call to the method in the most derived
class of in which the method can be found. That is, the actual class of
an object, not the stored class of a reference to an object. If the method
cannot be found in the actual class of the object, a search is made back
through the parents to the root. However, in the case of searching back
through polymorphic classes, only the first defined class is looked at. For
example:

C1 is Class
END
PROCEDURE C1::Display()
Info("Class1")

C2 is Class
object C1
END
PROCEDURE C2::Display()
Info("Class2")


C3 is class
object C1
END
PROCEDURE C3:Display()
Info("Class3")

C4 is class
object C2
object C3
END

The method display defined in C3 cannot be accessed from anywhere except
class C3 or derivations from C3, not even references to C3 whose actual objects
are not derived from C3 in the earlies path. For example:

Tmp1 is C4 dynamic = new C4
Tmp3 is C3 dynamic = Tmp1

Tmp1:Display() // This will display "Class 2"
Tmp3:Display() // This will also display "Class 2"!

However, if the no reference is found going back to the base class, WinDev
will look at the reference class next before searching up from the base class.
So for instance, if you remove PROCEDURE C1:Display(), then the results will
be different:

Tmp1 is C4 dynamic = new C4
Tmp3 is C3 dynamic = Tmp1

Tmp1:Display() // This will display "Class 2"
Tmp3:Display() // This will display "Class 3"



Another issue the has come up with WinDev 7.5 is the removal of the syntax:

MyDerivedClassInstance:MyBaseClass::MyBaseClassMethod()

This permitted the calling of the base class method for an object instance
that was not the "object" object. This can no longer be done. Calling a
base class method from a derived class can now only be done with the instance
object of the class method.
I.E. only :MyBaseClass::MyBaseClassMethod() is permitted.


Approaches:

A. Use of Scope Operator ("::")

The most dangerous part of WinDev binding is that a base class in the form
of a library cannot execute its own code if a derived class happens to override
it. For example, a basic stack class defined as follows:

StackableItem is class
Next is object dynamic
END

Stack is class
TopOfStack is object dynamic
END
PROCEDURE Stack::Add(AStackableItem)
AStackableItem:Next = :TopOfStack
:TopOfStack = AStackableItem


would fail to execute if the user of a class (or some derived class way down
in the class hierarchy) happened to define a class method call Add. Any
attempt to call the Stack::Add would be superceded (even from within Stack).

This problem can be reduced using the scope definition operator "::" from
within a base class in order to force correct operation at least from within
the class. [This is not presently possible due to a bug in WinDev which
prevents you from specifying your own class scope as a class scope method
override. However you can define an outer (derived) protecting class which
merely relays calls to the inner (parent) class.] This protects the class
itself from having its own internal operations inadvertently overridden.
For example:

StackableItem is class
Next is object dynamic
END

InStack is class
TopofStack is object dynamic
END
PROCEDURE InStack::Add(AStackableItem)
AStackableItem:Next = :TopOfStack
:TopOfStack = AStackableItem


Stack is class
END
PROCEDURE Stack::Add(AStackableItem) // This ones redundant
:InStack::Add(AStackableItem)
PROCEDURE Stack::AddTwo(Item1, Item2) // But this ones not
:InStack::Add(Item2) // protected
by forcing the call to InStack's Add routine, not a derived routing
:InStack::Add(Item1) // Ditto

B. Avoid Derivations for Container Classes

The previous "Stack" examples used a "StackableItem" for keeping stacking.
This means that stackable objects must be derived from StackableItem. Any
class that keeps references to other classes should not do so in the form
of derived classes but should keep such objects as foreign. Stack then becomes:

StackableItem is Class
Next is StackableItem
Storage is object
END

InStack is class
TopofStack is StackableItem
END
PROCEDURE InStack::Add(Item)
Top is StackableItem dynamic = new StackableItem
Top:Storage = Item
Top:Next = :TopOfStack
:TopOfStack = Top

Stack is class
END
PROCEDURE Stack::Add(AStackableItem) // This ones redundant
:InStack::Add(AStackableItem)

Finally, when defining libraries, it would make sense to use a helpful yet
unique naming convention to preclude the unexpected. For example, it is
highly unlikely someone would override stkADD for stack ADD.