Jump to content

Recommended Posts

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 by Mike Torrettinni

Share this post


Link to post

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

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

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 by Attila Kovacs
  • Like 1
  • Thanks 1

Share this post


Link to post

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;

 

 

 

  • Like 1
  • Thanks 1

Share this post


Link to post

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

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
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
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.

 

  • Like 2
  • Thanks 1

Share this post


Link to post
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.

  • Like 4

Share this post


Link to post
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
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
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

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
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 by Edwin Yip

Share this post


Link to post

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.

  • Haha 1

Share this post


Link to post
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

Following on from my comment about complexity, I'm wondering what's wrong with this:


image.thumb.png.ea548dfd0cd52e4cbe6560bedec15168.png
 

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 by David Heffernan
  • Like 4

Share this post


Link to post

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
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.

  • Like 2

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×