My guest post from L.V. didn't seem to have enough Delphi specifics for one commenter, so I thought about it, and realized, that what L.V. is talking about is Practices (stuff people do), not features.
But there are features in Delphi that I think are either over-used, or used inappropriately, or used indiscriminately, or which should almost never be used, since better alternatives almost always will exist. Time for that list. No humorous guest-posting persona for this post, sorry, just my straight opinions.
1. WITH statement
This one is hardly surprising to be in the list, as it's one of the most controversial features in the Delphi language. I believe that it is almost always better to use a local variable with a short name, creating an unambiguous and readable statement, instead of using a WITH. A double with is much more confusing than a single WITH, but all WITH statements in application layer code should be eliminated, over time, as you perform other bug fix and feature work on a codebase.
2. DFM Inheritance
I don't mind having TApplicationForm inherit non-visually from a TApplicationBaseForm that doesn't have a DFM associated with it, but I find that maintenance and ongoing development of forms making use of DFM inheritance is problematic. There can be crazy issues, and it's very difficult to make changes to an upstream form and understand all the potential problems downstream. This is especially true when a set of form inheritances grows larger. I have even forced non-visual-inheritance using an interposing class, and found that IDE stability, and ease of working with a codebase is improved.
3. Frames
The problems with frames and with DFM-inherited are overlapping, but Frames have the additional troubling property of being hard to make visually fit and look good. You can't really assume that any change in the base frame control's original positions will be overridden or not, you just don't know. Trying to move anything around in a frame is an exercise in frustration. I prefer to compose parts of complex UIs at runtime instead of at designtime.
4. Visual Binding
I have had nothing but trouble with Visual Binding. It seems that putting complex webs of things into a design-time environment is not a net win for readability, clarity, and maintainability. I would rather read completely readable code, and not deal with bindings. Probably there are some small uses for visual binding, but I have not found them. My philosophy is to avoid it. It's a cool feature, when it works. But the end result is as much fun as a mega-form.
5. Untyped Parameters in User Procedures or Functions
Modern Pascal should be done with PByte rather than the old way of handling "void *" types (if you know C) in Pascal is the untyped var syntax. If possible, I prefer to use PByte which I consider much more modern way of working. I believe the two are more or less equivalent in capabilities, and that Delphi still contains untyped var params for historical compatibility reasons, but unless I'm writing a TStream and must overload a method that already has this signature, I prefer not to introduce any more anachronisms like that in my code.
6. Classic Pascal File IO Procedures
Streams should have replaced the use of AssignFile, Reset, Rewrite, CloseFile.
7. Unnecessary Use of Pointer Types and Operations in Application Layer Code
In low level component code, with unit tests, perhaps sometimes, pointer types and operations will be used. To implement your own linked list of value types which are not already implicitly by reference, but in application layer (form, data module) code that most Delphi shops spend 90% of their time, introducing raw pointer operations into the application code is almost always going to make me require it to be changed, if I'm doing a code-review. Delphi is a compiled "somewhat strongly typed" language, and I'm most happy with application layer code that does not peel away the safety that the type system gives me.
8. Use of ShortString Types with Length Delimiters, in or out of Records
Perhaps in the 1980s, a pascal file of a record type, with packed records made sense. These days, it's a defect in your code. The problem is once such a pattern is in your code, it's very difficult to remove it. So while an existing legacy application may contain a lot of code like that, I believe a "no more" rule has to be set up, and module by module, the unsafe and unportable stuff will have to be retired, replaced, or updated. The amount of pain this kind of thing causes in real codebases that I have seen that used it, is hard to overstate.
9. Use of Assignable (Non Constant) Consts
A compiler flag {$J+} in Delphi allows constants to be overwritten. It should never be used.
But there are features in Delphi that I think are either over-used, or used inappropriately, or used indiscriminately, or which should almost never be used, since better alternatives almost always will exist. Time for that list. No humorous guest-posting persona for this post, sorry, just my straight opinions.
1. WITH statement
This one is hardly surprising to be in the list, as it's one of the most controversial features in the Delphi language. I believe that it is almost always better to use a local variable with a short name, creating an unambiguous and readable statement, instead of using a WITH. A double with is much more confusing than a single WITH, but all WITH statements in application layer code should be eliminated, over time, as you perform other bug fix and feature work on a codebase.
2. DFM Inheritance
I don't mind having TApplicationForm inherit non-visually from a TApplicationBaseForm that doesn't have a DFM associated with it, but I find that maintenance and ongoing development of forms making use of DFM inheritance is problematic. There can be crazy issues, and it's very difficult to make changes to an upstream form and understand all the potential problems downstream. This is especially true when a set of form inheritances grows larger. I have even forced non-visual-inheritance using an interposing class, and found that IDE stability, and ease of working with a codebase is improved.
3. Frames
The problems with frames and with DFM-inherited are overlapping, but Frames have the additional troubling property of being hard to make visually fit and look good. You can't really assume that any change in the base frame control's original positions will be overridden or not, you just don't know. Trying to move anything around in a frame is an exercise in frustration. I prefer to compose parts of complex UIs at runtime instead of at designtime.
4. Visual Binding
I have had nothing but trouble with Visual Binding. It seems that putting complex webs of things into a design-time environment is not a net win for readability, clarity, and maintainability. I would rather read completely readable code, and not deal with bindings. Probably there are some small uses for visual binding, but I have not found them. My philosophy is to avoid it. It's a cool feature, when it works. But the end result is as much fun as a mega-form.
5. Untyped Parameters in User Procedures or Functions
Modern Pascal should be done with PByte rather than the old way of handling "void *" types (if you know C) in Pascal is the untyped var syntax. If possible, I prefer to use PByte which I consider much more modern way of working. I believe the two are more or less equivalent in capabilities, and that Delphi still contains untyped var params for historical compatibility reasons, but unless I'm writing a TStream and must overload a method that already has this signature, I prefer not to introduce any more anachronisms like that in my code.
6. Classic Pascal File IO Procedures
Streams should have replaced the use of AssignFile, Reset, Rewrite, CloseFile.
7. Unnecessary Use of Pointer Types and Operations in Application Layer Code
In low level component code, with unit tests, perhaps sometimes, pointer types and operations will be used. To implement your own linked list of value types which are not already implicitly by reference, but in application layer (form, data module) code that most Delphi shops spend 90% of their time, introducing raw pointer operations into the application code is almost always going to make me require it to be changed, if I'm doing a code-review. Delphi is a compiled "somewhat strongly typed" language, and I'm most happy with application layer code that does not peel away the safety that the type system gives me.
8. Use of ShortString Types with Length Delimiters, in or out of Records
Perhaps in the 1980s, a pascal file of a record type, with packed records made sense. These days, it's a defect in your code. The problem is once such a pattern is in your code, it's very difficult to remove it. So while an existing legacy application may contain a lot of code like that, I believe a "no more" rule has to be set up, and module by module, the unsafe and unportable stuff will have to be retired, replaced, or updated. The amount of pain this kind of thing causes in real codebases that I have seen that used it, is hard to overstate.
9. Use of Assignable (Non Constant) Consts
A compiler flag {$J+} in Delphi allows constants to be overwritten. It should never be used.