I took a brief respite from WDIAHAD to get caught up on some other content and try to get this site updated to the latest version of Confluence. I'm still working on the upgrade - I'm having some issues with PostgreSQL on my test VM - but hopefully I'll get that sorted out shortly.
In any case, in my last instalment I was having problems writing a class where I wanted to pass the class's instance to another object. I couldn't figure out the WinDev equivalent to "self" or "this". Peter Holemans came to the rescue and told me the keyword I was looking for was "object".
I also got some justifiable questions and criticisms about my class actually needing to pass itself to another class. So let me explain.
Here's the class:
I'm using this class to create a doubly-linked list, so that each node will have a reference to the node (if any) that comes before and/or after.
This is a pretty terrible example, really. In general I think it's a bad idea for an object to pass itself to another object; the only reason I'm allowing it here is because that other object is just another instance of the same class.
So allow me a little digression on why passing "self" isn't usually a good thing; further, I hope those of you who are non-Clarion folk will pardon the source of the example, which is the the ABC class library.
Among the many ABC classes are a WindowManager class and a BrowseClass. The WindowManager largely handles events and manages control updates including refreshing browses when some relevant data has changed. BrowseClass mainly manages the display of browse contents.
But there's something curious - the BrowseClass Init methods both take a WindowManager object as a parameter.
I think of browses as being subordinate to windows, so to my mind the WindowManager is the higher level, "containing" object, while the BrowseClass is the lower level, "contained" object. Logically, I'm going to have one window manager for my window, but I could have multiple browses, each with their own BrowseClass instance. So I can compose a functioning window using a WindowManager that manages one or more BrowseClasses and probably some other objects as well.
One of my rules of thumb is that objects that are contained by other objects should never need to know anything about their containers.
My purpose here isn't to dump on the ABC class library design - for its day, it was pretty good. But as soon as you give a "contained" object carnal knowledge of its container, a couple of bad things happen:
- The contained object can work in secret on the container. Well, not really in secret, at least not if you have the source code, but when you're working at the container level you don't know what the contained object is doing to the container. This makes the code much less readable.
- The contained object has a dependency on the container. What if you want to use the BrowseClass on its own, or without a window manager class? Can't be done. Reusability is severely compromised.
The Node class above doesn't introduce either of these problems since it's only passing its own instance to another instance of the same class.
Other interesting bits
WinDev lets you declare constants in classes, which is the best place to put constants that are specific to a class's usage:
Code Block |
---|
MyClass is class
CONSTANT StringType = "string"
CONSTANT IntType = "int"
END |
Very useful, that.
Object references can be low/weak or strong. From the docs:
- The strong reference (by default): In this case, the class object will be freed only when all the references of the object are freed.
- The low reference: In this case, the objects will be automatically freed according to their scope (even if a global reference was taken on these objects). The low reference must be specified during the dynamic instantiation of the object taking reference.
I tried to think of a scenario where I'd want to use a low reference but I couldn't come up with anything that sounded plausible. If you've ever had a reason to use a low reference, please comment!
The reference assignment operator is <-
Multiple inheritance vs interfaces
WinDev does not, as near as I can tell, offer support for interfaces. It does, however, support multiple inheritance, where one class can be derived from two or more classes. .
Both multiple inheritance and interfaces enable a lot of flexibility in class design. Multiple inheritance is a more powerful technique that is often criticized for introducing too much complexity. I've used interfaces (in Clarion, Java and C#) so that's what I'm used to, and at first I was a bit perturbed to see that they weren't implemented in WinDev. But multiple inheritance should certainly fill the void in most situations where you might think about using an interface.
The importance of object-oriented programming
The tutorial devotes only three pages to OOP; that shouldn't be an indication of how much time you should be spending writing object-oriented code. I'm pretty much a broken record on this subject, but I really believe that as much as possible, your business logic belongs in classes; all you should have in the embed points is the bare minimum of code needed to wire up your classes for use in the app.