Lazarus

Free Pascal => General => Topic started by: Hansvb on July 20, 2021, 07:20:03 pm

Title: Use an Ordinal in constant
Post by: Hansvb on July 20, 2021, 07:20:03 pm
Hi,

How can I use an ordinal type in a constant? I have this:


Code: Pascal  [Select][+][-]
  1.       type
  2.         TTableNames = (SETTINGS_META);  //Ordinal (Enumerated types)
  3.  
  4.       var
  5.       TableName :     TTableNames;
  6.  
  7.       const creMetaTbl = 'CREATE TABLE IF NOT EXISTS '+ TableName.SETTINGS_META + '(' +
  8.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  9.                                 'VALUE              VARCHAR(255))';
  10.  

This gives the error: illegal expression.

Title: Re: Use an Ordinal in constant
Post by: madref on July 20, 2021, 07:23:21 pm
shouldn't there be a space between ten '(' else the tablename will be something like '10(Key......'
' (' ....
Code: Pascal  [Select][+][-]
  1. const creMetaTbl = 'CREATE TABLE IF NOT EXISTS '+ TableName.SETTINGS_META + ' (' +  
  2.                               'KEY                VARCHAR(50)  UNIQUE  ,' +
  3.                               'VALUE              VARCHAR(255))';
  4.  


If you have an illegal expression make the expression visible on your screen with
Code: Pascal  [Select][+][-]
  1. ShowMessage (string);
then you can see what you have done
Title: Re: Use an Ordinal in constant
Post by: Hansvb on July 20, 2021, 07:38:17 pm
How does that work in a constant?
The constant gives the illegal expression error.
Title: Re: Use an Ordinal in constant
Post by: alpine on July 20, 2021, 08:05:42 pm
Hi,

How can I use an ordinal type in a constant? I have this:


Code: Pascal  [Select][+][-]
  1.       type
  2.         TTableNames = (SETTINGS_META);  //Ordinal (Enumerated types)
  3.  
  4.       var
  5.       TableName :     TTableNames;
  6.  
  7.       const creMetaTbl = 'CREATE TABLE IF NOT EXISTS '+ TableName.SETTINGS_META + '(' +
  8.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  9.                                 'VALUE              VARCHAR(255))';
  10.  

This gives the error: illegal expression.

You can't. It is illegal to concatenate string with other than string or character.
Title: Re: Use an Ordinal in constant
Post by: Kays on July 20, 2021, 08:39:57 pm
How can I use an ordinal type in a constant?
Just like that.
Code: Pascal  [Select][+][-]
  1. program ordinalValueDemo(input, output, stdErr);
  2. type
  3.         resolution = (HD, HDDeluxe, HDPremium);
  4. const
  5.         standardResolution = HD;
  6. begin
  7. end.

I have this:
Uhm, what do you want to achieve by this design? If you want to ensure there are no duplicate table names, this is rather a task of your DBMS, not your Pascal program.
The FPC’s standard RTL can convert the names of ordinal value members at run‑time using write/writeLn/writeStr, but there ain’t no function nor syntax that does the same at compile-time (i. e. in constant definitions). For example:
Code: Pascal  [Select][+][-]
  1. program enumerationConversionDemo(input, output, stdErr);
  2. type
  3.         table = (settingsMeta);
  4. const
  5.         createTable = 'create table if not exists ';
  6. var
  7.         query: string;
  8. begin
  9.         writeStr(query, createTable, settingsMeta,
  10.                 ' (key varchar(50) unique, value varchar(255));');
  11.         query := upcase(query);
  12.        
  13.         writeLn(query);
  14. end.
Title: Re: Use an Ordinal in constant
Post by: Hansvb on July 20, 2021, 09:34:34 pm
Quote
Uhm, what do you want to achieve by this design?

What i would like is that i have all my table names in one place in one list. So if i later want to change a table name i have to change it in one place and not in a lot of places. I thought that ordinals where the way to go.
If that is not possible then i just have to type them where i need them.
Title: Re: Use an Ordinal in constant
Post by: alpine on July 20, 2021, 10:19:14 pm
Quote
Uhm, what do you want to achieve by this design?

What i would like is that i have all my table names in one place in one list. So if i later want to change a table name i have to change it in one place and not in a lot of places. I thought that ordinals where the way to go.
If that is not possible then i just have to type them where i need them.

Code: Pascal  [Select][+][-]
  1. type
  2.   TTableOrd = (toTable1, toTable2, toTable3);
  3.  
  4. const
  5.   TableNames: array[TTableOrd] of String = (
  6.     {toTable1} 'Table1',
  7.     {toTable2} 'Table2',
  8.     {toTable3} 'Table3'
  9.   );
  10.  
  11.   function GetCreateSQL(ATable: TTableOrd): String;
  12.   begin
  13.     Result := 'CREATE TABLE IF NOT EXISTS ' + TableNames[ATable] + ' (' +
  14.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  15.                                 'VALUE              VARCHAR(255))';
  16.   end;
  17.  
  18.   //....
  19.   GetCreateSQL(toTable1);

That is: a mapping table from ordinal to string.
Is that suitable for the purpose?

At the other hand, probably you'll want a different columns for each table, so you'll need yet another dim for the  + '(key varchar(50) unique, value varchar(255))' thing. Something like:
Code: Pascal  [Select][+][-]
  1. const
  2.   TableNames: array[TTableOrd, 1..2] of String = (
  3.     {toTable1} ('Table1', '(key varchar(50) unique, value varchar(255))'),
  4.     {toTable2} ('Table2', '(key varchar(50) unique, ...)'),
  5.     {toTable3} ('Table3', '(key varchar(50) unique, ...)')
  6.   );
  7.  
  8.   function GetCreateSQL(ATable: TTableOrd): String;
  9.   begin
  10.     Result := 'CREATE TABLE IF NOT EXISTS ' + TableNames[ATable, 1] + ' ' + TableNames[ATable, 2];
  11.   end;
  12.  
Title: Re: Use an Ordinal in constant
Post by: Remy Lebeau on July 21, 2021, 01:52:07 am
What i would like is that i have all my table names in one place in one list. So if i later want to change a table name i have to change it in one place and not in a lot of places.

An admirable goal.

I thought that ordinals where the way to go.

Only if the actual names are stored in a separate array, and the ordinals are used as indexes into that array, like how y.ivanov showed.

The alternative is to use string constants instead.  You could store them as individual constants in a separate unit, eg:

Code: Pascal  [Select][+][-]
  1. unit TableNames;
  2.  
  3. interface
  4.  
  5. const
  6.   SETTINGS_META = 'SETTINGS_META';
  7.   ...
  8.  
  9. implementation
  10.  
  11. end.

Code: Pascal  [Select][+][-]
  1. uses
  2.   ..., TableNames;
  3.  
  4. const creMetaTbl = 'CREATE TABLE IF NOT EXISTS ' + TableNames.SETTINGS_META + '(' +
  5.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  6.                                 'VALUE              VARCHAR(255))';

Or, as constant members of a class, eg:

Code: Pascal  [Select][+][-]
  1. type
  2.   TTableNames = class
  3.   public
  4.     const SETTINGS_META = 'SETTINGS_META';
  5.     ...
  6.   end;
  7.  
  8. ...
  9.  
  10. const creMetaTbl = 'CREATE TABLE IF NOT EXISTS ' + TTableNames.SETTINGS_META + '(' +
  11.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  12.                                 'VALUE              VARCHAR(255))';
Title: Re: Use an Ordinal in constant
Post by: Kays on July 21, 2021, 02:21:03 pm
[…] You could store them as individual constants in a separate unit, eg: […]
I’m not a fan of duplicating data. Per se, I like to create enumeration data types as often as possible, because they create incompatibilites, i. e. I can use them as formal parameters and thus easily restrict the range of acceptable values.

I’d really rather write a conversion function, or even a simple type helper:
Code: Pascal  [Select][+][-]
  1. {$modeSwitch typeHelpers+}
  2. type
  3.         table = (settingsMeta);
  4.         tableHelper = type helper for table
  5.                         function asString(): string;
  6.                 end;
  7.  
  8. function tableHelper.asString(): string;
  9. begin
  10.         writeStr(asString, self);
  11.         asString := upCase(asString);
  12. end;
It’s just a few lines of code. Then you can write settingsMeta.asString. This will work fine for all table names that are shorter than 127 characters (FPC’s limit for significant characters in identifiers). This kind of implementation will “nicely” crash if you are attempting to convert the name of a “non‑existent” table (e. g. table(42).asString).
TinyPortal © 2005-2018