Lazarus

Miscellaneous => Suggestions => Topic started by: GypsyPrince on April 04, 2020, 10:40:33 pm

Title: [SOLVED] Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 04, 2020, 10:40:33 pm
We can currently create enumerated types as follows:

Code: Pascal  [Select][+][-]
  1. //Boole-Logic - represents an enhanced boolean (True, False, or Neither) value or state...
  2. Type Boologic = (Nay=-1, Nor=0, Aye=1);

However, we can't assign an existing ordinal type to our enumerated type during is declaration.

I know such a feature would be possible to implement because other languages have done it, but would Free Pascal consider adding enumerated constant types (as structures) based on ordinal types?

Example:

Code: Pascal  [Select][+][-]
  1. Struct CriticalErrors : int64 //Enumerated constant type named "CriticalErrors' - of type int64...
  2.   AccessViolation = 4;
  3.   AppDomainUnloaded = 3;
  4.   BadImageFormat = 5;
  5.   CantUnloadAppDomain = 6;
  6.   ExecutionEngine = 7;
  7.   InvalidProgram = 9;
  8.   NonCritical = 1;
  9.   OutOfMemory = 2;
  10.   StackOverflow = 8;
  11.   ThreadAbort = 10;
  12. End;
  13.  
  14. Struct CalendarDays : String //Enumerated constant type named "CalendarDays' - of type String...
  15.   Day01 = 'Sunday';
  16.   Day02 = 'Monday';
  17.   Day03 = 'Tuesday';
  18.   Day04 = 'Wednesday';
  19.   Day05 = 'Thursday';
  20.   Day06 = 'Friday';
  21.   Day07 = 'Saturday';
  22. End;
  23.  
  24. Procedure PrintDay();
  25.   Var
  26.     dayCurrent : CalendarDays;
  27.  
  28. Begin
  29.     dayCurrent := CalendarDays.Day04;
  30.  
  31.     ShowMessage('Today is ' + dayCurrent + '.');
  32.  
  33.     //Output = "Today is Wednesday."
  34. End;

Note that in each type (struct) declaration, all enumerated elements inherent the same declared type (int64 or String).

Something similar to this can be done using enumerated arrays or sets. However, they are very inefficient to use.  Additionally, this method allows us to encapsulated our constant values, lending to better OOP. Also, in other languages which have implemented this feature, the enumerated type can be read directly  into a variable, routine parameter/argument, property, etc. of that same type.

Example:
 
Code: Pascal  [Select][+][-]
  1. Procedure PrintDay();
  2.   Var
  3.     dayCurrent : CalendarDays;
  4.     strCurrent : String;
  5.  
  6. Begin
  7.     dayCurrent := CalendarDays.Day04;
  8.  
  9.     strCurrent := dayCurrent; //Because the 'CalendarDays' enumerated type is String, the variable
  10.                               //strCurrent can be assigned its value.
  11.  
  12.     //Could also be condensed to: strCurrent := CalendarDays.Day04;
  13.  
  14.     ShowMessage('Today is ' + strCurrent + '.');
  15.  
  16.     //Output = "Today is Wednesday."
  17. End;

Object Pascal already has a somewhat similar feature to this using variable in the record type. And technically, we could use the record type enumeration to achieve the purpose of this feature request. However, the downside to doing so is that I don't know if the programmer would have the ability to lock the variable elements within the record type against editing. Hence, the reason for wanting the same feature using constants so their values can't be inadvertently changed during runtime.
Title: Re: Enumerated constant types using existing ordinal types...
Post by: winni on April 05, 2020, 01:37:44 am
Hi!

In Pascal it is done shorter and more elegant:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.SpeedButton1Click(Sender: TObject);
  2. type
  3.   CalDays= (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
  4. var
  5.   myDay : CalDays;
  6.   s: string;
  7. begin
  8.   myDay := Thursday;
  9.   WriteStr(s, myDay);
  10.   Showmessage(s);
  11. end;          
  12.  
  13.  

Winni
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 01:48:42 am

However, we can't assign an existing ordinal type to our enumerated type.


I'm wondering why the Ord function exists since 1987 then  :P

https://www.freepascal.org/docs-html/rtl/system/ord.html (https://www.freepascal.org/docs-html/rtl/system/ord.html)
Title: Re: Enumerated constant types using existing ordinal types...
Post by: winni on April 05, 2020, 01:51:52 am
Hi!

Ord / Pred / Succ existed in N. Wirth's first Pascal design < 1970.

Winni
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 01:55:36 am
Hi!

Ord / Pred / Succ existed in N. Wirth's first Pascal design < 1970.

Winni

on big machines Sir, yes! on micro-computers, tp introduced this around the year i said
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 01:57:16 am
so with Transtyping  on one way and Ord the other way back to get indices, you can do merely what you want on sets of elements
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 01:57:59 am
Yes. But your function does not do what I'm asking.

Read about transtyping/ typecasts
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 02:02:40 am
your feature request, as you know how to typecast and index back, is useless , the RangeChecking compiler option is clever enough when you test your "awesome" LOL code ;)
Title: Re: Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 05, 2020, 02:03:45 am
It is not useless if I have a use for it.
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 02:07:15 am
It is not useless if I have a use for it.
yea we all have such needs !

Here I NEED a feature request that is very IMPORTANT! a compiler that writes my programs on its own, because I don't plan to remove my gloves in front of my keyboard, each time it's cold in my room
 :P :D
Title: Re: Enumerated constant types using existing ordinal types...
Post by: winni on April 05, 2020, 02:13:12 am
Wow... this place is such a waste of time...

So why are you here?

This is a Pascal forum.

If you want to have some odd C constructs to be translated 1:1 - this is not the right place.

It is already all there. But you have to dive into Pascal.

Pascal was there before C was created.
C has learned a lot from Pascal.
But not enough.

Winni
Title: Re: Enumerated constant types using existing ordinal types...
Post by: mercurhyo on April 05, 2020, 02:18:57 am
NOW with your permission, I consider you as friend @Winni
Welcome to my Mean Humour World hehehe
Thank you!

@Winni +1000
 :D
Title: Re: Enumerated constant types using existing ordinal types...
Post by: winni on April 05, 2020, 02:43:48 am

on big machines Sir, yes! on micro-computers, tp introduced this around the year i said

Nope!

UCSD Pascal for 80 different small and not so small computers had it since 1978.
UCSD Pascal war sold from 1979 on as Apple Pascal for the Apple II.

I  have worked with it!

Winni

Title: Re: Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 08, 2020, 12:38:12 am
@winni

Quote
In Pascal it is done shorter and more elegant:

Code: Pascal  [Select]
procedure TForm1.SpeedButton1Click(Sender: TObject);
type
  CalDays= (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
var
  myDay : CalDays;
  s: string;
begin
  myDay := Thursday;
  WriteStr(s, myDay);
  Showmessage(s);
end;

Unfortunately, the declaration

Code: Pascal  [Select][+][-]
  1. type
  2.   CalDays= (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);

equates to

Code: Pascal  [Select][+][-]
  1. type
  2.   TCalDays= (Sunday=1, Monday=2, Tuesday=3, Wednesday=4, Thursday=5, Friday=6, Saturday=7);

Because of this, a simplistic implementation of...

Code: Pascal  [Select][+][-]
  1. ShowMessage(TCalDays.Sunday);

will result in the numeric value being displayed/referenced rather than the string I'm looking for.

Ideally, I should be able to do this to be efficient...

Code: Pascal  [Select][+][-]
  1. type
  2.   TCalDays= (day01='Sunday', day02='Monday', day03='Tuesday', day04='Wednesday', day05='Thursday', day06='Friday', day07='Saturday');
  3.  
  4. ShowMessage(TCalDays.day03); //Displays "Tuesday"
  5.  

However, as is currently implemented, in order to get to the string value (incorrectly positioned as the enumerated value's name) I must add the 2 additional steps of assigning the enumeration element to a string variable, then use the WriteStr() function to extract the element name (rather than properly extracting the element's value).

Code: Pascal  [Select][+][-]
  1. var
  2.   myDay : CalDays;
  3.   s: string;
  4.  
  5. begin
  6.   myDay := Thursday; //2 extra steps to convert the enumeration element's name to a value.
  7.   WriteStr(s, myDay);
  8.  
  9.   Showmessage(s);
  10. end;

So, for me anyway, I see it as more efficient that I continue to use regular string constants rather than an enumerated type when dealing with string values.
Title: Re: Enumerated constant types using existing ordinal types...
Post by: winni on April 08, 2020, 12:55:26 am
@winni

Unfortunately, the declaration

Code: Pascal  [Select][+][-]
  1. type
  2.   CalDays= (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);

equates to

Code: Pascal  [Select][+][-]
  1. type
  2.   TCalDays= (Sunday=1, Monday=2, Tuesday=3, Wednesday=4, Thursday=5, Friday=6, Saturday=7);

No
Title: Re: Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 08, 2020, 01:10:03 am
yep
Title: Re: Enumerated constant types using existing ordinal types...
Post by: winni on April 08, 2020, 01:24:32 am
Yep?????

1=0

?????
Title: Re: Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 08, 2020, 01:32:12 am
I had the numeric index values wrong.

Code: Pascal  [Select][+][-]
  1. type
  2.   TCalDays= (Sunday=0, Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6);

My point stands...
Title: Re: Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 08, 2020, 05:39:45 am
@winni
@mercurhyo

While it is still 1 step more required than what I would prefer, the GetEnumName() and GetEnumValue() functions are 1 step less than would be required using the WriteStr() function (they eliminate the need for use of a variable), and I think I can use them to work with current enumerated type structure as follows.

Code: Pascal  [Select][+][-]
  1. type
  2.   TCalDays = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
  3.  
  4. procedure TMainForm.FormCreate(Sender: TObject);
  5. begin
  6.     ShowMessage(GetEnumName(TypeInfo(TCalDays), Ord(Tuesday)));         //Displays "Tuesday"...
  7.  
  8.     ShowMessage(InttoStr(GetEnumValue(TypeInfo(TCalDays), 'Tuesday'))); //Displays "2"...
  9. end;

Found this at:

https://forum.lazarus.freepascal.org/index.php?topic=33819.0 (https://forum.lazarus.freepascal.org/index.php?topic=33819.0)

Many thanks to both of you gentlemen for your assistance!
Title: Re: Enumerated constant types using existing ordinal types...
Post by: PascalDragon on April 08, 2020, 10:47:11 am
While it is still 1 step more required than what I would prefer, the GetEnumName() and GetEnumValue() functions are 1 step less than would be required using the WriteStr() function (they eliminate the need for use of a variable), and I think I can use them to work with current enumerated type structure as follows.

But if you look at the code you'll see that using GetEnumName is less efficient than using WriteStr (use of the former results in an implicit exception frame, and GetEnumValue needs to do pointer adjustments to get the names after a check whether it's dealing with Booleans while the later directly passes the conversion table to the writer function and there's no implicit exception frame).

Also you can always create yourself a type helper:

Code: Pascal  [Select][+][-]
  1. // interface section
  2. type
  3.   TCalDaysHelper = type helper for TCalDays
  4.     function ToString: String; inline;
  5.   end;
  6.  
  7. // implementation section
  8. function TCalDaysHelper.ToString: String;
  9. begin
  10.   WriteStr(Result, Self);
  11. end;
  12.  
  13. // somewhere else:
  14. Tuesday.ToString
  15. // or
  16. caldaysvar.ToString
Title: Re: [Solved] Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 08, 2020, 06:28:32 pm
rvk
Quote
Hero Member
*****

Posts: 3950

Re: Getting a string representation of an enum value
« Reply #4 on: August 25, 2016, 04:20:17 pm »
Quote from: fatmonk on August 25, 2016, 04:19:36 pm
I did look at WriteStr() but missed that the result gets sent to the first argument...
I also edited my post to include the GetEnumName-example which is what WriteStr() uses internally.

The line:

Quote
I also edited my post to include the GetEnumName-example which is what WriteStr() uses internally.

from that post in the link I provided earlier is the only reason I went with the GetEnumName() function over the WriteStr() procedure.

I wish there was a way to verify whether that particular statement is true.
Title: Re: [Solved] Enumerated constant types using existing ordinal types...
Post by: JdeHaan on April 08, 2020, 06:44:44 pm
on my mac with Catalina this prints the text 'Tuesday'.

Code: Pascal  [Select][+][-]
  1. program enumwrite;
  2.  
  3. type
  4.   TCalDays= (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
  5.  
  6. begin
  7.   writeln(TCalDays.Tuesday); // prints 'Tuesday'
  8. end.
  9.  
  10.  


Lazarus 2.1.0 r62775 FPC 3.3.1 x86_64-darwin-cocoa (beta)
Title: Re: [Solved] Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 08, 2020, 08:36:05 pm
Code: Pascal  [Select][+][-]
  1. Type ControlCharacters = (
  2.     CTL_AKNWLDGMNT : Char = #6, //Control character; acknowledgment.
  3.     CTL_BACKSPACE : Char = #8,  //Control character; backspace.
  4.     CTL_BELL : Char = #7,       //Control character; bell ("ding") sound.
  5.     CTL_CANCEL : Char = #24;    //Control character; cancel.
  6.     CTL_CRGRTRN : Char = #13,   //Control character; carriage return.
  7.     CTL_DATALINK : Char = #16   //Control character; data link.
  8.   );
  9.  
  10.  
  11.   Type DrawingCharacters = (
  12.     DWG_ALT179 : String = '│', //Drawing character; line - single vertical. Equal to {Alt+179}.
  13.     DWG_ALT180 : String = '┤', //Drawing character; right coupler - single vertical/single horizontal. Equal to {Alt+180}.
  14.     DWG_ALT181 : String = '╡', //Drawing character; right coupler - single vertical/double horizontal. Equal to {Alt+181}.
  15.     DWG_ALT182 : String = '╢', //Drawing character; right coupler - double vertical/double horizontal. Equal to {Alt+182}.
  16.     DWG_ALT183 : String = '╖', //Drawing character; right upper connector - double vertical/single horizontal. Equal to {Alt+183}.
  17.     DWG_ALT184 : String = '╕'  //Drawing character; right upper connector - single vertical/double horizontal. Equal to {Alt+184}.
  18.   );

Both Type enumerations above are non-functional mockups do demonstrate my needs.

For string enumerations, the techniques proposed so far will often work, though not always, especially if the string is long. It wouldn't make sense to have an enumeration element name that is 50 characters long.

Also, in such cases as above, it is not feasible to use the shown literal values and hash values as element names, either. In most case, it is the element value I need to access and not the element name.  In cases where the required value would always be a number, this would not be an issue. However, the required value often needs to be a string or a character, which enumerated types do not allow.

I need...

Code: Pascal  [Select][+][-]
  1. ShowMessage(DrawingCharacters.DWG_ALT182); //Displays "╢"

rather than...

Code: Pascal  [Select][+][-]
  1. ShowMessage(DrawingCharacters.DWG_ALT182); //Displays "DWG_ALT182"

So, unless types structs are implemented, similar to...

Code: Pascal  [Select][+][-]
  1. Struct CriticalErrors : int64 //Enumerated constant type named "CriticalErrors' - of type int64...
  2.   AccessViolation = 4;
  3.   AppDomainUnloaded = 3;
  4.   BadImageFormat = 5;
  5.   CantUnloadAppDomain = 6;
  6.   ExecutionEngine = 7;
  7.   InvalidProgram = 9;
  8.   NonCritical = 1;
  9.   OutOfMemory = 2;
  10.   StackOverflow = 8;
  11.   ThreadAbort = 10;
  12. End;
  13.  
  14. Struct CalendarDays : String //Enumerated constant type named "CalendarDays' - of type String...
  15.   Day01 = 'Sunday';
  16.   Day02 = 'Monday';
  17.   Day03 = 'Tuesday';
  18.   Day04 = 'Wednesday';
  19.   Day05 = 'Thursday';
  20.   Day06 = 'Friday';
  21.   Day07 = 'Saturday';
  22. End;

I think it will just be more efficient for me to continue using regular constants in Object Pascal.
Title: Re: [Solved] Enumerated constant types using existing ordinal types...
Post by: PascalDragon on April 09, 2020, 01:47:53 pm
rvk
Quote
Hero Member
*****

Posts: 3950

Re: Getting a string representation of an enum value
« Reply #4 on: August 25, 2016, 04:20:17 pm »
Quote from: fatmonk on August 25, 2016, 04:19:36 pm
I did look at WriteStr() but missed that the result gets sent to the first argument...
I also edited my post to include the GetEnumName-example which is what WriteStr() uses internally.

The line:

Quote
I also edited my post to include the GetEnumName-example which is what WriteStr() uses internally.

from that post in the link I provided earlier is the only reason I went with the GetEnumName() function over the WriteStr() procedure.

I wish there was a way to verify whether that particular statement is true.

As I wrote in my reply above WriteStr is more efficient, because it's handled by the compiler (the compiler directly passes the enum's Ordinal-to-String table as well as the ordinal value of the enum to fpc_write_text_enum while GetEnumName needs to retrieve the pointer to that table using RTTI first).

Code: Pascal  [Select][+][-]
  1. Type ControlCharacters = (
  2.     CTL_AKNWLDGMNT : Char = #6, //Control character; acknowledgment.
  3.     CTL_BACKSPACE : Char = #8,  //Control character; backspace.
  4.     CTL_BELL : Char = #7,       //Control character; bell ("ding") sound.
  5.     CTL_CANCEL : Char = #24;    //Control character; cancel.
  6.     CTL_CRGRTRN : Char = #13,   //Control character; carriage return.
  7.     CTL_DATALINK : Char = #16   //Control character; data link.
  8.   );
  9.  
  10.  
  11.   Type DrawingCharacters = (
  12.     DWG_ALT179 : String = '│', //Drawing character; line - single vertical. Equal to {Alt+179}.
  13.     DWG_ALT180 : String = '┤', //Drawing character; right coupler - single vertical/single horizontal. Equal to {Alt+180}.
  14.     DWG_ALT181 : String = '╡', //Drawing character; right coupler - single vertical/double horizontal. Equal to {Alt+181}.
  15.     DWG_ALT182 : String = '╢', //Drawing character; right coupler - double vertical/double horizontal. Equal to {Alt+182}.
  16.     DWG_ALT183 : String = '╖', //Drawing character; right upper connector - double vertical/single horizontal. Equal to {Alt+183}.
  17.     DWG_ALT184 : String = '╕'  //Drawing character; right upper connector - single vertical/double horizontal. Equal to {Alt+184}.
  18.   );

Both Type enumerations above are non-functional mockups do demonstrate my needs.

For string enumerations, the techniques proposed so far will often work, though not always, especially if the string is long. It wouldn't make sense to have an enumeration element name that is 50 characters long.

Also, in such cases as above, it is not feasible to use the shown literal values and hash values as element names, either. In most case, it is the element value I need to access and not the element name.  In cases where the required value would always be a number, this would not be an issue. However, the required value often needs to be a string or a character, which enumerated types do not allow.

I need...

Code: Pascal  [Select][+][-]
  1. ShowMessage(DrawingCharacters.DWG_ALT182); //Displays "╢"

rather than...

Code: Pascal  [Select][+][-]
  1. ShowMessage(DrawingCharacters.DWG_ALT182); //Displays "DWG_ALT182"

Why not use something like this?

Code: Pascal  [Select][+][-]
  1. {$ScopedEnums On}
  2. type
  3.   TDrawingCharacters = (
  4.     DWG_ALT179,
  5.     DWG_ALT180,
  6.     DWG_ALT181,
  7.     DWG_ALT182,
  8.     DWG_ALT183,
  9.     DWG_ALT184,
  10.   );
  11.  
  12. const
  13.   DrawingCharacters: array[TDrawingCharacters] of Char = (
  14.     '│'
  15.     '┤'
  16.     '╡'
  17.     '╢'
  18.     '╖'
  19.     '╕'
  20.   );
  21.  
  22. // or instead of an operator overload a type helper as mentioned in my previous post
  23. operator := (aValue: TDrawingCharacter): String; // assignment operator for enum -> char is currently not allowed
  24. begin
  25.   Result := DrawingCharacters[aValue];
  26. end;
Title: Re: [Solved] Enumerated constant types using existing ordinal types...
Post by: GypsyPrince on April 10, 2020, 01:00:00 am
Quote
Why not use something like this?

That is actually a great suggestion for most sane people. But in my disturbed mind, it creates too much work to have to maintain down the road. If I ever have to make a change, that method creates 2 separate points to maintain(type and const) whereas structs or regular constants create only 1 point of maintenance. LOL
Title: Re: [Solved] Enumerated constant types using existing ordinal types...
Post by: PascalDragon on April 10, 2020, 10:47:10 am
At least here the compiler will remind you that you forgot to edit the other one, cause if you add an entry to TDrawingCharacters then the compiler will complain about a missing entry in DrawingCharacters.
TinyPortal © 2005-2018