A.M. Hoornweg 144 Posted August 11, 2021 (edited) Hello all, I recently stumbled upon some code whose syntax was new to me. That doesn't happen too often so I'm slightly overwhelmed. How do you call this elegant way of declaring constants, and is it documented somewhere? I especially like the implicit association between a type and values. Type tSomeType=( begindoc=$01, Newpage=$02, enddoc=$03 ); Edited August 11, 2021 by A.M. Hoornweg Share this post Link to post
Uwe Raabe 2058 Posted August 11, 2021 Just now, A.M. Hoornweg said: is it documented somewhere Yes, here: Enumerated Types with Explicitly Assigned Ordinality Share this post Link to post
A.M. Hoornweg 144 Posted August 11, 2021 3 minutes ago, Uwe Raabe said: Yes, here: Enumerated Types with Explicitly Assigned Ordinality Thank you! So if I understand correctly, it's just an enum with explicitly defined integer values instead of the default 0...X sequence that the compiler would otherwise generate. Too bad, my first impression was that the constants had an implicit associated data type (integer) and that I could use it for stuff like Type tnumerals=( one='uno', two='due') but that clearly isn't the case. Too bad. But still, I think the syntax is very handy for some of my purposes. Share this post Link to post
David Heffernan 2345 Posted August 11, 2021 50 minutes ago, A.M. Hoornweg said: But still, I think the syntax is very handy for some of my purposes. Explicit ordinal values tends to be used for interop with external libs. It's rarely useful for pure delphi code. Share this post Link to post
dummzeuch 1505 Posted August 11, 2021 Note though that this kind of enums has only limited support in RTTI. btw: This has been available since Delphi 6, so you are rather late to the party. 😉 Share this post Link to post
A.M. Hoornweg 144 Posted August 11, 2021 1 hour ago, David Heffernan said: Explicit ordinal values tends to be used for interop with external libs. It's rarely useful for pure delphi code. I very often have the case that I need to parse records in files and data streams where some integer field identifies the type of content that follows. Some of them were generated by software of my own, some by others. So for that, it is eminently useful: Instead of declaring tons of constants with prefixes to clarify the context they apply to, one just declares an enum which locks the constants into a common namespace. For example, look at what Borland did a long time ago in units System.pas and Variants.pas. It's full of prefixed constants like VarEmpty, VarNull, VarInteger .... where a single enum type tVariantType= (Empty=0, Null=1, ...) would have been much prettier. This example comes to mind because I need to decode and encode variants quite often. 1 Share this post Link to post
Fr0sT.Brutal 900 Posted August 11, 2021 (edited) 2 hours ago, David Heffernan said: Explicit ordinal values tends to be used for interop with external libs. It's rarely useful for pure delphi code. I used to have enums starting from 1 when I needed 0 value to have "null" meaning so that empty structures would be inited with "null". However, I didn't want that null belong to enum itself. So I did TEnum = (enOne = 1, enTwo, ...) enNull = TEnum(0) However, this is not portable (FPC appears much more strict regarding range checking) and lacks RTTI which I use widely so I changed declarations to TEnumNullable = (enNull, enOne, enTwo, ...) TEnum = enOne..High(TEnumNullable) Edited August 11, 2021 by Fr0sT.Brutal Share this post Link to post
A.M. Hoornweg 144 Posted August 11, 2021 I just tried if succ() and pred() work correctly with eplicit ordinal values if there are gaps between the numbers. They don't. Too bad, it would have been totally cool. Share this post Link to post
David Heffernan 2345 Posted August 11, 2021 4 hours ago, A.M. Hoornweg said: For example, look at what Borland did a long time ago in units System.pas and Variants.pas. This is interop. Share this post Link to post
Guest Posted August 12, 2021 On 8/11/2021 at 10:23 AM, David Heffernan said: Explicit ordinal values tends to be used for interop with external libs. It's rarely useful for pure delphi code. type myEnum = (meFirst = 0, meSecond, meThird); ... myUnitExternalButCompiledArray[Ord(myEnum)] ... Pure Delphi. Useful or "anti-pattern"? Please note that this is not a flame, it is a sincere question. Regards, /D Share this post Link to post
David Heffernan 2345 Posted August 12, 2021 1 hour ago, Dany Marmur said: Useful or "anti-pattern"? You tell me. What is the use here? You have not explained the intention. Share this post Link to post
Remy Lebeau 1400 Posted August 12, 2021 5 hours ago, Dany Marmur said: type myEnum = (meFirst = 0, meSecond, meThird); Enums always start at 0 implicitly, unless explicitly stated otherwise. 5 hours ago, Dany Marmur said: Pure Delphi. Useful or "anti-pattern"? Nothing wrong with using an enum for array indexes, provided the enum elements start at 0 and are sequential, which is the default behavior. type myEnum = (meFirst, meSecond, meThird); myUnitExternalButCompiledArray[meFirst] myUnitExternalButCompiledArray[meSecond] myUnitExternalButCompiledArray[meThird] var e: myEnum; e := ...; myUnitExternalButCompiledArray[Ord(e)] Share this post Link to post
Guest Posted August 13, 2021 So writing "= 0" is similar to "explaining variables" IMHO. Not the worst. Share this post Link to post
dummzeuch 1505 Posted August 13, 2021 59 minutes ago, Dany Marmur said: So writing "= 0" is similar to "explaining variables" IMHO. Not the worst. Actually, it might cause an enum to not have RTTI: "Enumerated constants with a specific value [...] do not have RTTI. (from http://docwiki.embarcadero.com/RADStudio/Sydney/en/Simple_Types_(Delphi)#Enumerated_Types_with_Explicitly_Assigned_Ordinality ) (I didn't check this.) Share this post Link to post