How can I use WriteLn with an enum type?
Asked Answered
O

5

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.

Overcareful answered 16/12, 2010 at 9:11 Comment(4)
Hint: What does the compiler say?Mikkimiko
You heretic. The seventh day is Sunday. ;-) Also: the weekdays are enumerations, which are constants, not printable strings.Nerte
[Error] hours.dpr(28): Illegal type in Write/Writeln statement is the compiler errorOvercareful
seems like @goreSplatter got it then, you can't print the enumerationDuky
S
16

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.

Spiracle answered 16/12, 2010 at 11:47 Comment(5)
+1. This is the proper way to convert an enumeration to a string.Seaward
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.Hydraulic
@codeelegance-> Please can you post a sample type of this situation. I use RTTI and this code and never it fail for me.Lampblack
TypeDay = (Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7); should do it.Hydraulic
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.Hydraulic
H
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.
Hoskins answered 16/12, 2010 at 9:23 Comment(1)
+1 for Array[TypeDay] of string. I had to delete my own simply dum answer because of this.Zerla
L
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.

Lithotrity answered 16/12, 2010 at 9:45 Comment(5)
you got to be kidding! writing assembler code in Delphi? what for?Luciusluck
@David Heffernan: I think this is his optimized version. There is no need to downvote.Zerla
@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.Caye
Although sometimes they don't perform well. Try GetProperty from new RTTI, then GetPropInfo from old RTTI, compare the speed: 50 times faster.Cuzco
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.Lithotrity
A
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

Argument answered 16/12, 2010 at 11:20 Comment(0)
L
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. 

Lyophobic answered 15/5, 2021 at 5:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.