Recent

Author Topic: Please help me better understand this error ...  (Read 3614 times)

EganSolo

  • Sr. Member
  • ****
  • Posts: 398
Please help me better understand this error ...
« on: August 05, 2025, 03:36:13 am »
Consider this bit of code
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. Type
  3.   { TBook }
  4.  
  5.   TBook = class
  6.   private
  7.     fBookType : String;
  8.   public
  9.     constructor create; virtual;
  10.   public
  11.     Property BookType: String read fBookType write fBookType;
  12.   end;
  13.  
  14.   { TLongBook }
  15.  
  16.   TLongBook = class(TBook)
  17.   public
  18.    constructor create; override;
  19.   end;
  20.  
  21.   TBookClass = class of TBook;
  22.  
  23.   const
  24.     aDefaultBookType : TBookClass = TBook;
  25.  
  26. { TBook }
  27. constructor TBook.create;
  28. begin
  29.   fBookType := 'Book';
  30. end;
  31.  
  32. { TLongBook }
  33. constructor TLongBook.create;
  34. begin
  35.   fBookType := 'LongBook';
  36. end;
  37.  
  38.   //The compiler issues Error:Illegal expression when it encounters the default value in the
  39.   //function's header.
  40.   //
  41.   //If you replace the function's signature with the next line, the program compiles
  42.   //
  43.   //function CreateBook(const aBookClass: TBookClass): TBook;
  44.   function CreateBook(const aBookClass : TBookClass = aDefaultBookType): TBook;
  45.   begin
  46.      Result := aBookClass.Create;
  47.   end;
  48.  
  49.   Procedure DisplayBook(const aBook: TBook);
  50.   begin
  51.     Writeln(aBook.BookType);
  52.   end;
  53.  
  54. var aBook : TBook;
  55. begin
  56.   aBook := CreateBook(TBook);
  57.   DisplayBook(aBook);
  58.   aBook.Free;
  59.   aBook := CreateBook(TLongBook);
  60.   DisplayBook(aBook);
  61.   aBook.Free;
  62.   Readln;
  63. end.
  64.  
  65.  

My thought process:
  • TBookClass is a type over a domain defined by TBook and its descendants.
  • TBook is a value that a variable of type TBookClass accepts.
  • The compiler is happy with the declaration of aDefaultBookType, which has a similar signature to the formal paramter in Init2
  • Therefore, the compiler should be able to compile Init2's header.

So why is the compiler flagging the default value in Init2 as a syntax error?
« Last Edit: August 05, 2025, 03:53:48 am by EganSolo »

Thaddy

  • Hero Member
  • *****
  • Posts: 19169
  • Glad to be alive.
Re: Please help me better understand this error ...
« Reply #1 on: August 05, 2025, 07:10:44 am »
A type reference <> a type  hence the commented line will work. A reference can not be a default.
If you want, simply overload CreateBook
objects are fine constructs. You can even initialize them with constructors.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6395
  • Compiler Developer
Re: Please help me better understand this error ...
« Reply #2 on: August 05, 2025, 09:39:30 pm »
So why is the compiler flagging the default value in Init2 as a syntax error?

A default parameter needs to expressed using a constant expression. A typed constant is not a constant expression.

EganSolo

  • Sr. Member
  • ****
  • Posts: 398
Re: Please help me better understand this error ...
« Reply #3 on: August 06, 2025, 04:31:37 am »
Hum ... PascalDragon, you wrote
Quote
A default parameter needs to expressed using a constant expression. A typed constant is not a constant expression.

Thaddy, I think you're making the same argument. If that's the case, why did the compiler properly compile the constant declaration?

Code: Pascal  [Select][+][-]
  1.   const aDefaultBookType : TBookClass = TBook;
  2.  

That's a typed constant which has the same declaration as the function. What's different?


tetrastes

  • Hero Member
  • *****
  • Posts: 762
Re: Please help me better understand this error ...
« Reply #4 on: August 06, 2025, 10:05:21 am »
May be this will help you understand:
Code: Pascal  [Select][+][-]
  1. const
  2.     ii: integer = 2;
  3.  
  4. function ff(const jj: integer = ii): integer;
  5. begin
  6.     ff := jj + 2
  7. end;
  8.  
results in the same Error:Illegal expression.

cdbc

  • Hero Member
  • *****
  • Posts: 2787
    • http://www.cdbc.dk
Re: Please help me better understand this error ...
« Reply #5 on: August 06, 2025, 10:14:24 am »
Hi
The "Dead Horse" you're beating is buried here:
Code: Pascal  [Select][+][-]
  1. const
  2.     ii: integer = 2;
  3. /// or:
  4. const
  5.     aDefaultBookType : TBookClass = TBook;
The fact of the matter is -- even though it says loud 'n clear "const" IT IS NOT! a const but in fact a _static variable_ (depending on {$J+/-})
For it to be a _const_ you'll have to define {$J-} in your unit.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

tetrastes

  • Hero Member
  • *****
  • Posts: 762
Re: Please help me better understand this error ...
« Reply #6 on: August 06, 2025, 10:17:56 am »
For it to be a _const_ you'll have to define {$J-} in your unit.
Regards Benny

But it doesn't help to compile this code.  ;)

EganSolo

  • Sr. Member
  • ****
  • Posts: 398
Re: Please help me better understand this error ...
« Reply #7 on: August 06, 2025, 10:21:59 am »
Tetrastes and cdb: Thanks a lot! That does help.

However, I'm not at the end of my puzzlement.

I've modified my program by replacing aDefaultBookType as the default value in the function call by TBook. Tetrastes, in your example, that would be akin to replacing ii as the default value with 2.

The compiler is still throwing an Illegal expression error. Why is that?

program Project1;
Type
  { TBook }

  TBook = class
  private
    fBookType : String;
  public
    constructor create; virtual;
  public
    Property BookType: String read fBookType write fBookType;
  end;

  { TLongBook }

  TLongBook = class(TBook)
  public
   constructor create; override;
  end;

  TBookClass = class of TBook;

  const
    aDefaultBookType : TBookClass = TBook;

{ TBook }
constructor TBook.create;
begin
  fBookType := 'Book';
end;

{ TLongBook }
constructor TLongBook.create;
begin
  fBookType := 'LongBook';
end;

  //The compiler issues Error:Illegal expression when it encounters the default value in the
  //function's header.
  //
  //If you replace the function's signature with the next line, the program compiles
  //
  //function CreateBook(const aBookClass: TBookClass): TBook;
  function CreateBook(const aBookClass : TBookClass = TBook): TBook; //TBook replaced aDefaultBookType
  begin
     Result := aBookClass.Create;
  end;

  Procedure DisplayBook(const aBook: TBook);
  begin
    Writeln(aBook.BookType);
  end;

var aBook : TBook;
begin
  aBook := CreateBook(TBook);
  DisplayBook(aBook);
  aBook.Free;
  aBook := CreateBook(TLongBook);
  DisplayBook(aBook);
  aBook.Free;
  Readln;
end.

gues1

  • Guest
Re: Please help me better understand this error ...
« Reply #8 on: August 06, 2025, 10:34:11 am »
....
Code: Pascal  [Select][+][-]
  1. const
  2.     ii: integer = 2;
  3.  

For it to be a _const_ you'll have to define {$J-} in your unit.
Regards Benny
But it doesn't help to compile this code.  ;)

But why not ?:
Code: Pascal  [Select][+][-]
  1. const
  2. ii = integer(2);

tetrastes

  • Hero Member
  • *****
  • Posts: 762
Re: Please help me better understand this error ...
« Reply #9 on: August 06, 2025, 10:49:15 am »
Because of

A default parameter needs to expressed using a constant expression. A typed constant is not a constant expression.

Code: Pascal  [Select][+][-]
  1. const
  2.     ii: integer = 2;
  3.  
Here ii is typed constant. It is not constant expression, is it writable or not.

Code: Pascal  [Select][+][-]
  1. const
  2. ii = integer(2);

And here ii is ordinary constant. It is constant expression. Try to compile with both variants and you'll see.

tetrastes

  • Hero Member
  • *****
  • Posts: 762
Re: Please help me better understand this error ...
« Reply #10 on: August 06, 2025, 11:05:01 am »
  //The compiler issues Error:Illegal expression when it encounters the default value in the
  //function's header.
  //
  //If you replace the function's signature with the next line, the program compiles
  //
  //function CreateBook(const aBookClass: TBookClass): TBook;
  function CreateBook(const aBookClass : TBookClass = TBook): TBook; //TBook replaced aDefaultBookType
  begin
     Result := aBookClass.Create;
  end;

TBook is not constant expression. It is not even class instance. It is class declaration. Your code is somewhat equivalent to
Code: Pascal  [Select][+][-]
  1. function ff(const jj: integer = LongInt): integer;

EganSolo

  • Sr. Member
  • ****
  • Posts: 398
Re: Please help me better understand this error ...
« Reply #11 on: August 06, 2025, 11:18:16 am »
Well, that's where I'm getting confused: A constant is a static value within a domain. For instance, 2 is a static value in the integer domain, whereas the integer variable i is not.

A class plays a dual role. It is a type definition AND a static value within the domain defined by the class of type. Consider the following parallel:

Code: Pascal  [Select][+][-]
  1. Type
  2.   TMyBook = class end;
  3.   TMyLongBook = class(TMyBook) end;
  4.   TMyShortBook = class(TMytBook) end;
  5.  
  6.   TBookClass = class of TBook;
  7.  
  8.   DaysOfTheWeek = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
  9.  

Monday ... Sunday are static values within the DaysOfTheWeek domain. In a similar vein, TMyBook, TMyLongBook and TMyShortBook are static values (constants) within the TBookClass domain. There's a logical consistency when viewing these things this way. After all, once a class is defined, it can't be changed within the program's run-time. It's a _constant_

So, why is the compiler treating it as something other than a constant __within the context of TBookClass? I don't get it.

Khrys

  • Sr. Member
  • ****
  • Posts: 440
Re: Please help me better understand this error ...
« Reply #12 on: August 06, 2025, 01:41:38 pm »
Class references, as the name implies, are references - aka pointers that need to point somewhere.
More specifically, a class reference is a pointer to the VMT of the underlying type, stored somewhere in the final executable.

Pointers hold addresses - which is the crux of this issue, because addresses can't be known at compile time since they manifest as a result of the compilation & linking processes.

Attempting to use a class reference as a compile-time constant essentially amounts to this (which naturally also fails to compile):

Code: Pascal  [Select][+][-]
  1. var { or const, it doesn't matter }
  2.   Number: Integer = 0;
  3.  
  4. const
  5.   NumberReference = @Number; // <--- Error: Illegal expression

tetrastes

  • Hero Member
  • *****
  • Posts: 762
Re: Please help me better understand this error ...
« Reply #13 on: August 06, 2025, 02:41:11 pm »
But why this
Code: Pascal  [Select][+][-]
  1. const
  2.     aDefaultBookType : TBookClass = TBook;
is compiled? And what does it mean?

Khrys

  • Sr. Member
  • ****
  • Posts: 440
Re: Please help me better understand this error ...
« Reply #14 on: August 06, 2025, 03:55:09 pm »
But why this
Code: Pascal  [Select][+][-]
  1. const
  2.     aDefaultBookType : TBookClass = TBook;
is compiled? And what does it mean?

That's because typed constants aren't actually constants, as ridiculous as it sounds.
When  {$J+}  is active, the only difference between regular variables and typed constants is that the latter must be initialized to some value.

Apart from that, typed "constants" are just regular static variables; they have an address & take up space in RAM and are initialized at program startup with values embedded in the binary.
And since their value isn't known at compile-time, they cannot be part of constant expressions.

 

TinyPortal © 2005-2018