7

I'm trying to make a custom data type for days of the week but I can't get it to write it. The compiler error says this:

[Error] hours.dpr(28): Illegal type in Write/Writeln statement

program hours;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TypeDay = (Sun,Mon,Tue,Wed,Thu,Fri,Sat);

var day: TypeDay;

begin
     for day := Sun to Sat do
     begin
         writeln(day);
     end;
end.

It's in Delphi 7 on Windows.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Tom
  • 79
  • 1
  • 2

5 Answers5

17

You don't need to write Assembler for this; TypInfo include all that you need for do this (get the string associated to an enumerated value).

This code:

program hours;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  TypInfo;

type
  TypeDay = (Sun,Mon,Tue,Wed,Thu,Fri,Sat);

var
  day: TypeDay;
  Str:String;

begin
     for day := Sun to Sat do begin
        Str := GetEnumName(TypeInfo(TypeDay),ord(day));
         writeln(Str);
     end;
end.

And this is the output:

alt text

Regards.

  • 1
    +1. This is the proper way to convert an enumeration to a string. – Mason Wheeler Dec 16 '10 at 12:40
  • 3
    Note this will not work if the enum members are assigned specific ordinal values, in which case the compiler strips the RTTI. (At least this has been the case in every version of Delphi I've used) Not really sure the reason for this. In these situations a key/value pair is a reasonable solution. – Kenneth Cochran Dec 16 '10 at 15:56
  • @codeelegance-> Please can you post a sample type of this situation. I use RTTI and this code and never it fail for me. – Germán Estévez -Neftalí- Dec 16 '10 at 16:31
  • 2
    `TypeDay = (Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7);` should do it. – Kenneth Cochran Dec 16 '10 at 16:51
  • 1
    Researched this and apparently the compiler doesn't generate RTTI for enums assigned ordinals that differ from what the compiler would've assigned. So discontiguous enums and enums that don't start with 0 would trigger this. See [here.](http://stackoverflow.com/questions/1420562/why-do-i-get-type-has-no-typeinfo-error-with-an-enum-type/1420649#1420649) – Kenneth Cochran Dec 16 '10 at 17:03
11

Tom, Writeln does not support a Enum as parameter. you must call to the Ordfunction to get the ordinal representation. if you wanna show the names of your TypeDay you can write a code like this.

program hours;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TypeDay     = (Sun,Mon,Tue,Wed,Thu,Fri,Sat);
const
  TypeDayStr  : Array[TypeDay] of string = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');

var day: TypeDay;

begin
     for day := Sun to Sat do
       writeln( Ord(day));

     for day := Sun to Sat do
       writeln( TypeDayStr[day]);

     Readln;
end.
RRUZ
  • 134,889
  • 20
  • 356
  • 483
4

You can use RTTI to write the enumerate names.

Here is an optimized function I wrote some time ago:

program hours;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function GetEnumName(aTypeInfo: pointer; aIndex: integer): PShortString;
asm // get enumerate name from RTTI
    or edx,edx
    movzx ecx,byte ptr [eax+1] // +1=TTypeInfo.Name
    mov eax,[eax+ecx+1+9+1] //BaseType
    mov eax,[eax]
    movzx ecx,byte ptr [eax+1]
    lea eax,[eax+ecx+1+9+4+1] // eax=EnumType.BaseType^.EnumType.NameList
    jz @0
@1: movzx ecx,byte ptr [eax]
    dec edx
    lea eax,eax+ecx+1 // next short string
    jnz @1
@0:
end;

type
  TypeDay = (Sun,Mon,Tue,Wed,Thu,Fri,Sat);

var day: TypeDay;

begin
     for day := Sun to Sat do
     begin
         writeln(GetEnumName(TypeInfo(TypeDay),ord(day))^);
     end;
end.

But be warned that this version doesn't check for that aIndex to be in range.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • you got to be kidding! writing assembler code in Delphi? what for? – none Dec 16 '10 at 09:59
  • 4
    @David Heffernan: I think this is his optimized version. There is no need to downvote. – ali_bahoo Dec 16 '10 at 10:46
  • 3
    @sad_man It's a pointless optimisation and it's liable to get broken when the implementation changes in a new release. It's very bad practice to write code like this when documented, maintained, public interfaces exist. – David Heffernan Dec 16 '10 at 12:10
  • 1
    Although sometimes they don't perform well. Try GetProperty from new RTTI, then GetPropInfo from old RTTI, compare the speed: 50 times faster. – himself Dec 16 '10 at 14:29
  • I wrote this was an optimized function. So don't blame me. I used such asm functions in our ORM, because I needed the RTTI to be accessed with huge speed. In the ORM code, it uses the record structures of the System.pas definition, so it's more reliable than this hard-coded but working version. Note that there is also PUREPASCAL version of the asm optimized RTTI functions, and also a possibility to use TypInfo (for instance, it won't block compiling the code with FPC) in our units. So I agree with your comments, of course. I try to make it as fast as possible, AND maintain compatibility. – Arnaud Bouchez Dec 16 '10 at 18:19
2

Enumerations are not strings, so you need to convert them.
For conversion, you can use the GetEnumName function from the Delphi TypInfo unit as explained at delphi.about.com.

--jeroen

Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154
0

Interestingly enough, I'm able to use readLn with enum types in FPC (Lazarus), but will throw the same error (illegal type) as mentioned above in Delphi, Oxygene, PascalABC.Net...


    type
        beverage = (coffee, tea, milk, water, coke, limejuice);
    
    var
        drink : beverage;
    
    begin
         writeLn('Which drink do you want? ');
         writeLn('Here are the choices: coffee, tea, milk, water, coke, limejuice ');
         readLn(drink);
         writeLn('So you would like to drink ', drink, '.');
         readLn
    end. 

chikega
  • 135
  • 1
  • 6