Leif Uneus 43 Posted February 21, 2019 (edited) 6 minutes ago, Lars Fosdal said: Isn't there something weird about RTTI for enums that have manually set ordinal values as well? Define "weird". Enumerations with defined ordinal values do not have RTTI. See http://docwiki.embarcadero.com/RADStudio/en/Simple_Types_(Delphi)#Enumerated_Types_with_Explicitly_Assigned_Ordinality Edited February 21, 2019 by Leif Uneus Share this post Link to post
Lars Fosdal 1791 Posted February 21, 2019 Just now, Leif Uneus said: Define "weird". Enumerations with defined ordinal values do not have RTTI. That is the "weird" right there. Definitively a good reason to avoid defined ordinal values in enumerations. 1 Share this post Link to post
Uwe Raabe 2057 Posted February 21, 2019 35 minutes ago, Lars Fosdal said: Definitively a good reason to avoid defined ordinal values in enumerations. Lately I often use helpers to map those enumerations to their ordinal values. type TEnum = (plough, foo, bar, wtf); TEnumHelper = record helper for TEnum private const FMap: array[TEnum] of Integer = (5, 9, 14, 1000); function GetAsInteger: Integer; procedure SetAsInteger(const Value: Integer); public property AsInteger: Integer read GetAsInteger write SetAsInteger; end; function TEnumHelper.GetAsInteger: Integer; begin Result := FMap[Self]; end; procedure TEnumHelper.SetAsInteger(const Value: Integer); var idx: TEnum; begin for idx := Low(FMap) to High(FMap) do begin if FMap[idx] = Value then begin Self := idx; Exit; end; end; raise ERangeError.CreateFmt('invalid integer for TEnum: %d', [Value]); end; This is pretty simple to use: var enum: TEnum; begin enum.AsInteger := plough.AsInteger + foo.AsInteger; if enum = bar then begin ShowMessage('Hooray!'); end else begin ShowMessage(wtf.AsInteger.ToString); end; end; 2 Share this post Link to post
Attila Kovacs 629 Posted February 21, 2019 (edited) @Uwe Raabe Phuhhh, this is just mapping numbers into an enum. Your helper actually is like the following code, with obfuscated names. I don't think I want to debug such code. It even works on negative values in the list. TEnum = (five, nine, fourteen, thousand) enum.AsInteger := five.AsInteger + nine.AsInteger; if enum = fourteen then begin Writeln('Hooray!'); end There must be a special use-case to do this, I suppose. Edited February 21, 2019 by Attila Kovacs Share this post Link to post
Uwe Raabe 2057 Posted February 21, 2019 3 minutes ago, Attila Kovacs said: this is just mapping numbers into an enum. Well, that is what giving number in the enum declaration is, too, The ADD example was just a little joke, because the numbers given nicely add up by coincidence. 1 Share this post Link to post
Attila Kovacs 629 Posted February 21, 2019 1 minute ago, Uwe Raabe said: was just a little joke *phew* 🙂 Share this post Link to post
Lars Fosdal 1791 Posted February 25, 2019 Just curious: Has anyone seen a valid use case for defined ordinal values in enumerations? Share this post Link to post
Guest Posted February 25, 2019 13 minutes ago, Lars Fosdal said: Just curious: Has anyone seen a valid use case for defined ordinal values in enumerations? Not really when writing my own code, I try to avoid them if possible. Sometimes for interop with an API, e.g. when translating C headers where enums are already declared that way. Or when you need to support a binary format which uses some specific ordinal values, then it depends - you might still prefer to use an enum but avoid conversion. Share this post Link to post
Rollo62 536 Posted February 25, 2019 I used it for grouping (in very rare cases: type TMyEnum = ( None, GroupA = 100, A_1, A_2, GroupB = 200, B_1, B_2, Group_Last ); TMyEnum_Helper = record helper for TMyEnum function IsGroupA : Boolean; end; function TMyEnum_Helper.IsGroupA : Boolean; begin Result := (Value > TMyEnum.GroupA) and (Value < TMyEnum.GroupB); end; function TMyEnum_Helper.IsGroupB : Boolean; begin Result := (Value > TMyEnum.GroupB) and (Value < TMyEnum.Group_Last); end; I know thats a little smelly, so please don'T throw stones on my head. But I still find it very useful and efficient in some special cases, where I want to avoid a second variable for the grouping. Share this post Link to post
Lars Fosdal 1791 Posted February 25, 2019 5 hours ago, Ondrej Kelle said: Not really when writing my own code, I try to avoid them if possible. Sometimes for interop with an API, e.g. when translating C headers where enums are already declared that way. Or when you need to support a binary format which uses some specific ordinal values, then it depends - you might still prefer to use an enum but avoid conversion. I still prefer using regular constants for bit-fiddling. Share this post Link to post
Uwe Raabe 2057 Posted February 25, 2019 25 minutes ago, Rollo62 said: so please don'T throw stones on my head. Only virtually 🚯 Share this post Link to post
Rudy Velthuis 91 Posted March 1, 2019 (edited) On 2/25/2019 at 8:36 AM, Lars Fosdal said: Just curious: Has anyone seen a valid use case for defined ordinal values in enumerations? Yes, C or C++ header translations (altough I would prefer integers and masks for those). For plain Delphi code they don't make a lot of sense. Edited March 1, 2019 by Rudy Velthuis Share this post Link to post
Joseph MItzen 251 Posted March 17, 2019 On 2/25/2019 at 2:36 AM, Lars Fosdal said: Just curious: Has anyone seen a valid use case for defined ordinal values in enumerations? Mapping days of the weeks to numbers. For instance, in some systems Monday is zero, while with ISO it is 1-7. And in the United States we like the week to start on Sunday instead of Monday. Share this post Link to post
Joseph MItzen 251 Posted March 17, 2019 On 3/1/2019 at 3:42 PM, Rudy Velthuis said: Yes, C or C++ header translations (altough I would prefer integers and masks for those). For plain Delphi code they don't make a lot of sense. Why don't they make a lot of sense? Share this post Link to post
Rudy Velthuis 91 Posted March 20, 2019 On 2/18/2019 at 12:05 PM, Lars Fosdal said: Not all for loops are created equal.Considerfor x in [value1, value2, value3]You would expect to see x vary in the order of the values in the list. However – if x and the values are of an enumerated type, looping the “list” does NOT loop in the apparent order of the constant, but in the order of the enumerated type declaration, such as it would for any set. Example at: https://larsfosdal.blog/2019/02/18/delphi-pitfalls-enumerated-types-and-for-loops/ If you use in, i.e. enumerators, you should not rely on any specific order, unless the enumerator is documented to have one. The only guarantee is that every element is visited, if possible (i.e. no break, no exceptions, etc.). Share this post Link to post