Recent

Author Topic: question about an enumeration within another enumeration  (Read 4497 times)

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: question about an enumeration within another enumeration
« Reply #15 on: July 29, 2020, 10:28:46 am »
Which is why I called such typecasting silliness. Especially if enums are saved to file and a corrupt file is later read you can immediately get a crash from undefined values, as numerous posts on the ML and this forum in times past testify.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: question about an enumeration within another enumeration
« Reply #16 on: July 29, 2020, 10:38:53 am »
On the back-end, all that is needed is for each instance of an enumerated type to be expanded when it shows up on the right side of an equation within the type declaration.

Code: Pascal  [Select][+][-]
  1. type
  2.   TSmallEnum = (Mary, Jane, Sue);
  3.   TLargeEnum = TSmallEnum + (Bob, Larry, Michael, Sally, Cheryl);
  4.  

And what would the behavior be with $ScopedEnums On? Would it be TLargeEnum.Mary or TSmallEnum.Mary? If the latter would this mean that duplicates are allowed, so that I could have a TSmallEnum.Mary and a TLargeEnum.Mary? What if I mix enums that are declared as $ScopedEnums On and those without?
First, for the record, I am _not_ asking for this feature to be implemented but, I'd like to answer your question.

Also first, the use of the "+" sign is not ideal from an implementation viewpoint.  @Marcov pointed out some of the problems and there are more if it were implemented using "+".

The answer to your question about the scoped enums is that the compiler should see  TLargeEnum.Mary as being the same constant as TSmallEnum.Mary.  The compiler could be "informed" of that by using an "inheritance" mechanism instead of "+".  Something along the lines of "TLargeEnum(TSmallEnum) = (additional constants here);"  effectively making a TSmallEnum a subset of TLargeEnum (just as an ancestor is always a member of its descendants in OOP).

The real problem comes when declaring sets of enumerations built like that.  It would be common for a TSmallEnum to require only 32bits to represent the set but, the larger enum(s) may require more, yet, since one is a subset of the other, the sets should be the same size and the compiler cannot know that at the time it find TSmallEnum.  The inefficient but safe approach would be to make all sets derived from enumerated types accommodate the maximum number of elements (256 at this time) and possibly add the option to calculate the optimal size with a second "pass/compile" (wpo ? - global program optimization)

The other way would be to allow a set declaration to be done only on the larger set and emit an error on a set declared for the smaller enum when and if a larger one is found later in the code.  Also, a prophylactic restriction would be to allow only a single inheritance chain since an inheritance tree would really complicate matters for the compiler and be a source of confusion for programmers.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: question about an enumeration within another enumeration
« Reply #17 on: July 29, 2020, 10:42:43 am »
Which is why I called such typecasting silliness. Especially if enums are saved to file and a corrupt file is later read you can immediately get a crash from undefined values, as numerous posts on the ML and this forum in times past testify.

You could argue against untagged variant records in exactly the same way, and they're been in Pascal (although possibly not Wirth's later languages) ab initio.

I was actually trying to be positive back there. I didn't mean "this is a dumb idea", I meant "this is something that could probably be done usefully in the compiler, and having a robust and efficient compilation-time implementation is far superior to the sort of runtime hack beloved of the LISP brigade".

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: question about an enumeration within another enumeration
« Reply #18 on: July 29, 2020, 11:09:58 am »
Because after 5 seconds somebody tries a few things and posts the following bug

I'd already got there. It needs a compile-time extensor notation, not a runtime operator. Some sort of type helper?

I meant that you need syntax that is basically a kind of single derivation. So the syntax should reflex that an enum can only use one other enum, and can only append values. Probably also enums that set values by hand should be excluded.

glorfin

  • Full Member
  • ***
  • Posts: 148
  • LMath supporter
Re: question about an enumeration within another enumeration
« Reply #19 on: July 29, 2020, 12:24:58 pm »
Quote
I'd like to have an enumeration be a "superset" of another enumeration.

Maybe sets would serve you better than enumerations? With sets you can easily do such things.
« Last Edit: July 29, 2020, 12:26:47 pm by glorfin »

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: question about an enumeration within another enumeration
« Reply #20 on: July 29, 2020, 02:38:09 pm »

Why would it have to be that complicated?

Because after 5 seconds somebody tries a few things and posts the following bug

Code: Pascal  [Select][+][-]
  1. type
  2.   TSmallEnum = (Mary, Jane, Sue);
  3.   TSmallEnum2 = (Kate);
  4.   TLargeEnum = TSmallEnum +  TSmallEnum2 + (Bob, Larry, Michael, Sally, Cheryl);
  5.  

This is all logical with "+" semantics

While I like possibilities that this potential feature would bring, and while I am sorta, kinda, defending it at the moment, I want to be clear that the constructs I chose were for effectively conveying the concept, and not laying down the definitive syntax.    I figured that "+" would be problematic (having looked at various threads in the past on various feature requests).

The main gist of my comment is this:  The construct is assembled at compile time, and could possibly be done along the lines of what is currently allowed, even if the visual representation the developer uses is different.

But I was serious about understanding what the flaws would be, because I know that many seemingly simple requests have significant underlying drawbacks or complexities.

If we overlook the "+" debate for a second, I still don't see a problem with the example you gave, which could be converted behind the scenes to:

Code: Pascal  [Select][+][-]
  1. type  
  2.   TLargeEnum = (Mary, Jane, Sue, Kate, Bob, Larry, Michael, Sally, Cheryl);
  3.   TSmallEnum = Mary..Sue;  
  4.   TSmallEnum2 = Kate..Kate;
  5.  

Now, I have to address the points that @PascalDragon made...  :(
-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: question about an enumeration within another enumeration
« Reply #21 on: July 29, 2020, 02:52:02 pm »
And what would the behavior be with $ScopedEnums On? Would it be TLargeEnum.Mary or TSmallEnum.Mary? If the latter would this mean that duplicates are allowed, so that I could have a TSmallEnum.Mary and a TLargeEnum.Mary? What if I mix enums that are declared as $ScopedEnums On and those without?

You compiler developers...   Sigh...  (Said affectionately)

The easy, but annoying answer would be that those two features are mutually exclusive.  Either you get $EnumSupersets or you get $ScopedEnums.

I'm intrigued enough to give it a little more thought this week, but thus far, the issues that you have raised in these few questions are significant enough that I wouldn't want to have to open up the can of worms any further than what has been suggested so far.

I think it would be more consistent, if this superset functionality were available at all, that it could not be mixed with $ScopedEnums at all.  Whether that means a total exclusivity (as I said in the sentence above) or just that no enum superset could be part of a scoped enum (while both are active at the same time), would be up for discussion, but in looking at the two features, it seems far more prudent to avoid trying to meld them in any way.

(BTW, I appreciate you and @marcov and others responding to my query on this.   The enlightenment is helpful.)
-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: question about an enumeration within another enumeration
« Reply #22 on: July 29, 2020, 02:59:18 pm »
The answer to your question about the scoped enums is that the compiler should see  TLargeEnum.Mary as being the same constant as TSmallEnum.Mary.  The compiler could be "informed" of that by using an "inheritance" mechanism instead of "+".  Something along the lines of "TLargeEnum(TSmallEnum) = (additional constants here);"  effectively making a TSmallEnum a subset of TLargeEnum (just as an ancestor is always a member of its descendants in OOP).


Thanks for this additional perspective.  Do you see this as being a better option than just forbidding that combination (as per my recent post)?
-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: question about an enumeration within another enumeration
« Reply #23 on: July 29, 2020, 03:47:08 pm »
And what would the behavior be with $ScopedEnums On? Would it be TLargeEnum.Mary or TSmallEnum.Mary? If the latter would this mean that duplicates are allowed, so that I could have a TSmallEnum.Mary and a TLargeEnum.Mary? What if I mix enums that are declared as $ScopedEnums On and those without?

You compiler developers...   Sigh...  (Said affectionately)

It's part of the job description to find the hair in the soup. :P Not to mention that even if someone else would implement it, I'd still be part of the people who'd need to maintain it...  :-X

If we overlook the "+" debate for a second, I still don't see a problem with the example you gave, which could be converted behind the scenes to:

Code: Pascal  [Select][+][-]
  1. type  
  2.   TLargeEnum = (Mary, Jane, Sue, Kate, Bob, Larry, Michael, Sally, Cheryl);
  3.   TSmallEnum = Mary..Sue;  
  4.   TSmallEnum2 = Kate..Kate;
  5.  

And what if TSmallEnum is declared in a different unit, thus can't be changed in any way?

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: question about an enumeration within another enumeration
« Reply #24 on: July 29, 2020, 08:39:27 pm »
Thanks for this additional perspective.  Do you see this as being a better option than just forbidding that combination (as per my recent post)?
You're welcome and, there are combinations that shouldn't be allowed because they could create lot of confusion. One such would be creating multiple supersets from a root enumeration (a tree).  Allowing that would make it quite unclear what enumerations can be treated as supersets and what enumerations are totally different types unrelated to each other even though they share a common ancestor enumeration. 

For instance:

Code: Pascal  [Select][+][-]
  1. TEnumRoot = (a, b, c);
  2. TEnumA(TEnumRoot) = (d, e, f);    // a, b, c, d, e, f
  3. TEnumB(TEnumRoot) = (x, y, z);    // a, b, c, x, y, z
  4.  
In that case EnumA and EnumB are supersets of EnumRoot but, they are completely different types (they represent a different set of constants.)  It would make things a lot simpler for the compiler and, easier for the programmer to understand, if branches are not allowed (EnumA and EnumB are different branches of EnumRoot.)

IOW, enumeration supersets should be single chain and strictly additive.  In the above example, the compiler would report an error when seeing TEnumB because that creates a separate branch, i.e, a completely new type which can be quite confusing for a programmer that needs to maintain that code.



It's part of the job description to find the hair in the soup. :P
That would lead to the conclusion that bald programmers write better code since there is a lower probability there will be hairs in the soups they make. :)

And what if TSmallEnum is declared in a different unit, thus can't be changed in any way?
Allowing enumeration supersets to be spread among units is a source of complications but, it is not unreasonable to require that all subsets of the enumeration be declared in the same unit or possibly in the same "type" declaration as is the case for some pointer declarations.  In the case of the same unit, I believe OOP already implements such a restriction using visibility modifiers (though not for enumerations.)



Maybe sets would serve you better than enumerations? With sets you can easily do such things.
Can't do it with sets because a set doesn't define constants, it depends on its elements having been previously defined.  IOW, a set is always a derived type, it is a set of something and, that something has to be defined first.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

nanobit

  • Full Member
  • ***
  • Posts: 160
Re: question about an enumeration within another enumeration
« Reply #25 on: July 29, 2020, 08:52:45 pm »
In that case EnumA and EnumB are supersets of EnumRoot but, they are completely different types (they represent a different set of constants.) 

Another workaround currently possible:
Meets requirements: edit single list and support inheritance.
Caveat: child-specific names (d, e, f) are usable outside of child-type.

One parent, two children:

const
  a = 0;
  b = a + 1;
  c = a + 2;
  pLast = c;

  d = pLast + 1;
  e = d + 1;
  f = d + 2;
  c1Last = f;

  w = pLast + 1;
  x = w + 1;
  y = w + 2;
  z = w + 3;
  c2Last = z;

type
  TParent = a..pLast;
  TChild1 = a..c1Last;
  TChild2 = a..c2Last;

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: question about an enumeration within another enumeration
« Reply #26 on: July 29, 2020, 09:49:15 pm »
It's part of the job description to find the hair in the soup. Not to mention that even if someone else would implement it, I'd still be part of the people who'd need to maintain it...

Yeah, I can appreciate the motivation that brings. :)


If we overlook the "+" debate for a second, I still don't see a problem with the example you gave, which could be converted behind the scenes to:

Code: Pascal  [Select][+][-]
  1. type  
  2.   TLargeEnum = (Mary, Jane, Sue, Kate, Bob, Larry, Michael, Sally, Cheryl);
  3.   TSmallEnum = Mary..Sue;  
  4.   TSmallEnum2 = Kate..Kate;
  5.  

And what if TSmallEnum is declared in a different unit, thus can't be changed in any way?

Yeah... well... It starts to unravel quite a bit, doesn't it.

It's not nearly as useful if it's going to be confined to a single unit, IMO...    (Well, it would still be useful, but it seems like it would be a lot of work to go through to be stuck there.)

So, we'd have to keep tabs on all enums, expand smaller ones into larger ones, and then somehow keep track of who is a subset of whom, without going back for a second pass.

Hmmm...  Well, it sounded nice before you guys poked my bubble. :)

-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: question about an enumeration within another enumeration
« Reply #27 on: July 29, 2020, 09:54:26 pm »
IOW, enumeration supersets should be single chain and strictly additive.  In the above example, the compiler would report an error when seeing TEnumB because that creates a separate branch, i.e, a completely new type which can be quite confusing for a programmer that needs to maintain that code.

Agreed.


Allowing enumeration supersets to be spread among units is a source of complications but, it is not unreasonable to require that all subsets of the enumeration be declared in the same unit or possibly in the same "type" declaration as is the case for some pointer declarations. 

I'm still undecided on if limiting it this way -- which gets past a major hurdle -- doesn't just reduce its value, too.
-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: question about an enumeration within another enumeration
« Reply #28 on: July 30, 2020, 12:08:29 am »
Allowing enumeration supersets to be spread among units is a source of complications but, it is not unreasonable to require that all subsets of the enumeration be declared in the same unit or possibly in the same "type" declaration as is the case for some pointer declarations. 

I'm still undecided on if limiting it this way -- which gets past a major hurdle -- doesn't just reduce its value, too.
In a way, it does reduce its value a little but, at the same time, by requiring that everything be in one place, a programmer who has to maintain the code doesn't have to go to multiple places to figure out all the elements in the enumeration (something I feel is important.) Another important consideration from an implementation viewpoint is that if sets are defined on these enumerations, the compiler has to have a reasonably easy way of figuring out how many bits to allocate for the sets.  Just because of that, I'd be rather tempted to require that all sub-enumerations be in a single type definition thus, not even allowing them to be spread around in a unit.

Also, usually, one knows all the values that an enumeration should have but, there are times when it's convenient to "divide" the enumeration into groups.  An analogy is array slices, there are times when it's useful to be able to operate on a slice of it instead of the entire array.  For instance, if an enumeration superset is composed of 3 subsets named, ENUM_ROOT, ENUM_A, ENUM_B then one can do "for i in ENUM_ROOT do ... " or "for i in ENUM_B do ..." and allowing sets on these "named enumeration subsets" would allow something like "if identifier in ENUM_ROOT_SET then..." which would return false even if the identifier is in the larger set but not a member of the root.  Unlike an array slice which can go from any element to any element an enumeration slice would always be from the beginning of the enumeration to the end of the named sub-enumeration.  IOW, from zero (0) (presuming no value has been set manually) to n where n would be determined by which sub-enumeration is used.

These things can be "synthesized" currently but, it takes more type definitions which obscures the intention and, depending on how they are synthesized, they also open the possibility that an identifier added later doesn't make it into all those additional type definitions.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: question about an enumeration within another enumeration
« Reply #29 on: July 30, 2020, 09:03:16 am »
I wonder whether it's worth pointing out that application code shouldn't be aware of the numerical values or enumerated items, the only thing that really matters is Succ() and Pred(). Succ() of the last item of the foundation enumeration is invalid, leaving the real problem being Pred() of the first item of an extended enumeration where this crosses units.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018