Prof A Olowofoyeku (The African Chief) wrote:
On 25 Apr 2003 at 2:27, Frank Heckenbach wrote:
[...]
Sure, storing them is easy. The question is what to do with them afterwards?
That can be left to the programmer to do something with it, or to do nothing with it. Never underestimate the ability of programmers to do something with something ;-/
Sorry, such blanket statements don't impress me.
Each to his own - but I don't think anyone person can presume to know what any number of other people could do with any particular feature in a piece of software.
Congratulations! You have just found a reason to include any feature at all into any programming language.
Seriously, when discussing the merits of some feature, we must at least consider it concretely. Just saying someone may be able to do something with it is pointless.
Of course one may know what one would prefer for others not to do - but in the end, people will do what they choose/need to do. So, if you can store the integer values, please store them. Others can then decide for themselves what (if any) they want to do with it.
Why don't they compile the application with debug info and read the necessary information from there at runtime? Sure, this is fragile and system-dependent and perhaps more or less undocumented and what not, but it's the same if I just store the values in the VMT, without any guarantee of where and how to access them or whether it may change anytime.
The point is that there is no documented way to retrieve them (at least not AFAIK -- the BP documentation doesn't contain any, and you didn't tell me any so far either).
[...]
Type TMethodType = Procedure (Sender : pObject);
So, you don't make it dependent only on the programmer's "discipline", but also on the internals (here, calling conventions of methods).
I am not sure what the objection is here. This is precisely how BP's OWL framework and Delphi's VCL framework operate. You might not like it, and it might prove restrictive for programmers who would like to do things differently, but BP and Delphi programmers have been coping quite well for a very long time.
Yes, BP and Delphi do much other dirty stuff as well. In almost all cases I've seen so far, there was a clean, "Pascalish" and easier to use alternative available. E.g., dynamic sized memory allocation with `GetMem' and `SizeOf' vs. schemata. Or how about being able to pass local routines as procedural parameters only by using hand-written assembler code (as they do in at least one of their famous class libraries, quite likely in each of time), because doing it in plain Pascal (which is according to classic Pascal, not even EP) doesn't work in BP ...
My impression is that they're just too lazy to implement the nontrivial features of Pascal. (No news so far, I know.) But even if they find they'd need them in their own code, they do not finally implement them, but invent some dirty work-around (which then spreads to their users and spoils many more people's programming habits).
I hope you understand now why I'm so allergic to this "that's how Borland does it" argument. When discussing the usefulness of some feature, more often than not that's an indication of bad design it seems ...
If they ever change, this will just break.
It never changed in BP's OWL, and it will never change in Delphi's VCL.
Uhm, the calling convention is defined by the compiler, not the library. When it changes in the compiler (or some other compiler uses another one), the library will silently break. Apparently you don't mind code that silently breaks, but for me that's one of the worst kind of bugs.
I am not expecting mine to change either. In any case, anything can change in any library, OOP framework, or software. If that happens, people have the option of not upgrading to the new version (just like some BP programmers decided to ignore Delphi),
Apparently they don't mind to create some dead-ends (like so much proprietary software). In contrast, we should try to design our features in a future-proof way, so that they will not force some people to keep using old versions when something changes ...
or making the necessary changes in their code.
After probably some hours of debugging to find out what went wrong, and a number of "bug" reports sent to the wrong places ...
This is not rocket science, and it happens everywhere - in gcc, gpc, and many other things.
Fortunately it isn't rocket science. Anyone who programs rockets (or any real machinery) with such fragile code will not keep their jobs very long I hope.
"my_integer" can be any integer value that I choose (and of course there is no way for Borland to predict what it will be). Yet I know that whenever the user clicks on or selects a control or menu item with the ID of "my_integer", then my method "foo" will be executed. I don't have to bother myself with a case statement, or anything other than to have my method in the format described above. I am not sure that I understand what is so objectionable about this.
- It's type unsafe. As I said a lot of times now (and would like to repeat again and again), type-unsafety means, sooner or later, mysterious crashes and some nice time spent with the debugger (low-level, even).
- The mechanism to access them via procedural types (as you described, and I don't know a better way) adds another type-unsafety. (Though at least this one, in constrast to the first one, might affect only the library author, not every user of it.)
- It's probably less efficient. I didn't check exactly (which might require debugging such a program on the assembler level), but in the documentation there are some indications that they use a linear search loop whose time used is roughly proportional to the number of indices that exist (whereas a `case' statement can run in constant time). If there are only a few indices, it doesn't matter, but AFAIUI, there are usually a lot of them, so the speed difference might be significant.
- They apparently use an undocumented feature to retrieve the information (at least BP doesn't have a `GetMethodPtr', don't know about Delphi).
- Actually, it's not only only undocumented, but contrary to the documentation. According to the documentation of BP 7 the only difference to virtual methods is that dyanamic methods may save memory. (So if someone takes the documentation for what it says, they might choose to remove the indices because they don't care about memory usage and they feel the code becomes more readable without them or want it to run a little faster or for whatever reason, and the code will break, altough according to the documentation it should behave the same -- only perhaps run faster and take more memory.)
Enough for a start? ;-)
I suppose a more useful feature for this goes in the direction of procedural types for object methods (which may have some nontrivial aspects, which may be why they didn't choose to implement them).
I haven't checked the details -- if they don't suffice it may be necessary to do some pre-compiling step (which, e.g. scans the source code for those IDs and generates the `case' statement or whatever). With their RAD tools, it would probably be easy (since it works pre-compile, anyway). For a non-RAD programming environment, it may be a little new (though it could be mostly hidden from the user as part of their "automake" mechanism). Even if there would be a little inconvenience (such as slightly longer build time), that's still much better than using an inherently unsafe mechanism.
Frank