Recent

Author Topic: FPC Unleashed (inline vars, statement expr, tuples, match, indexed/lazy labels)  (Read 35644 times)

Fibonacci

  • Hero Member
  • *****
  • Posts: 950
  • Behold, I bring salvation - FPC Unleashed
Agreed, this is a legitimate gap. I have tried this myself many times and kept hitting the same wall ;D

Good news though: it already works with inline variables:

Code: Pascal  [Select][+][-]
  1. var
  2.  TheSig:      DWORD = $abcd;
  3.  TheSig2    : array[0..3] of char = 'abcd';
  4.  TheSigDword: DWORD absolute TheSig2;
  5.  
  6. //const TheSig3 = DWORD('abcd');         // nope
  7. //const TheSig3: DWORD = DOWRD('abcd');  // nope
  8. //var TheSig3: DWORD = DWORD('abcd');    // nope
  9.  
  10. begin
  11.  writeln('TheSig:        ', TheSig);       { $abcd          }
  12.  writeln('TheSigDword:   ', TheSigDword);  { 'abcd'         }
  13.  
  14.  var sig := DWORD('abcd');              // ok!
  15.  writeln('[inline] sig:  ', sig);
  16.  var sig2: DWORD := DWORD('abcd');      // ok!
  17.  writeln('[inline] sig2: ', sig2);
  18.  
  19.  readln;
  20. end.

Code: Text  [Select][+][-]
  1. TheSig:        43981
  2. TheSigDword:   1684234849
  3. [inline] sig:  1684234849
  4. [inline] sig2: 1684234849

I'll try to extend it to classic const and var.
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

LeP

  • Sr. Member
  • ****
  • Posts: 306
Looks like a bug to me since DWORD('abcd') is known (or should be known) at compile time but, FPC apparently couldn't figure it out.
I'ts not a bug, casting a string to integer is a non sense, also if in some languages (for example in C, which is a language known to be error-proof  :o ) is permitted. Should be used a new RTL function to do this (in my opinion).
I never see this, and hope never see this again  ::)
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

440bx

  • Hero Member
  • *****
  • Posts: 6493
I never see this, and hope never see this again  ::)
Then you must not read much C code.  It's very common in C/C++ code, just about every signature found in structs is specified that way.



@Fibonacci,

What's your take on the "distinct" feature ?
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

LeP

  • Sr. Member
  • ****
  • Posts: 306
Then you must not read much C code.  It's very common in C/C++ code, just about every signature found in structs is specified that way.
Yes, I use C only to make DLL interface with some hardware (and never found that but ... I'm sure is like you say).

Normally I use the .h files to make wrappers in Pascal and here again I never found that.
Only one time I faced on similar things (on FOURCC of media encoder / decoder), but I simply made a function to write and read that.
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

Khrys

  • Sr. Member
  • ****
  • Posts: 441
Feature request:

a way of declaring a type that is an alias of a currently known type BUT is NOT assignment compatible with its base type.

Why have this ?: many, many reasons, but among them, that would allow creating Windows API definitions where the type HWND isn't compatible with HHEAP or HMODULE or HANYOTHERHANDLE which would enable the compiler to do type checking (after all, Pascal is supposed to do strong type checking.)

+1

It has always seemed strange to me that Pascal, known for being very strongly typed, refuses to enforce distinctness between types explicitly marked as such (think  type <NEWLINE> type HWND = HANDLE  - what's the purpose of the second  type  if it doesn't even make  HWND  distinct from  HANDLE?)

Additional feature request:

Consider casts of equal size entities to be valid in const declaration.  Consider the following example:
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD('abcd');
  3.  
Currently FPC will not accept the above constant.  Since 'abcd' is 4 bytes, the size of a DWORD and a DWORD is a valid constant, it would be very nice, not to mention convenient, if the compiler accepted such casts.

It is also very commonly use to create record signatures.  MZ anybody ? ;)

The fact that  DWORD('abcd')  is possible at all is beyond cursed  :o  since when are casts allowed to dereference pointers?
(And before you say "strings are actually pointers" is a C-ism, look at the disassembly of that expression -  'abcd'#0  is just a regular constant that's resident in memory and accessed via label.)

How about this?

Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD($61626364); // 'abcd'
  3. begin
  4.   Rec.Signature := NToBE(ASIGNATURE);
  5. end

440bx

  • Hero Member
  • *****
  • Posts: 6493
In the code:
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD('abcd');
  3.  
The compiler is _explicitly_ being told that a sequence of 4 characters (not a string, but 4 bytes that represent the characters 'a', 'b', 'c' and 'd') is to be interpreted as a DWORD (which is 4 bytes.)

There should NOT be a string 'abcd' stored anywhere in the executable as a result of that definition.  The sequence of bytes 'abcd' is a constant, just like a number.  It is _incorrect_ for the compiler to store it in the binary because it is a constant.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

ccrause

  • Hero Member
  • *****
  • Posts: 1117
A goto that jumps "several thousand lines away" is the "fault" of the programmer, not of goto itself. (At the very least it should be accompanied with a comment.) Spaghetti code can be created with many languague features.
A properly designed language should NOT allow that under any circumstances.  A language that allows that is simply stated very very poorly designed and, a programmer who uses gotos is in dire need of learning a few things.  I really mean that.

If a programmer wants a goto then he/she should drop to assembly, that way, the programmer who reads the code knows that everything goes, no limits because it's assembler.

What about renamed goto's which are simply goto's with implied destinations:
exit - goto end of current subroutine (optionally set result of function)
break - goto end of current loop
continue - goto start of current loop

One could argue that these named goto's have explicit scope limits.

440bx

  • Hero Member
  • *****
  • Posts: 6493
One could argue that these named goto's have explicit scope limits.
And that is what makes those statements (exit, break, continue) completely acceptable while "goto" is completely unacceptable in all circumstances.  The _destination_ is the problem in the 'goto' statement.  Of course, making a 'goto''s destination variable is adding crime to insult and injury.  Programmers have been _fired_ for doing that and, people who do that should not be allowed to program.


FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD('abcd');
Currently FPC will not accept the above constant.  Since 'abcd' is 4 bytes

Perhaps internally 'abcd' isn't represented as 4 bytes... It may be treated as a string of unicode characters, and the compiler doesn't bother to find out if all characters are also valid ASCII characters. This seems valid, though not a constant and a bit wordy:

Code: Pascal  [Select][+][-]
  1. var
  2.         abcd_str : array[0..3] of AnsiChar = 'abcd';  abcd : DWord absolute abcd_str;


why simply don't write as natural language Pascal impose?
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD($abcd);

'abcd' is #$61 + #$62 + #$63 + #$64, it is not #$A + #$B + #$C + #$D.

'abcd' as a DWord would be the integer value $64636261 (on little-endian machines).


It has always seemed strange to me that Pascal, known for being very strongly typed, refuses to enforce distinctness between types explicitly marked as such (think  type <NEWLINE> type HWND = HANDLE  - what's the purpose of the second  type  if it doesn't even make  HWND  distinct from  HANDLE?)

It could be done with records or classes that encapsulate the actual value, though it's a lot more to type. There's also the question if the compiler is still able to pass these constructs to a subroutine via CPU registers.


The fact that  DWORD('abcd')  is possible at all is beyond cursed  :o  since when are casts allowed to dereference pointers?

Why would 'abcd' be a pointer?


How about this?

Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD($61626364); // 'abcd'
  3. begin
  4.   Rec.Signature := NToBE(ASIGNATURE);
  5. end

That would require manually translating these strings...
« Last Edit: April 17, 2026, 07:59:36 am by creaothceann »

440bx

  • Hero Member
  • *****
  • Posts: 6493
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD('abcd');
Currently FPC will not accept the above constant.  Since 'abcd' is 4 bytes

Perhaps internally 'abcd' isn't represented as 4 bytes... It may be treated as a string of unicode characters, and the compiler doesn't bother to find out if all characters are also valid ASCII characters.
the sequence 'abcd' occurs in a const section therefore the compiler must treat it as a constant, there is nothing preventing that.  Additionally, the compiler is being told to typecast it to DWORD which forces the size to be 4 which in turn forces the compiler to interpret them as ASCII.    That statement is rock solid and the compiler should handle it without problems.  The compiler is being told everything it needs to know and, there is nothing in the statement that conflicts with what it is being told, IOW, there is nothing illegal in the expression.

This seems valid, though not a constant and a bit wordy:

Code: Pascal  [Select][+][-]
  1. var
  2.         abcd_str : array[0..3] of AnsiChar = 'abcd';  abcd : DWord absolute abcd_str;
That's not a constant.  The whole point of DWORD('abcd') is to use the value as a _signature_ which is identified by a _constant_.  That var is obviously not a constant.  It's unusable.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Khrys

  • Sr. Member
  • ****
  • Posts: 441
Why would 'abcd' be a pointer?

👇

(And before you say "strings are actually pointers" is a C-ism, look at the disassembly of that expression -  'abcd'#0  is just a regular constant that's resident in memory and accessed via label.)

The compiler treats it as one when  DWORD('abcd')  is inside a function body, as evidenced by the code it generates:

Code: ASM  [Select][+][-]
  1. mov eax, DWORD PTR .Ld1
  2.  
  3. .Ld1:
  4.     .ascii "abcd\0"

This is no different than using  ASIGNATURE: PChar = 'abcd';  followed by  PDWORD(ASIGNATURE)^.
In other words, it's a filthy pointer cast followed by a dereference, and type safety goes straight out the window like dissident Russian oligarchs.

Thausand

  • Hero Member
  • *****
  • Posts: 545
I never see this, and hope never see this again  ::)
Then you must not read much C code.  It's very common in C/C++ code, just about every signature found in structs is specified that way.
+1.

Good example riff (https://en.wikipedia.org/wiki/Resource_Interchange_File_Format):
Quote
RIFF files consist entirely of "chunks". The overall format is identical to IFF, except for the endianness as previously stated, and the different meaning of the chunk names.

All chunks have the following format:
-  4 bytes: an ASCII identifier for this chunk (examples are "fmt " and "data"; note the space in "fmt ").
But is normal for think this ok for store identifier and have dword (because that make more easy for recognize hexadeci (or have bits) and many more easy for change endian...  :))
A docile goblin always follow HERMES.md

440bx

  • Hero Member
  • *****
  • Posts: 6493
The compiler treats it as one when  DWORD('abcd')  is inside a function body, as evidenced by the code it generates:
What the compiler is doing when DWORD('abcd') appears in a const section is incorrect.  The compiler is being told that it is a constant (it's in a const section) and that it is 4 bytes (DWORD.)  The compiler has no business allocating storage for the characters abcd and using a pointer to it.   That's appalling, it is being told to define a _compiler constant_ not allocate storage.

I agree with you that the compiler is creating a "filthy pointer", very filthy because there is no reason for it to exist.

FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8572
It has always seemed strange to me that Pascal, known for being very strongly typed, refuses to enforce distinctness between types explicitly marked as such (think  type <NEWLINE> type HWND = HANDLE  - what's the purpose of the second  type  if it doesn't even make  HWND  distinct from  HANDLE?)

Particularly since Wirth realised that Pascal was excessively lax, and had much stricter type compatibility rules in his subsequent languages.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD('abcd');
Currently FPC will not accept the above constant.  Since 'abcd' is 4 bytes

Perhaps internally 'abcd' isn't represented as 4 bytes... It may be treated as a string of unicode characters, and the compiler doesn't bother to find out if all characters are also valid ASCII characters.

The sequence 'abcd' occurs in a const section therefore the compiler must treat it as a constant, there is nothing preventing that.

I think the compiler starts at the right side of an expression. It sees a string, then tries to fit that into what the cast says it should be, then "saves" it as a constant... And something in that sequence of events goes wrong.


the compiler is being told to typecast it to DWORD which forces the size to be 4 which in turn forces the compiler to interpret them as ASCII.    That statement is rock solid and the compiler should handle it without problems.  The compiler is being told everything it needs to know and, there is nothing in the statement that conflicts with what it is being told, IOW, there is nothing illegal in the expression

Compiler: Yeah, well, you know, that's just, like, your opinion, man.

 

TinyPortal © 2005-2018