Mike Torrettinni 198 Posted October 13, 2020 (edited) I use a lot of enums and was thinking if there is better to way to 'find' the proper enum to be used. So, I was thinking something like this for THTMLType enum: THTMLType = (htTemplate, htStatic, htHeader, htCustom); TReportEnums = record HTML: THTMLType; end; var gEnums: TReportEnums; and used like this: vHTMLReportType := gEnums.HTML.htTemplate; If I try I get error: E2018 Record, object or class type required, on HTML. . Edit: I would like to have something that could use code completion, so I don't need to remember htTemplate. I would type Enums. and I would select among options HTML. and then I would see THTMLType options... Any suggestions, or this is just not possible? Edited October 13, 2020 by Mike Torrettinni Share this post Link to post
Bill Meyer 337 Posted October 13, 2020 http://docwiki.embarcadero.com/RADStudio/Sydney/en/Scoped_Enums_(Delphi) 1 Share this post Link to post
Lajos Juhász 293 Posted October 13, 2020 Are you loooking for this http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/compdirsscopedenums_xml.html ? The $SCOPEDENUMS directive enables or disables the use of scoped enumerations in Delphi code. More specifically, $SCOPEDENUMS affects only definitions of new enumerations, and only controls the addition of the enumeration's value symbols to the global scope. In the {$SCOPEDENUMS ON} state, enumerations are scoped, and enum values are not added to the global scope. To specify a member of a scoped enum, you must include the type of the enum. For example: {$SCOPEDENUMS ON} type THTMLType = (htTemplate, htStatic, htHeader, htCustom); vHtmlReportType:=THTMLType.htTemplate; // Ok vHtmlReportType:=htTemplate; // [dcc32 Error] Unit1.pas(35): E2003 Undeclared identifier: 'htStatic' Share this post Link to post
Mike Torrettinni 198 Posted October 13, 2020 No, I'm not sure scoped enums is what I need. I would like to have something that could use code completion, so I don't need to remember htTemplate. I would type Enums. and I would select among options HTML. and then I would see THTMLType options... (I added this into first post) I hope it makes sense. Share this post Link to post
Attila Kovacs 629 Posted October 13, 2020 (edited) He wants to _find_ the appropriate enum and not obfuscate it deeper. It should be a task for the IDE which fail big time in it, even the help provided by emba is trying to hide which are the possible values. Still, I would not say that your example is a "better way" but you are mixing variables with types. So it should be something like: type TGEnums = class type THTMLType = (htTemplate, htStatic, htHeader, htCustom); end; var x: TGEnums.THTMLType; begin x := TGEnums.THTMLType.htTemplate; --- or --- type THTMLType = (htTemplate, htStatic, htHeader, htCustom); TGEnums = class type HTMLType = THTMLType; end; var x: THTMLType; begin x := TGEnums.HTMLType.htTemplate; Edited October 13, 2020 by Attila Kovacs 1 1 Share this post Link to post
Darian Miller 361 Posted October 13, 2020 In your example, HTML is a field variable of the TReportEnums structure with the specific type defined to be THTMLType. You are trying to access it as an Enumeration and not as a variable. Delphi offers meta classes where you can define a variable to be a class type such as: TMySomethingClass = class of TMySomething, and you can define a variable of type TMySomethingClass, but this only works with classes. AFAIK there's no similar thing for records. Not a great solution, but if you could group your defines in one class you could get code completion from a master class like: TMasterRecordTypes = class type THTMLType = (htTemplate, htStatic, htHeader, htCustom); TSecondRecordType = (srOne, srTwo, srThree); end; vHTMLReportType := TMasterRecordTypes.THTMLType.htTemplate; Or just put all your related record types into a particular unit and use the unit name as the scope, which is how it's normally done. vHTMLReportType := MyUnitName.THTMLType.htTemplate; 1 1 Share this post Link to post
Darian Miller 361 Posted October 13, 2020 Note: A real good Delphi reference book is "Delphi XE2 Foundations" by Chris Rolliston. Well worth the money and it will help with issues like this. Share this post Link to post
Mike Torrettinni 198 Posted October 13, 2020 This is awesome! It can be defined outside of class, too: type THTMLType = (htTemplate, htStatic, htHeader, htCustom); TGEnums = class type HTML = THTMLType; end; procedure DoIt(aHtml: TGEnums.HTML); begin end; procedure TForm2.FormCreate(Sender: TObject); var x: TGEnums.HTML; begin x := TGEnums.HTML.htTemplate; DoIt(x); DoIt(TGEnums.HTML.htTemplate); end; Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 3 hours ago, Darian Miller said: Or just put all your related record types into a particular unit and use the unit name as the scope, which is how it's normally done. vHTMLReportType := MyUnitName.THTMLType.htTemplate; ...which is how it's normally done. You do this in every case? I only do this when enums are from multiple used units. like BorderStyle := Forms.bsNone; otherwise I never prefix enum with unit name. Share this post Link to post
Darian Miller 361 Posted October 14, 2020 12 minutes ago, Mike Torrettinni said: ...which is how it's normally done. You do this in every case? I only do this when enums are from multiple used units. like BorderStyle := Forms.bsNone; otherwise I never prefix enum with unit name. No, not all the time but the more I do it, the more I like it. You were wanting a better system of not having to remember a specific enumeration like htTemplate. One suggestion was to just create a HTML related unit that contains the main generic HTML related types that you want to use so you can remember the general unit name and then lean on code completion to find the type/enumeration. Create a naming system that you like for these types of units, something like HTMLTypes.pas, HTMLUtils.pas, HTMLShared.pas, or whatever naming style you prefer and then you can type HTMLTypes. and invoke code completion to get all of your shared HTML related types and drill down to the one you want. If you have HTTP related items you also create HTTPTypes.pas (or whatever) and then DBTypes, EmailTypes, etc. These shared units usually have type definitions with little code. One code smell is if you are including a bunch of code in one of these shared units, then that code should be split out to its own unit (likely several new units.) Defining where the code should live is a primary key to the ability to maintain the code over time. It also helps you code much faster if the organization makes internal sense. Choice 1 is one unit with every single line of code. Choice 2 is a separate unit for every class or type definition, no matter how small. There's a balance somewhere in the middle, leaning greatly towards 2. 2 1 Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 (edited) Thanks for detailed explanation. A lot to think about. 🙂 Edited October 14, 2020 by Mike Torrettinni Share this post Link to post
David Heffernan 2345 Posted October 14, 2020 What problem are you trying to solve? What's wrong with vHTMLReportType := htTemplate; Share this post Link to post
Vincent Parrett 750 Posted October 14, 2020 8 minutes ago, David Heffernan said: What problem are you trying to solve? My take is what he really wants in code completion that actually works? It bugs the hell out of me that when I'm typing an assignment statement and the left side is an enum, that code completion offers all sorts of crap that is not relevant. If the type isn't found, tell me that. 4 Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 2 minutes ago, David Heffernan said: What problem are you trying to solve? What's wrong with vHTMLReportType := htTemplate; Nothing is wrong, both cases still work: Procedure(Enums.HTML.htTemplate); or Procedure(htTemplate); In second case I know the exact enum, in first case I can use code completion to help me. Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 1 minute ago, Vincent Parrett said: My take is what he really wants in code completion that actually works? Yes! 🙂 Share this post Link to post
David Heffernan 2345 Posted October 14, 2020 16 minutes ago, Mike Torrettinni said: Nothing is wrong, both cases still work: Procedure(Enums.HTML.htTemplate); or Procedure(htTemplate); In second case I know the exact enum, in first case I can use code completion to help me. You'd be far better off using scoped enumeration. It forces you to fully qualify the enumeration. Instead of deciding what the solution is beforehand, you are better off understanding the options offered by the language and working with the language, not swimming against the tide. Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 14 minutes ago, David Heffernan said: You'd be far better off using scoped enumeration. It forces you to fully qualify the enumeration. Instead of deciding what the solution is beforehand, you are better off understanding the options offered by the language and working with the language, not swimming against the tide. Not sure how would scoped enums help me remember the names to use the correct one... I would still need to remember THTMLType, right? Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 This is working pretty good! Good thing is that this is only enum organization layer, all enums are still outside of class, so still can be used separate. I set a few more enums into Enums class and I can organize enums from multiple units, too. Share this post Link to post
Edwin Yip 154 Posted October 14, 2020 (edited) 2 hours ago, David Heffernan said: You'd be far better off using scoped enumeration. It forces you to fully qualify the enumeration. Instead of deciding what the solution is beforehand, you are better off understanding the options offered by the language and working with the language, not swimming against the tide. But the IDE is the key to be productive. I'd go with the approach suggested by Darian Miller - use unit-scoped enums. Most of the time, enums should be visible to the entire app scope and it's reasonable to put them in a commonly used unit. That being said, I actually have the best option (for this very specific need) to suggest: == Use scoped enums and use CodeInsightPlus to replace the IDE's code-complete. From their product page, it says: Quote Suggest scoped enums Edited October 14, 2020 by Edwin Yip Share this post Link to post
Stefan Glienke 2002 Posted October 14, 2020 Give types a meaningful and obvious name. Then you don't have issues remembering them. 1 Share this post Link to post
Lars Fosdal 1792 Posted October 14, 2020 Well, we have thousands of meaningful and reasonably obvious names (within their context) - but yeah - remembering them gets harder every year. Age takes its toll. 😛 But - Code Insight should work whether you are assigning or passing as a parameter. Unfortunately, it has often put the enumerated values a long way down the list of candidates. We've only started using 10.4.1, so the jury is still out on this issue, but the LSP has been less than rock solid so far. 1 Share this post Link to post
David Heffernan 2345 Posted October 14, 2020 2 hours ago, Mike Torrettinni said: Not sure how would scoped enums help me remember the names to use the correct one... I would still need to remember THTMLType, right? Why is that harder than remembering something else, as you seem to want to do? Why is complexity so compelling? Share this post Link to post
David Heffernan 2345 Posted October 14, 2020 (edited) Following on from my comment about complexity, I'm wondering what's wrong with this: You don't need to remember anything. Why are you seeking complexity here? You seem to be trying to solve a problem that simply does not exist. Edited October 14, 2020 by David Heffernan 4 Share this post Link to post
Mike Torrettinni 198 Posted October 14, 2020 Aha, now I see understand what you are referring to. Well, in my experience, Code completion and Error insight are not most reliable features in Delphi IDE. They might (or not) work in simple unit examples, while a lot of times they break in larger units, or sometimes just a specific definition can break them. The new LSP is supposed to fix (avoid) these issue, but as far as reports go, it is improvement, but still not working 100% of the times. There are issue reports in quality portal on this topic. So, invoking code completion from empty space (like in your example) could/or not work. While code completion from Enums. behaves better, in my experience, works more often. I use Delphi 10.2.3, so code completion could differ between mine and your version. What version are you using? Share this post Link to post
David Heffernan 2345 Posted October 14, 2020 7 minutes ago, Mike Torrettinni said: What version are you using? That's XE7. It seems to me to be folly to design your code based on an IDE tooling issue, and especially one which is soon to be resolved. Further, the issue at stake here, as always when coding, is far less about the experience when writing code, as the experience when reading code. It's not worth it to reduce the readability of your code to give a minor easing to your experience when entering the code. 2 Share this post Link to post