Jump to content

Recommended Posts

1. You cannot extend a set of constants if they are defined in a record type in a third party library. There is no record inheritance.

2. An enumeration give us more type safety than a set of integer constants.

3. Scoped enumerations.

4. I like prefixes. But if not, see 3.

 

I use enums with 100 or more members. If instead of them I used named integer constants, adding and subtracting them, there would be many hard-to-find errors.

Edited by Kryvich
  • Like 1

Share this post


Link to post

When I need to add a new member to the enum, I ... just insert the new member into the enum. If I had a set of named constants, I would have to renumber all the constants starting from the insertion position.
So what about extensibility?

  • Like 1

Share this post


Link to post
21 minutes ago, Kryvich said:

1. You cannot extend a set of constants if they are defined in a record type in a third party library. There is no record inheritance.

2. An enumeration give us more type safety than a set of integer constants.

3. Scoped enumerations.

4. I like prefixes. But if not, see 3.

 

I use enums with 100 or more members. If instead of them I used named integer constants, adding and subtracting them, there would be many hard-to-find errors.

Why do you need to inherit records?

 

If I know the value of the constant, I don't need anything else.


Also, no one forbids transferring the api header files.

Take tlb for example, constants are beautifully declared in it.
Within the module. Can be within a record or class.

 

When I use Windows dll I can perfectly use the constants from the header file.

Edited by Marat1961

Share this post


Link to post
13 minutes ago, Kryvich said:

When I need to add a new member to the enum, I ... just insert the new member into the enum. If I had a set of named constants, I would have to renumber all the constants starting from the insertion position.
So what about extensibility?

Or you can add a new value to the end of the list.

For example, we take Google protocol buffer, where tags are used to identify fields.
Do not touch the old field identifiers unless you want to break anything.

Share this post


Link to post
27 minutes ago, Kryvich said:

Scoped enumerations.

If you put in a record or a class, the type name will be a namespace.
To refer to a constant you use the dot notation

Record_type.Constant_name

Share this post


Link to post
55 minutes ago, Kryvich said:

I use enums with 100 or more members. If instead of them I used named integer constants, adding and subtracting them, there would be many hard-to-find errors.

I remember where I had to use an enumerated type of this size.
Probably the largest type is tokens in the parser.
But now I use the compiler of the compiler.

In my opinion, when there are a lot of objects, they no longer work by name. The head and brains do not need to be overloaded.

For identification, you already need to use handlers.
So that there is no desire to cope with them, you can put the whole in the record.

   hParam = record
     v: Cardinal;
   end;
   hParamHelper = record Helper for hParam
     constructor From (v: Cardinal);
     function request: hRequest; inline;
   end;

or they write well here
http://gamesfromwithin.com/managing-data-relationships

Share this post


Link to post

Members of an enum are not objects. For ex. I have IDs of syntax relations of words in a natural language (about 200 IDs). The numerical values of the enumeration members are not important to us, only their names matter. Therefore, there is no need to specify integer values for each member of an enum in your program.

 

1., 2., 3., 4. - it was the answer to the words of Wirth, which you quoted earlier.

Quote

If I know the value of the constant, I don't need anything else.

Enumerations were invented in order not to use ordinalities of its members directly. And so as not to (accidentally) add, subtract and divide them like numbers. This is Pascal where type safety matters.

Quote

Also, no one forbids transferring the api header files.

Take tlb for example, constants are beautifully declared in it.

Headers can use enums as well. It depends on how the С-language headers are translated into Pascal code.

Quote

Do not touch the old field identifiers unless you want to break anything.

With enumerations, you can reorder old values as you want. And nothing will break if the ordinalities are not directly used anywhere.

Quote

If you put in a record or a class, the type name will be a namespace.

Overcomplication, misuse of software entities.

  • Like 2

Share this post


Link to post

Interesting philosophical discussion.

I like and use enums heavily, always with full scope and "T"-named for safety reasons (to avoid cases as in the start of this thread).
Of course I know some people like the "non-prefixed" version of everything,  this I think leads to many issues.


On the other hand, the record proposal from @Marat1961 is worth considering too, as a good 2nd alternative.

Maybe they can nicely coexist both, with their pros and cons, I won't fell disturbed too much.

 

I see also one very practical benefit that speaks for enums nowadays:  They can use class helpers.
From that I make also heavy use, leading to focus code where it belongs to.
I'm not 100% sure, since I never checked that, but I think class helpers won't work on consts.

Share this post


Link to post
15 hours ago, Stefan Glienke said:

And I thought enums and the possibility to build sets of enums is one of those unique features in Delphi that many other languages such as C++ don't have hence you have to and/or with damn bitmasks....

+1. The most useful and powerful Delphi feature which I miss in other languages. These bunches of constants are just ugly and - what's more important - they do not allow type checking.

  • Like 1

Share this post


Link to post
3 minutes ago, Fr0sT.Brutal said:

+1. The most useful and powerful Delphi feature which I miss in other languages. These bunches of constants are just ugly and - what's more important - they do not allow type checking.

Exactly - my most stupid and most difficult to find mistakes in OpenGL came from using wrong constant (with similar name to the correct one).

Share this post


Link to post

A pitfall with Enums is that they are so easy to change.  Add another member in the middle of the list, and you have changed the ordinal value of the rest.

This is fine if you only use the enumerated reference inside your application, but if you use the ordinal - f.x. when saving to/retrieving from a database, or when transmitting to another system - you get into trouble.

 

 

Share this post


Link to post

Yes, but that may happen too when you insert a new value in a consts list, and re-order their values to make it ordered more nicely.

Exactly such cases I handle in the enum itself by class helpers ToXxx and FromXxx.

 

Working with number ranges inside an enum, I can even implement a "poor man's grouping", like

enum     0 ...   99 ==> Isgroup1

enum 100 ... 199 ==> Isgroup2

 

All this well supported by class helpers, with least memory footprint.

Edited by Rollo62

Share this post


Link to post
24 minutes ago, Lars Fosdal said:

A pitfall with Enums is that they are so easy to change.  Add another member in the middle of the list, and you have changed the ordinal value of the rest.

This is fine if you only use the enumerated reference inside your application, but if you use the ordinal - f.x. when saving to/retrieving from a database, or when transmitting to another system - you get into trouble.

 

 

You can use:

type tTestEnum = (None=0, One=1, Eight=8);

 

Edited by Vandrovnik

Share this post


Link to post
8 minutes ago, Vandrovnik said:

You can use:


type tTestEnum = (None=0, One=1, Eight=8);

 

 

Which causes problems for RTTI.

Share this post


Link to post
1 hour ago, Lars Fosdal said:

if you use the ordinal - f.x. when saving to/retrieving from a database, or when transmitting to another system - you get into trouble.

If you use ordinal values of an enum you already are likely to get into trouble, not talking about data exchange with other systems.

Share this post


Link to post

Well, it is all about littering the code with comments like "do not remove or reorder elements" 😛

Share this post


Link to post
1 hour ago, Lars Fosdal said:

Well, it is all about littering the code with comments like "do not remove or reorder elements"

Hmm, I think of enums like of an abstraction. I don't care what number has "enumFoo", I often won't notice if it had no number at all. All I want is that "enumFoo" is member of type "TEnumFoo" and (sometimes) that it goes after "enumLaz" and before "enumBar". If I need to let it go beyond my application, I'll use its string name "enumFoo" or special string from "FooNames: array[TEnumFoo] of string". Number values are applied only when I'm sure the definition of enum is consistent (f.ex., between two apps of the same complex).

  • Like 2

Share this post


Link to post
3 hours ago, Lars Fosdal said:

This is fine if you only use the enumerated reference inside your application, but if you use the ordinal - f.x. when saving to/retrieving from a database, or when transmitting to another system - you get into trouble.

It is why textual exchange and API formats were invented. XML, JSONYAML. It's why Microsoft replaced the binary format DOC with DOCX. Do not pass an enumeration member by its numeric value, use its name.

  • Like 1

Share this post


Link to post

As for its own database, the program may store the enumerations in a field of any type: text, binary. But if a programmer chooses the binary format, then it is his responsibility to correctly interpret the stored data. It is possible, for example, to add a format version to the database and interpret the stored data accordingly.

Share this post


Link to post
41 minutes ago, Kryvich said:

Do not pass an enumeration member by its numeric value, use its name.

Yes, but also names might change over time, so thats no real benefit over numbers.

All right, numbers have a higher risk of being re-ordered, but in principle: "enums might change over time".

 

Thats on reason why I prefer the conversion logic nearby, in enum's class helper itself.
There I have only one point of logic, where I could even do some conversion corrections from different enum-type versions.

 

Edited by Rollo62

Share this post


Link to post
17 hours ago, Kryvich said:

 

 

17 hours ago, Kryvich said:

Overcomplication, misuse of software entities.

That is, you so interpret the declaration of constants inside the record?

Share this post


Link to post

Don't take it to heart. Sometimes it is difficult to find the right English words, which makes my sentences sound too categorical.

Share this post


Link to post
18 hours ago, Kryvich said:

Members of an enum are not objects. For ex. I have IDs of syntax relations of words in a natural language (about 200 IDs). The numerical values of the enumeration members are not important to us, only their names matter. Therefore, there is no need to specify integer values for each member of an enum in your program.

I am not forcing you to use this programming style.
In my programs at the domain level, I also make extensive use of enumerated types.
I consider it permissible to use them even in the library if it is available in the source.
But knowing the pitfalls of using them is probably not bad.

Niklaus Wirth for me is a GURU of the highest level

 

I would have already thought about their organization and semantic separation.
It is possible that these names should be organized into some taxnomy, and maybe even more than one.

And what kind of subject area, knowledge base?
May I have a look at the code of your project?
Type declarations and how you use them.

 

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

×