Feature Request: Extending enumerators and hierarchies lazarus / 64-FPC development ---------------------------------------------------------------------- EganSolo · 2025-08-06 03:44 Two feature requests that don't break backward compatibility: 1. Extending enumerated types: Currently, we can restrict enumerated types. It would be handy to extend them: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type   WorkingDays   =  (Monday, Tuesday, Wednesday, Thursday, Friday);   DaysOfTheWeek =  (WorkingDays, Saturday, Sunday);  The compiler already flags duplicated enumerated types. In this case, it would recognize DaysOfTheWeek as an extension of WorkingDays and would then internally redeclare WorkingDays as a restriction of DaysOfTheWeek. That's an oversimplification, of course, but you get the idea. Consider this more elaborate example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type   WorkingDays   =  (Monday, Tuesday, Wednesday, Thursday, Friday);   DaysOfTheWeek =  (WorkingDays, Saturday, Sunday);   SpecialDays   =  (WorkingDays, Birthday, AnniversaryDay);  Admittedly, this is forced, but it highlights the possible complication: Monday is now an item of type WorkingDays, DaysOfTheWeek and SpecialDays. Nevertheless, that's no different than what happens for instances of classes in a hierarchy. Speaking of Hierarchy, the next feature is a generalization of the previous request: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  RootHierarchy   = (DaysOfTheWeek, MonthsOfTheYear); DaysOfTheWeek   = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); MonthsOfTheYear = (January, February, March, April, May, June, July, August, September, October, November, December); A hierarchy leverages enumeration to implement a simplified ontology. It allows a rapid grouping of things somewhat orthogonal to the more rigid inheritance mechanism. What do you guys think? ---------------------------------------------------------------------- MarkMLl · 2025-08-06 06:50 Quote from: EganSolo on August 06, 2025, 05:44:33 am1. Extending enumerated types: Currently, we can restrict enumerated types. It would be handy to extend them: I definitely agree with that one, it's something I raised years ago in the context of i) A class (emulating a piece of hardware) could return certain states which were defined as an enumeration (device not ready, device busy and so on). ii) A subclass (emulating a more complex piece of hardware) could return extra states (beginning of medium, end of medium etc.). To some extent, it's possible to work around the lack of this by defining numeric bases for subranges. However I consider that at best to be a kludge. MarkMLl ---------------------------------------------------------------------- gues1 · 2025-08-06 07:55 I think, my half cent, that this is dangerous and can lead to various attribution issues. In your example: Quote from: EganSolo on August 06, 2025, 05:44:33 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type   WorkingDays   =  (Monday, Tuesday, Wednesday, Thursday, Friday);   DaysOfTheWeek =  (WorkingDays, Saturday, Sunday);   SpecialDays   =  (WorkingDays, Birthday, AnniversaryDay);  How can be interpreted this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i constW = WorkingDays; //DaysOfTheWeek or SpecialDays ? By now the physical implementation of the enumerated type is on value (position too) and this can be (... IT IS) useful to save that value and reload it, and for compatibility with something else. Again, have different enums with the same meaning is not something good. But the idea on "hierarchy leverages enumeration" is something to think about. ---------------------------------------------------------------------- EganSolo · 2025-08-06 08:08 QuoteHow can be interpreted this:     const     W = WorkingDays; //DaysOfTheWeek or SpecialDays ? Excellent point. As with other ambiguous declarations, disambiguation would be required. So, the compiler would flag that as an error and we would redeclare it as: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  W : DaysOfTheWeek = WorkingDays;  That's one solution that's already in use elsewhere. For instance, if you have two functions foobar in unit1 and unit2, you might need to specify which one you want to use by prefixing them with the unit name as in Unit1.foobar or Unit2.footbar. In general, I think that ambiguity that can be removed with existing mechanisms should not be ignored. Nevertheless, I agree with you that this feature introduces ambiguity. ---------------------------------------------------------------------- Thaddy · 2025-08-06 08:13 With properly defined set of enumeration this can already be achieved? and a set is an enumerated type as well. As long there is an enumeration that contains all possible values it is quite easy to do that with set operators. Since a subrange can be declared as const this effectively looks like what you want to achieve. Crude example:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}type  day = (monday, tuesday, wednesday, thursday,friday,saturday,sunday);  days = set of day;const //<--- becomes an enumeration because of const.  weekenddays:days = [saturday,sunday];  workdays:days = [monday,tuesday,wednesday,thursday,friday];var   x:day;begin  writeln('What are my days off this week:');  for x in weekenddays do writeln(x);  writeln('What are my workdays this week:');  for x in workdays do writeln(x);  readln;end. ---------------------------------------------------------------------- Thaddy · 2025-08-06 08:15 Quote from: EganSolo on August 06, 2025, 10:08:24 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  W : DaysOfTheWeek = WorkingDays; No problem. Posts crossed, but my example refutes this. It is already possible by declaring a set of enumeration to create new enumerations  declared const and the enumeration itself contains all possible values for the domain. ---------------------------------------------------------------------- ASerge · 2025-08-06 18:30 Quote from: EganSolo on August 06, 2025, 05:44:33 amThe compiler already flags duplicated enumerated types. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$SCOPEDENUMS ON} ---------------------------------------------------------------------- EganSolo · 2025-08-07 19:45 Thaddy,  I love the ingenuity of your solution, but help me understand how it addresses this use case, which is what I was hoping to achieve by extending enumerations: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Unit Unit1;//assume this unit is written by author1Interfaceuses Classes, SysUtils;Type  WeekDay = (Monday, Tuesday, Wednesday, Thursday, Friday);ImplementationEnd.  I write my unit and do this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Unit MyUnit;Interfaceuses Classes, SysUtils, Unit1;Type  DaysOfTheWeek = (DayOfTheWeek, Saturday, Sunday);ImplementationEnd.  Could you still solve for this using constant sets? ---------------------------------------------------------------------- Thaddy · 2025-08-08 17:27 Yes, I already did....Other example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}type  // full enum   day= (monday,tuesday,wednesday,thursday,friday,saturday,sunday);   days = set of day;const   workdays:days = [monday,tuesday, wednesday, thursday, friday];   weekend:days  = [saturday, sunday];var  thisweek:days = [];  d:day;begin   thisweek := thisweek + workdays;   include(thisweek,saturday);// overtime   exclude(thisweek, wednesday);//day off.   for d in thisweek do      writeln(d);  readln;end.Outputs: Code: [Select]monday tuesday thursday friday saturdayYou only have to know how sets really work. ---------------------------------------------------------------------- EganSolo · 2025-08-09 01:23 Your example started with a full enum. Mine started with a partial one: In my example the author of Unit1 defined __what he thought was a full enum__ and I want to extend it, without changing his code. Don't you think you're solving a different use case? ---------------------------------------------------------------------- Thaddy · 2025-08-09 19:17 That will likely never be possible or adds multiple passes to the compiler to resolve (not going to happen). Otherwise it requires compile-time sizes to be manipulated at runtime (likely not going to happen). What I tried to explain is that the full set of possibilities, the enum to choose from, need to be known at compile time and any subset you like can be declared as const. Since anything you showed is compile-time anyway.....means by definition the full enum is already known... So, no, I am solving the same case, just with some intricacies you forgot about? ---------------------------------------------------------------------- EganSolo · 2025-08-10 21:45 Hi Thaddy:   Admittedly, the simplistic example I gave listed the enumerated types, however, it's not that difficult to imagine an example where Unit1 is in a vendor's package that preclude a change to its code. I don't think my example is contrived, and extended enumerated types is a really useful feature.   You bring up a good point: adding multiple compilation passes is a no-no. Nevertheless, I fail to see why that would be required. Forward compiling is sufficient to recognize extended enumeration much like it recognizes classes that inherits from already defined classes. Furthermore, disambiguating an enumerated item to determine its provenance would be done by crawling a dependency chain among enumerated types, the same way we do it when we locate a declared attributes in a class. ---------------------------------------------------------------------- Thaddy · 2025-08-11 15:35 When you propose external libraries the solution is: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}type  Tbyte = set of 0..255;// max setconst  bb: Tbyte = [0..255];  cc: TByte = [201,202,203];var  b:byte;begin  for b in bb do writeln(b);  writeln;  for b in cc do writeln(b);end.Which proves that any subset of high(enum) can be expressed as a subset. Where you go wrong is named enums... that is not possible.(unless you cast) Enums can contain gaps, where a gap is valid for the enum but has no name attached. Then it would fail miserably. ( I provided at patch, once, to only allow named elements in a named enum range , but that was refused: although the patch was correct, querying the name slows downs the code a lot, which is not the intention of enums. ) ---------------------------------------------------------------------- EganSolo · 2025-08-13 00:22 I sense that this discussion veered from my initial ask. I'm not interested in what hack I might choose to implement something like an enumerated type extension. My question was whether that would be a feature worth having or not. Thaddy, you explained that it could be done with sets. Still, I'm afraid your explanation hinges on knowing the whole domain of enumerated types at compile time for all the units and packages involved in the project, which is impractical for reasons I've outlined: if I'm including a commercial package that I don't want to touch, that solution breaks. Using integers as an approximation to enumerated types is, again, self-defeating. So, I'd like to reorient this conversation to this initial ask: Are extended enumerated types a good thing and should we have them in the language? The how is an implementation question worth having after we've answered this question. ---------------------------------------------------------------------- Thaddy · 2025-08-13 03:47 You can't do what you want, that is unless there is an underlying structure, may be hidden, that expresses the full range. Any other thing would not be an enum. I fear you don't grasp that a third party provided enum also has indices starting from 0. Concatinating with you own enum that also starts from index 0 leads to duplicates or makes the resulting enum worthless because one of the enums must shift their values. Do you understand that part? I am not veering away from your original idea, I am merely pointing out it can not be done in a meaningful way. suppose my enum is:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i myenum = (one,two,three);And some external code provides an enum Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i theirenum = (four, five,six);how would you merge them without loosing their value or changing their meaning? Because Ord(one) = 0 and ord(four) is also 0, you can't make that 4, because then the meaning of the enum has changed and code would not work as expected. E.g., toggling a switch based on enum, what I use a lot for IoT. will fail if the external enum would be merged into your own. one <> four but both originally are Ord(one)  =  0 and ord(four) = 0. It would toggle the wrong switch. Enums, by definition, do not allow duplicates. That leaves two solutions: Use sets where the full enum is known. Or create an overlay like so: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  myenum = (one,two,three);  theirenum = (four,five,six);var  ours:myenum;  theirs: theirenum absolute ours;begin  writeln(Ord(two) = Ord(five));// correct  // writeln(two = five);       // errorend.That at least leaves the original ordinal values intact so you do not create accidents. Another example:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}{$scopedenums on}uses typinfo,rtti;type  myenum = (one,two,three);  theirenum = (four,five,six);  // what is asked is myenum+theirenum := combinedenum as expression  // if that were possible the index would change and   // the original meaning is lost.  // so we redefine it with the same names.  combinedenum = (one,two,three,four,five,six);var  ours:myenum;  theirs: theirenum absolute ours;begin  writeln(ord(myenum.two));       // 1  writeln(ord(theirenum.five));   // 1  writeln(ord(combinedenum.five));// 4 // <--meaning is lost, index is now 4.end.That is why it is a bad idea. Renders enums useless. The primary goal of enums is to provide an index based on readable names. ---------------------------------------------------------------------- EganSolo · 2025-08-15 00:28 Hi Thaddy, Thank you for the example you gave. It will help clarify my intent a bit. Let me reproduce it here, then I'll show how extension would work: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type  myenum = (one, two, three);  theirenum = (four, five, six);  Here is how Extension would work: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type myenum   = (zero,one, two, three); //added zero to keep the ordinal mapping simple. theirenum = (four five six) extends myenum;  Since the compiler knows theirenum to be an extension of myenum, it would assign the ordinals 4, 5, 6 to its elements. There would be no confusion. Extension is not an anonymous union. It carries metadata that instructs the compiler to insert a pointer in the enumerated values of theirenum, pointing to the enumerated values of myenum. As I mentioned earlier, it functions similarly to inheritance. I hope this addresses your concerns. The mechanism for resolving and accessing the values is already in the compiler. In fact, if Pascal was fully orthogonal, then the enumerated type would have been defined as follows: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type  myenum   = Enumeration[one,two,three];  theirenum= Enumeration(myenum)[four,five,six];  This notation is for illustration purposes and shows quite clearly that treating the enumerated types with the same techniques we already have for managing inheritance would work. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  me: MyEnum = one;  te : TheirEnum = one; //works also  me2: MyEnum = five; //failsvar  m : MyEnum;  t   : TheirEnum;begin  t   := One;  m := t; //fails for type mismatch  t  := m; //succeeds m := mtenum(t); //succeeds at compile time but could still throw a run-time errorend. ---------------------------------------------------------------------- Thaddy · 2025-08-15 04:10 So, your new enum has different indices for the extension, changing their meaning, and that makes it, I am afraid, worthless. Furthermore, enums are compile-time constants. You can't change them into variables. ---------------------------------------------------------------------- EganSolo · 2025-08-15 04:15 What's worthless about different constants? The ordinal association is maintained, and the enumerated values are still constants. Could you please provide an example that would help me better understand your concern? ---------------------------------------------------------------------- Thaddy · 2025-08-15 04:22 Apart from the assembler output for enums, which are read only:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i .section .rodata.n_RTTI_$P$ENUMS_$$_DAY,"aw"        .balign 8.globl  RTTI_$P$ENUMS_$$_DAYRTTI_$P$ENUMS_$$_DAY:        .byte   3,3        .ascii  "day"        .quad   0        .byte   1        .long   0,6      .quad   0        .byte   6        .ascii  "monday"        .byte   7        .ascii  "tuesday"        .byte   9        .ascii  "wednesday"        .byte   8        .ascii  "thursday"        .byte   6        .ascii  "friday"        .byte   8        .ascii  "saturday"      .byte   6        .ascii  "sunday"        .byte   5        .ascii  "enums"        .byte   0Furthermore, an external library does not even export the enum names! only the ordinal values in a set. I would like you to look at the example I gave for the switch.Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  my_engine = (off,slow,fast);  //constant values 0,1,2  their_enginemod = (reverse, neutral, off);//constant values 0,1,2How will my engine behave? The code relies on their constant index..... So after the mod it is not off but goes in reverse.... Sets, on the other hand, do have a variable nature (although they can be declared as const) but indeed require that the full range is known. The most important part about enums is that they are ordered and their order can not change. Their member ordinal value (index) is fixed and the compiler makes them compile-time constants. Play with this:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library enumlib;type  myenum = (what,would, be, my, index);   function enumtest:myenum;  begin    enumtest := index;  end;  exports  enumtest;end.Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program enums;{$mode delphi}{$linklib 'enumlib'}type  myenum = (what,would, be, my, index);  // must be known.... function enumtest:myenum; externaL; begin  writeln(enumtest);end. And tell me what happens? Your main program needs to know the full enum to work as enum, now, doesn't it? Otherwise you'll end up withCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program enums2;{$mode delphi}{$linklib 'enumlib'}function enumtest:integer; externaL; begin  writeln(enumtest);end.Still works without enum, gives the index(4) instead. That is because an enum is an ordinal value. I can't make it any clearer than this. Bonus lib:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library enumlib2;type  // can't export a type!  myenum = (what, would, be, my, index);var  // can export a set! but enum type needs to be known at the other side  enumset:set of myenum = [what,would, be, my, index];export name 'enumset';  exports  enumset;end.