Proposing 4 New Ideas - #1 Enumerations lazarus / 64-FPC development ---------------------------------------------------------------------- IndigoBoy83 · 2019-03-22 12:23 PAGE #1A - Introducing Enumerations, and Evalues on Enumerations We create a new type: enumerations (Shortened to "enums"). We create a new type of variable: evalues (Shortened to "evals"). An enumeration is a list of evalues. An evalue is defined "on" some enumeration. We suggest here that the evalue "void" should AUTOMATICALLY be included into every enumeration by force so all programmers can share it. Also, the following enumerations are all equivalent: "void", "void.void", "void.void.void", etc. The "root" of an evalue is the name of the enumeration of which is prescribes to. We suggest that the enumeration of all types defined in a program be called "etypes". We have an "eval on everything" if no enumeration is given.  By default, this enumeration is of etypes, which is any evalues present in any enumerations. Consider the code: 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    enum1 : enum = ( big, bad, ugly );    enum2 : enum = ( big, good, smart );    enum3 : enum = ( smart, bright );var   eval1 : eval on enum1;   eval2 : eval on enum2; If a particular evalue "eval1" is set to another evalue "eval2", then we'd write the code: 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 eval1 := eval2; Notice, this will be executed (in runtime) *only* if the actual value of eval2 resides in the enumeration enum1 of eval1.  If it does NOT reside in that said enumeration then the line of code will be IGNORED.  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 eval1 := enum1.big;  // Works!eval1 := enum2.smart;  // IGNORED! Notice, an evalue can be given which has no root and still 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 eval1 := big;  // Works!eval1 := smart;  // IGNORED! We introduce the function "str" which returns a string representation of an evalue.  Observe: 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 eval1 := bad;writeln( 'eval1 = ', str(eval1) );  // writes the value of eval1 eval1 = enum1.bad We can make a listing of all evals in an enumerations by the following: One can delineate the evalues of an enumeration by using the square brackets "[" and "]".  This is demonstrated below: 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 writeln( '1st evalue in enum1: ', str(enum1[1]) );writeln( '2nd evalue in enum1: ', str(enum1[2]) );writeln( '3rd evalue in enum1: ', str(enum1[3]) );writeln( '4th evalue in enum1: ', str(enum1[4]) );writeln( '5th evalue in enum1: ', str(enum1[5]) ); Note, when accessing an evalue that is not present in an enumeration then we get the standard evalue "void". 1st evalue in enum1: big 2nd evalue in enum1: bad 3rd evalue in enum1: ugly 4th evalue in enum1: void 5th evalue in enum1: void We introduce the compiler words "exists in" so that one can test whether some evalue resides in some enumeration: 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 if eval1 exists in enum2 then writeln('The evalue ', str(eval1), ' exists in the enumeration enum2'); It should be allowed to create new enumerations recycling old ones by using unions, intersections, and negations of them. We write "union enumeration" as "OR". We write "intersection enumeration" as "AND". We write "negation enumeration" as "NOT". For example, using the above enum1, enum2 and enum3, we create: 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    enum4 : enum = enum1 OR enum2;    enum5 : enum = enum1 AND enum2;    enum6 : enum = (enum1 OR enum2) AND (NOT enum3). enum4 now consists of the five evalues: big, bad, ugly, good, smart enum5 now consists of the one evalue: big enum6 now consists of the four evalues: big, bad, ugly, good Notice that every enumeration *must* be properly defined in the "type section" of the program.  That is, every enumeration must have a *proper* name for otherwise the compiler will be confused as to what the root of the enumeration is for a given evalue. One can create an enumeration *on* an enumeration 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    enum7 : enum = (enum1, enum2); enum7 now consists of the five evalues: enum1.big, enum1.bad, enum1.ugly, enum2.big, enum2.good, enum2.smart This allows enumerations to be nested within others. The following is sample code: 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 Example_Using_Evalues_On_Enumerations; type    colors : enum = ( blue, red, black );    sizes : enum = ( small, medium, big );    brands : enum = ( honda, ford );    faces : enum = ( colors, sizes ); var   myeyecolor : eval on colors;   mynosesize : eval on sizes;   mycarbrand : eval on brands;   myface : eval on faces;  // NOTE: Only color (in my eye) and size (in my nose) can reside in faces.  The evalue of brand (in my car) cannot.    some_eval : eval;  // The "default" eval is on "etypes" begin  // Setting myeyecolor to black, mynosesize to medium, mycarbrand to honda     writeln( 'Setting myeyecolor to black, mynosesize to medium, and mycarbrand to honda' );     myeyecolor := colors.black;    mynosesize := sizes.medium;    mycarbrand := brand.honda;     writeln( '(1) My eyecolor: ', str(myeyecolor) );  // Will output "(1) My eyecolor: colors.black"    writeln( '(1) My nosesize: ', str(mynosesize) );  // Will output "(1) My nosesize: sizes.medium"    writeln( '(1) My carbrand: ', str(mycarbrand) );  // Will output "(1) My carbrand: brands.honda"    // Something about myface is either black (in myeyecolor) or medium (in mynosesize) but NOT honda (mycarbrand)     writeln( 'Something about myface is either colors.black or sizes.medium but NOT brand.honda' );     myface := myeyecolor;    writeln( '(2) Something about my face: ', str(myface) );  // Will output "(2) Something about my face: colors.black"     myface := mynosesize;    writeln( '(2) Something about my face: ', str(myface) );  // Will output "(2) Something about my face: sizes.medium"     myface := mycarbrand;  // This line is IGNORED because mycarbrand isn't something in things_aboutmyface    writeln( '(2) Something about my face: ', str(myface) );  // Will again output "(2) Something about my face: sizes.medium" (which was set before)   // Listing all the evalues in enumeration things_aboutmyface     writeln( 'Listing evalues in faces' );     writeln( '(3) faces[1]: ', str(faces[1]) );  // Will output "(3) faces[1]: colors.blue"    writeln( '(3) faces[2]: ', str(faces[2]) );  // Will output "(3) faces[2]: colors.red"    writeln( '(3) faces[3]: ', str(faces[3]) );  // Will output "(3) faces[3]: colors.black"    writeln( '(3) faces[4]: ', str(faces[4]) );  // Will output "(3) faces[4]: sizes.small"    writeln( '(3) faces[5]: ', str(faces[5]) );  // Will output "(3) faces[5]: sizes.medium"    writeln( '(3) faces[6]: ', str(faces[6]) );  // Will output "(3) faces[6]: sizes.big"    writeln( '(3) faces[7]: ', str(faces[7]) );  // Will output "(3) faces[7]: void"    writeln( '(3) faces[8]: ', str(faces[8]) );  // Will output "(3) faces[8]: void"   // Resetting myeyecolor as blue using some_eval      some_eval := blue;     writeln( 'Some_eval: ', str(some_eval) );  // Will output "Some_eval: blue".  NOTE: this eval does not have a root.     writeln( 'Setting myeyecolor, mynosesize, and mycarbrand to some_eval (some will be ignored)' );      myeyecolor := some_eval;     mynosesize := some_eval;  // This line is IGNORED because the evalue of some_eval right now (blue) is not in sizes     mycarbrand := some_eval;  // This line is IGNORED because the evalue of some_eval right now (blue) is not in brands      writeln( '(4) My eyecolor: ', str(myeyecolor) );  // Will output "(4) My eyecolor: colors.blue"     writeln( '(4) My nosesize: ', str(mynosesize) );  // Will output "(4) My nosesize: sizes.medium"      writeln( '(4) My carbrand: ', str(mycarbrand) );  // Will output "(4) My carbrand: brands.honda"   // Setting everything to void      some_eval := void;     writeln( 'Some_eval: ', str(some_eval) );  // Will output "Some_eval: void"     writeln( 'Setting myeyecolor, mynosesize, and mycarbrand to some_eval (none will be ignored)' );      myeyecolor := some_eval;     mynosesize := some_eval;     mycarbrand := some_eval;      writeln( '(5) My eyecolor: ', str(myeyecolor) );  // Will output "(5) My eyecolor: colors.void"     writeln( '(5) My nosesize: ', str(mynosesize) );  // Will output "(5) My nosesize: sizes.void;"      writeln( '(5) My carbrand: ', str(mycarbrand) );  // Will output "(5) My nosesize: cars.void;"end. The output of the above code: 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 Setting myeyecolor to black, mynosesize to medium, and mycarbrand to honda(1) My eyecolor: colors.black(1) My nosesize: sizes.medium(1) My carbrand: brands.hondaSomething about myface is either colors.black or sizes.medium but NOT brand.honda(2) Something about my face: colors.black(2) Something about my face: sizes.medium(2) Something about my face: sizes.mediumListing evalues in faces(3) faces[1]: colors.blue"(3) faces[2]: colors.red"(3) faces[3]: colors.black"(3) faces[4]: sizes.small"(3) faces[5]: sizes.medium"(3) faces[6]: sizes.big"(3) faces[7]: void"(3) faces[8]: void"Some_eval: blueSetting myeyecolor, mynosesize, and mycarbrand to some_eval (some will be ignored)(4) My eyecolor: colors.blue(4) My nosesize: sizes.medium(4) My carbrand: brands.hondaSome_eval: voidSetting myeyecolor, mynosesize, and mycarbrand to some_eval (none will be ignored)(5) My eyecolor: colors.void(5) My nosesize: sizes.void(5) My nosesize: cars.void ------------------------------------------------------------------ PAGE #1B - Introducing Esets on Enumerations We now create sets of evalues which we call "esets".  An eset is defined "of" some enumeration. Every enumeration can be used to define an eset; that is, any enumeration in the definition of an eset represents an eset of the enumeration where all of its evalues are present. The following code describes its use: 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 Example_Using_Esets_Of_Enumerations; type    colors : enum = ( blue, red, black, green ); Procedure Describe_Painting( apainting : eset of colors );var   acolor : eval on colors;begin  for acolor in apainting do    writeln( 'The color ', str(acolor), ' is in the painting.' );end; var   mypainting : eset of colors; begin  writeln('Making mypainting "blue AND red"');  mypainting := blue AND red;  Describe_Painting( mypainting );  // Will output that the colors blue and red are in mypainting   writeln('Making mypainting "(colors) AND NOT (blue OR red)"');  mypainting := (colors) AND NOT (blue OR red);  Describe_Painting( mypainting );  // Will output that the colors black and green are in mypaintingend. The output of the above code: Making mypainting "blue AND red" The color blue is in the painting. The color red is in the painting. Making mypainting "(colors) AND NOT (blue OR red)" The color black is in the painting. The color green is in the painting. We introduce the function "ord" which returns a numeral to the placing of an evalue in a given enumeration.  A variable whose type is an eset is constructed in the RAM as a sequence of bits, the number of which is equivalent to the number of evalues in the enumeration to which it perscribes to.  If the ith evalue in the enumeration is present in the eset, then the ith bit in the variable is 1.  Conversely, if the ith evalue in the enumeration is not present in the eset, then the ith bit in the variable is 0.  So, we introduce the ability to use the weird-brackets "{" and "}" to indicate which bit of a variable should be accessed/altered.  (I strongly believe the use of the weird-brackets should be henceforth used in general to delineate the bit of ANY VARIABLE.  The use of these brackets as comments should be changed/abandoned.) As 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 Program Further_Examples_Using_Evalues_And_Esets; type    colors : enum = ( blue, red, black, green, orange, purple, yellow ); Procedure Write_Colors( _setcolors : eset of color );var   acolor : eval on colors;begin  for acolor in colors do    write( ord(acolor), str(acolor), ' ' );  writeln;end; var   myclothingcolors : eset of colors; begin  writeln( 'The following colors exist:' );  Write_Colors( colors );   myclothingcolors := blue AND black AND purple;   writeln( 'My clothing is colored: ' );  Write_Colors( myclothingcolors );   writeln( 'Changing my attire (clothes)' );   myclothingcolors{1} := 0;  // not present  myclothingcolors{2} := 1;  // present  myclothingcolors{3} := false;  // not present  myclothingcolors{4} := true;  // present  myclothingcolors{5} := 5-5;  // not present  myclothingcolors{6} := 6-5;  // present  myclothingcolors{7} := true AND false;  // not present   writeln( 'My clothing is now colored: ' );  Write_Colors( myclothingcolors );end. The output of the above code: The following colors exist: 1blue 2red 3black 4green 5orange 6purple 7yellow My clothing is colored: 1blue 3black 6purple Changing my attire (clothes) My clothing is now colored: 2red 4green 6purple Notice that although the evalue "void" is present in every enumeration, when one makes the call such as "for acolor in colors do.." we will never get acolor taking on the value of "void"; it is simply not allowed by force. ---------------------------------------------------------------------- marcov · 2019-03-22 13:06 - "void" is not a Pascal standard. Empty set would be logical, but these are enums, not sets. - seems rather stringly typed. - What should happen if I assign enum2.big to eval1 ? Besides I fail to see any practical benefit to this feature, or why you would need to mix identifiers from various enum types. (See also https://www.freepascal.org/faq.html#extensionselect) ---------------------------------------------------------------------- Ñuño_Martínez · 2019-03-24 11:57 Did a diagonal reading* and I think this is just add complexity to actual Pascal enumerations without any real advantage.  Also I don't get the use of the of and on keywords.  May be you're confused and you think you're talking about a different programing language (ADA? Algol? ...). _________________ * Just read spare phrases and sections instead of read all the text.  Mostly small paragraphs and code snippets. ---------------------------------------------------------------------- ASBzone · 2019-03-24 15:17 Quote from: IndigoBoy83 on March 22, 2019, 01:23:30 pmPAGE #1A - Introducing Enumerations, and Evalues on Enumerations This is interesting, but the one question that seems to remain unanswered is, what advantage would this feature offer? I liked the STR function which would make it easier to use and display values in a set, but beyond that, I couldn't see what the advantage of all the rest was. What problem or problems would be eliminated by the implementation of this functionality?  I cannot speak for others, but I found it hard to understand that part. ---------------------------------------------------------------------- BeniBela · 2019-03-24 15:38 Perhaps it could be useful to extend enumerations? Like for string list sorting there is an enum TStringsSortStyle = (sslNone,sslUser,sslAuto). Someone who extends string list, might want to add more sorting modes, e.g. sslAutoAscending, sslAutoDescending, sslAutoNumeric, ..., but atm you can't extend the enum ---------------------------------------------------------------------- lucamar · 2019-03-24 17:15 Quote from: BeniBela on March 24, 2019, 04:38:18 pmPerhaps it could be useful to extend enumerations? Like for string list sorting there is an enum TStringsSortStyle = (sslNone,sslUser,sslAuto). Someone who extends string list, might want to add more sorting modes, e.g. sslAutoAscending, sslAutoDescending, sslAutoNumeric, ..., but atm you can't extend the enum Extending base types must always be done, if at all, with extreme care and having very clear what the objective is and whether there is a real need to extend the type. In the case you cite, for example, it's not only uneeded but actively harmful. What you want isn't realy an extension of sorting modes but a ... let's call it "specialization" of sslAuto, so it's better to create a new enumeration + set, say: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 TAutoSortStyles = (assDefault, assDescending, assNumeric); {Default is Alpha-Ascending}TAutoSortStyle = set of TAutoSortStyles; All you would need then is to override the default sort to take into account a new property, say:   AutoSortStyle: TAutoSortStyle; And all that, without having to touch a hair of the compiler ---------------------------------------------------------------------- PascalDragon · 2019-03-25 08:20 Quote from: ASBzone on March 24, 2019, 04:17:52 pmI liked the STR function which would make it easier to use and display values in a set, but beyond that, I couldn't see what the advantage of all the rest was. In Write(ln) you can already directly use enum values and have their names printed. Same with WriteStr. Using generic functions you can even wrap that into a function instead of having to declare an additional variable. And to display a whole set one can always use TypInfo.SetToString. ---------------------------------------------------------------------- ASBzone · 2019-03-27 19:42 Quote from: PascalDragon on March 25, 2019, 09:20:51 amIn Write(ln) you can already directly use enum values and have their names printed. Same with WriteStr. Using generic functions you can even wrap that into a function instead of having to declare an additional variable. And to display a whole set one can always use TypInfo.SetToString. Thanks, PascalDragon