Recent

Author Topic: Redeclared constant as variable  (Read 8752 times)

zamronypj

  • Full Member
  • ***
  • Posts: 133
    • Fano Framework, Free Pascal web application framework
Redeclared constant as variable
« on: July 17, 2019, 02:01:39 am »
Based on article

https://www.thedelphigeek.com/2019/07/when-true-is-not.html

Code: Pascal  [Select][+][-]
  1. program fuxkup;
  2.  
  3. var true : boolean = not false;
  4.  
  5. procedure magic;
  6. begin
  7.     true := false;
  8. end;
  9.  
  10. begin
  11.     writeln(true);
  12.     magic();
  13.     writeln(true);
  14. end.
  15.  
  16.  

My initial impression, FreePascal will refuse to compile because of duplicate identifier (because both, true as constant and true as variable, are in scope). But it does not.
Source code above will compile successfully and when run, print

true
false

Is this correct behavior?

« Last Edit: July 17, 2019, 02:20:07 am by zamronypj »
Fano Framework, Free Pascal web application framework https://fanoframework.github.io
Apache module executes Pascal program like scripting language https://zamronypj.github.io/mod_pascal/
Github https://github.com/zamronypj

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: Redeclared constant as variable
« Reply #1 on: July 17, 2019, 02:35:23 am »
Yup, kind of funky ! >:(

They're variables btw..
The only true wisdom is knowing you know nothing

Akira1364

  • Hero Member
  • *****
  • Posts: 561
Re: Redeclared constant as variable
« Reply #2 on: July 17, 2019, 03:23:15 am »
True and false are not constants or "reserved" words in FPC. They're just magic intrinsic keywords that the compiler registers internally as being equal to 1 and 0.

You can see where it does this here.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Redeclared constant as variable
« Reply #3 on: July 17, 2019, 09:24:33 am »
True and false are not constants or "reserved" words in FPC. They're just magic intrinsic keywords that the compiler registers internally as being equal to 1 and 0.

You can see where it does this here.
The location is right, but your assumption is not: they are indeed simply ordinary constants that are inserted by the compiler into the System unit upon compiling that unit.

Thaddy

  • Hero Member
  • *****
  • Posts: 14157
  • Probably until I exterminate Putin.
Re: Redeclared constant as variable
« Reply #4 on: July 17, 2019, 01:02:49 pm »
See also: https://wiki.freepascal.org/User_Changes_3.0#True_and_False_are_not_keywords_anymore so it is intentional.

They can be re-declared as any simple type including strings.
Code: Pascal  [Select][+][-]
  1. program trueorfalse;
  2. // silly season code
  3. const
  4.   true = 'yes';
  5.   false = 'no';
  6. begin
  7.   writeln(true,false);
  8. end.
« Last Edit: July 17, 2019, 01:16:58 pm by Thaddy »
Specialize a type, not a var.

Akira1364

  • Hero Member
  • *****
  • Posts: 561
Re: Redeclared constant as variable
« Reply #5 on: July 17, 2019, 03:06:20 pm »
The location is right, but your assumption is not: they are indeed simply ordinary constants that are inserted by the compiler into the System unit upon compiling that unit.

Well, I moreso meant constant as in something actually visibly declared somewhere in-source, I.E.

Code: Pascal  [Select][+][-]
  1. const TRUE = 1;

as opposed to an internally generated constsym. I know those ultimately amount to the same thing though.

Overall I think why this works is just a matter of "you can always redeclare any identifier that is not an actual reserved word", right?
« Last Edit: July 17, 2019, 03:08:21 pm by Akira1364 »

kupferstecher

  • Hero Member
  • *****
  • Posts: 583
Re: Redeclared constant as variable
« Reply #6 on: July 17, 2019, 07:35:32 pm »
They're just magic intrinsic keywords that the compiler registers internally as being equal to 1 and 0.
Is this guaranteed on all platforms?
Under Windows 7, Lazarus 2.0.2:
writeln(Integer(true)); // returns 1
writeln(Booltostr(true)); // returns -1

Why I ask, I'd like to do something like that:
Code: Pascal  [Select][+][-]
  1. aEnabled: Boolean;
  2. begin
  3.   someRegister:= (Integer(aEnabled) shl 5);
  4. end;

instead of
Code: Pascal  [Select][+][-]
  1.   if aEnabled
  2.    then someRegister:= (1 shl 5);
  3.    else someRegister:= 0;

And it would be nice, if the Integer type cast could be dropped somehow (Operator overload?).



Thaddy

  • Hero Member
  • *****
  • Posts: 14157
  • Probably until I exterminate Putin.
Re: Redeclared constant as variable
« Reply #7 on: July 17, 2019, 08:21:17 pm »
The integer cast is misplaced here. You should cast to an unsigned type. That should work, except for the sign bit if there is any signed integer type in the original code.
There seems to be a bug in sysutils.BoolToStr(), unless there's also a BooleanToStr().  Pascal Booleans are 0 and 1. C Compatible Bools are 0 and not 0 ( resolved as -1, but any value except 0 will return true)

I would file a bug report against BoolToStr

See https://freepascal.org/docs-html/ref/refse12.html#QQ2-26-29
« Last Edit: July 17, 2019, 08:28:34 pm by Thaddy »
Specialize a type, not a var.

kupferstecher

  • Hero Member
  • *****
  • Posts: 583
Re: Redeclared constant as variable
« Reply #8 on: July 17, 2019, 10:12:07 pm »
Hello Thaddy,

thanks for the documentation link! It's 1 and 0 as you said.

The operator overload I just tried and it compiles.


Furthermore I filed a bug report for booltostr:
https://bugs.freepascal.org/view.php?id=35856

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Redeclared constant as variable
« Reply #9 on: July 18, 2019, 09:32:00 am »
Overall I think why this works is just a matter of "you can always redeclare any identifier that is not an actual reserved word", right?
Indeed.

Thaddy

  • Hero Member
  • *****
  • Posts: 14157
  • Probably until I exterminate Putin.
Re: Redeclared constant as variable
« Reply #10 on: July 18, 2019, 04:21:57 pm »
Since the bug report was dismissed:
Here's what I propose:
Code: Pascal  [Select][+][-]
  1. program properbooleanstrings;
  2. // not BoolToStr() but BooleanToStr().
  3. function BooleanToStr(const a:Boolean):string;inline;
  4. begin
  5.   writestr(BooleanToStr{or maybe use result in some modes},ord(a))
  6. end;
  7.  
  8. begin
  9.   Writeln(BooleanToStr(true));
  10.   Writeln(BooleanToStr(false));    
  11. end.

Doesn't even need sysutils.... :D And works in all modes and respects Pascal type Booleans (0..1) instead of C type Boole (-1,0)..

Of course this also works:
Code: Pascal  [Select][+][-]
  1. function BooleanToStr(const a:Boolean):string;inline;
  2. begin
  3.   writestr(BooleanToStr{or maybe use result in some modes},a)
  4. end;
which prints either true or false.

Note the type helper has the same caveat as BoolToStr(), prints -1:
Code: Pascal  [Select][+][-]
  1. uses sysutils;
  2. var a:boolean = true;
  3. begin
  4.   writeln(a.Tostring); // using the type helper
  5. end.



« Last Edit: July 18, 2019, 04:56:39 pm by Thaddy »
Specialize a type, not a var.

ASerge

  • Hero Member
  • *****
  • Posts: 2212
Re: Redeclared constant as variable
« Reply #11 on: July 23, 2019, 10:02:24 pm »
Since the bug report was dismissed:
Because the only bug is that the documentation for the function is not complete.

Peter H

  • Sr. Member
  • ****
  • Posts: 272
Re: Redeclared constant as variable
« Reply #12 on: July 23, 2019, 10:39:54 pm »
So we can write now:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. const
  4.   true = not true;
  5. var
  6.   x:boolean;
  7.  
  8. begin
  9.   if true = (x<>x) then
  10.     writeln( 'Hello brave new World!' );
  11.   readln;
  12. end.
  13.  

This is more horrible than writable constants.
Sorry, but this has to be said.
« Last Edit: July 23, 2019, 10:44:57 pm by Peter H »

glorfin

  • Full Member
  • ***
  • Posts: 148
  • LMath supporter
Re: Redeclared constant as variable
« Reply #13 on: July 24, 2019, 01:55:52 pm »

This is more horrible than writable constants.
Sorry, but this has to be said.

Agreed. Such things should not be compiled. 

Thaddy

  • Hero Member
  • *****
  • Posts: 14157
  • Probably until I exterminate Putin.
Re: Redeclared constant as variable
« Reply #14 on: July 24, 2019, 04:30:14 pm »
Writable typed constants are much older than Object Pascal.
They serve - amongst other - a distinct purpose: maintaining state within the context of a procedure or function.
example:
Code: Pascal  [Select][+][-]
  1. program state;
  2. {$mode iso} (* ISO mode has no object extensions and $J+ is the default. *)
  3. function HowManyTimesDidYouCallMe:integer;
  4. const T: integer = 0;
  5. begin
  6.   inc(T);
  7.   HowManyTimesDidYouCallMe := T;
  8. end;
  9.  
  10. var i:integer;
  11. begin
  12.   for i := 0 to 9 do writeln(HowManyTimesDidYouCallMe);
  13. end.

So it is actually *very* usefull in a non-object oriented pascal program.

It is just that not many younger programmers appreciate its power.
The state of T is bound by its function (although in the background it is still global, no other procedure or function can access it)
Think of it as a precursor to object extensions.

 
« Last Edit: July 24, 2019, 08:01:37 pm by Thaddy »
Specialize a type, not a var.

 

TinyPortal © 2005-2018