Recent

Author Topic: Use an Ordinal in constant  (Read 4397 times)

Hansvb

  • Hero Member
  • *****
  • Posts: 602
Use an Ordinal in constant
« 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.


madref

  • Hero Member
  • *****
  • Posts: 949
  • ..... A day not Laughed is a day wasted !!
    • Nursing With Humour
Re: Use an Ordinal in constant
« Reply #1 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
« Last Edit: July 20, 2021, 07:26:32 pm by madref »
You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Lazarus 3.99 (rev main_3_99-649-ge13451a5ab) FPC 3.3.1 x86_64-darwin-cocoa
Mac OS X Monterey

Hansvb

  • Hero Member
  • *****
  • Posts: 602
Re: Use an Ordinal in constant
« Reply #2 on: July 20, 2021, 07:38:17 pm »
How does that work in a constant?
The constant gives the illegal expression error.

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Use an Ordinal in constant
« Reply #3 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.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
Re: Use an Ordinal in constant
« Reply #4 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.
Yours Sincerely
Kai Burghardt

Hansvb

  • Hero Member
  • *****
  • Posts: 602
Re: Use an Ordinal in constant
« Reply #5 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.

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Use an Ordinal in constant
« Reply #6 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.  
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1311
    • Lebeau Software
Re: Use an Ordinal in constant
« Reply #7 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))';
« Last Edit: July 21, 2021, 01:54:58 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
Re: Use an Ordinal in constant
« Reply #8 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).
Yours Sincerely
Kai Burghardt

 

TinyPortal © 2005-2018