Recent

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

440bx

  • Hero Member
  • *****
  • Posts: 6479
@440bx, quick one - what about this case?

Code: Pascal  [Select][+][-]
  1. {$mode unleashed}
  2.  
  3. function GetPixel: (Byte, Byte, Byte, Byte); // R, G, B, A
  4. begin
  5.   Result := (255, 128, 64, 200);
  6. end;
  7.  
  8. var
  9.   red, alpha: Byte;
  10. begin
  11.   (red, _, _, alpha) := GetPixel; // only red and alpha
  12.   WriteLn(red, ' ', alpha);
  13. end.
  14.  

Here _ is just a "skip this field" in tuple destructuring, nothing to do with match. Should we kill it here too? _ can be a variable name after all.

You're suggesting otherwise, but honestly - first, it's way too long a word, I don't like it, I'd rather have else. Second, if we had to pick something, I'd go with *.



Edit: ok, * is out. Forgot Pascal has (* ... *) comments, so (* already means "start of comment":

Code: Pascal  [Select][+][-]
  1. (*, y) := GetPair; // oops, this is a comment

So yeah, nevermind * :)
"otherwise" may be long but, at least, it is problem free, I think problem-free is worth a little extra typing.  OTH, if you really want a single character thing then use "~" (tilde) or some other 1 character symbol if you must,  but, definitely not "_" because "_" can be a variable and using it for anything else will cause problems because there will always be cases where the _scanner_ will not be able to tell the difference between variable and it's alter-meaning "otherwise".



As far as the poll, the logical option is (1) and consequently, not only it should be available in "match", it should also be available in "case".  IOW, that's the only option that provides consistency and generality.  The other 2 options are Hungarian losers ;)



« Last Edit: April 14, 2026, 11:36:17 pm by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Fibonacci

  • Hero Member
  • *****
  • Posts: 941
  • Behold, I bring salvation - FPC Unleashed
~? Bro, have you ever actually typed a tilde? I mean yeah, you clearly put one in your post, but maybe you copy-pasted it from somewhere :D It's shift+`, then SPACE to commit it, otherwise it just sits there waiting to eat your next letter. Way too much work for "skip this field". _ is shift+minus, one motion, done :D



As far as the poll, the logical option is (1) and consequently, not only it should be available in "match", it should also be available in "case".  IOW, that's the only option that provides consistency and generality.  The other 2 options are Hungarian losers ;)

Interesting - I had you pegged for 3 (match fall x of). One keyword up front and you know exactly what the whole block does, no surprises buried inside a begin..end. It's also more predictable - fall through everything until the end (or until leave), done. With 1 you have to sprinkle fall all over the place, and wrap single-statement branches in begin..end just to have somewhere to put it.

As for case - not touching it. I already poked it once and had to revert the change. Whatever syntax it has now, it stays.
« Last Edit: April 15, 2026, 12:34:40 am by Fibonacci »
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

440bx

  • Hero Member
  • *****
  • Posts: 6479
I don't like the tilde either but, I suggested it because you seem to want a single character.  If you want something that is really "economic" as far as typing, the "\" (backslash) I believe is unused and is a single keystroke, no need to even use shift.  Actually, while proofreading this paragraph, it occurred to me that the "=" (equal) could be used there.  I don't believe it would conflict with anything and it wouldn't even require any changes in the scanner.



For the record, adding "fall" to "case" should be very easy as it does not affect the rest of the "case" structure.  As far as code generation, it's also quite simple, omit the jump the compiler is currently emitting.



I favor enhancing current Pascal constructions over creating new ones, that's why having a new structure called "fall" isn't appealing to me.  A programming language should be lean yet flexible.  Having "fall" as a statement that operates in both, "match" and "case" does what is needed without adding unnecessary stuff that can be accomplished just as well with a single keyword ("fall" in this case - no pun intended.)



Side note: a lean programming language is a lot more important than first meets the eye.  C is lean and, it is one of the reasons it is still successful.  C++ OTH is getting bloated and that is already causing problems for its continued use.    Unfortunately, Ada isn't as lean as I'd like it to be but, it has a lot of great features and it really is meticulously designed (though still not perfect.)

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

creaothceann

  • Sr. Member
  • ****
  • Posts: 358
I also like poll option #1. There's a potentional conflict with any keyword we could come up with ("fall" could also be the name of a subroutine, or one of the values of an enumerated type), but I guess it's fine enough. (Ironically, a longer keyword would perhaps reduce naming collisions...)

"~" is "AltGr +" on a German keyboard, but I've got myself one with QWERTY layout, and tilde is "Shift `" on that, no space required to confirm it. So personally I like the tilde option.

Btw. "\" is "AltGr ß" on a German keyboard, arguably even worse than a shifted character. It's one of the reasons why I switched keyboard layouts.
« Last Edit: April 15, 2026, 12:49:07 am by creaothceann »

Fibonacci

  • Hero Member
  • *****
  • Posts: 941
  • Behold, I bring salvation - FPC Unleashed
Honestly I expected 3 to be the obvious pick. Isn't that kind of what fallthrough should be - the same way it works in C? Default falls through, leave instead of break to stop, and that's it. Familiar, heavily used, and C switch code could be ported to Pascal almost mechanically. A bit surprised to see 1 winning.
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

440bx

  • Hero Member
  • *****
  • Posts: 6479
To make it parallel to what's done in C, the C keyword "break" should be replaced by "fall". 

That's the most C like version, which is (1)

That's also why, "fall" should also be available in the "case" statement.  It makes no sense to have it in "match" and not have it in "case".

ETA:

Falling or not falling through to the code that follows a specific case should be _individually_ controllable_ (just as it is in C) and should also be conditional, IOW, be in an "if" statement if necessary to control whether or not fall through will happen (in C, the "break" may be in an "if" which makes breaking dependent of the state.  Same thing should happen for Pascal but to control falling instead.)

Having a construction that always falls through (as it is in C) doesn't work for Pascal because there is no keyword like "break" in C to prevent further undesired fall through.  Since, in Pascal "break" cannot be used for that purpose, a new keyword would be required.  Too messy not to mention completely unnecessary (since "fall" can be used to implement every possible execution path desired.)

Option (1) is what C's switch should have been, "breaking" is the default, continuing execution requires an explicit statement to make it happen, i.e, "fall".  Clean, simple, easy to understand and, easy to implement. Just the way it should be :)

« Last Edit: April 15, 2026, 03:04:09 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Fibonacci

  • Hero Member
  • *****
  • Posts: 941
  • Behold, I bring salvation - FPC Unleashed
Having a construction that always falls through (as it is in C) doesn't work for Pascal because there is no keyword like "break" in C to prevent further undesired fall through.  Since, in Pascal "break" cannot be used for that purpose, a new keyword would be required.  Too messy not to mention completely unnecessary (since "fall" can be used to implement every possible execution path desired.)

There is: leave
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

440bx

  • Hero Member
  • *****
  • Posts: 6479
There is: leave
Good to know but, option (1) doesn't need that additional keyword.  It does everything it needs with just "fall".

As previously stated, option (1) is the one that makes sense and as a bonus, it is parallel to C's switch (though reversed as far as fall through being the default in that language.)

Anyway, that makes 2 votes for option (1)
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

creaothceann

  • Sr. Member
  • ****
  • Posts: 358
Honestly I expected 3 to be the obvious pick. Isn't that kind of what fallthrough should be - the same way it works in C? Default falls through, leave instead of break to stop, and that's it. Familiar, heavily used, and C switch code could be ported to Pascal almost mechanically. A bit surprised to see 1 winning.

I'd estimate that "fall through" is not needed for the vast majority of projects, which is what Pascal gets right and C gets wrong, leading to an excess of break; instructions in C code.

What Pascal gets wrong imo is that there is a need for a no-overhead (i.e. no goto) fallthrough in certain projects. (Btw. you state "call [fall] anywhere in the block to drop into the next branch"; I hope this doesn't result in a jump instruction if fall is the last instruction of a branch.)

To be honest I probably won't use match nearly as much as case so I'm less concerned about what behavior is chosen for match, but imo case could definitely use the fall keyword.

Khrys

  • Sr. Member
  • ****
  • Posts: 436
Tuples, patterns, underscores,  match  expressions... is FPC Unleashed turning into Rust?  :D

creaothceann

  • Sr. Member
  • ****
  • Posts: 358
Tuples, patterns, underscores,  match  expressions... is FPC Unleashed turning into Rust?  :D

There's already lots of checking of what is borrowed...

MarkMLl

  • Hero Member
  • *****
  • Posts: 8572
~? Bro, have you ever actually typed a tilde? I mean yeah, you clearly put one in your post, but maybe you copy-pasted it from somewhere :D It's shift+`, then SPACE to commit it, otherwise it just sits there waiting to eat your next letter. Way too much work for "skip this field". _ is shift+minus, one motion, done :D

No it's not.

It's a standard 7-bit ASCII character and as such is fair game for language syntax (i.e. as distinct from needing UTF-8 etc.). Notably, ¬ which was used in several early languages is not part of 7-bit ASCII and should be avoided.

How a user actually gets it, and whether a particular keyboard layout repurposes it as a compose key, is another problem altogether.

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

440bx

  • Hero Member
  • *****
  • Posts: 6479
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. the following example uses a new keyword "distinct" to inform the compiler the new type is not assignment compatible with its base type.
Code: Pascal  [Select][+][-]
  1. type
  2.   TMYINTEGER = distinct integer;  
  3.  
  4. var
  5.   a : integer;
  6.   b : TMYINTEGER = TMYINTEGER(0);  { MUST be typecasted }
  7.   c : TMYINTEGER = integer(0);     { error because a TMYINTEGER is not assignment compatible with integer }
  8.  
  9.  
  10. begin
  11.   a := integer(b);     { ok }
  12.   b := TMYINTEGER(a);  { ok }
  13.  
  14.   b := 0;              { NOT ok -> error incompatible types }
  15.  
  16.   b := TMYINTEGER(ord('z'));  { ok, ord returns an integer which is then cast }
  17.   b := TMYINTEGER('z');       { NOT ok -> sizeof('z') = 1 <> sizeof(TMYINTEGER)  }
  18.  
  19.   b := TMYINTEGER('abcd');    { ok, 4 characters -> size 4 -> same size as TMYINTEGER }
  20. end;
  21.  
a typecast should be considered valid ONLY when type size of the types involved is the same.

NOTE: this is a standard feature in Ada.

Implementation is trivial and, simpler than what FPC currently does.  The compiler should simply consider variables of distinct types to be assignment compatible only when the types are the same just as it does for records.  IOW, the compiler could "think" of the type as a record type as far as assignment compatibility is concerned.

I suggest "distinct" as a new keyword to differentiate types but, anything that implies uniqueness would likely be another reasonable option.

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.)

NOTE: a possible alternative to "distinct" would be "strict".



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 ? ;)

« Last Edit: April 16, 2026, 10:32:19 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

LeP

  • Sr. Member
  • ****
  • Posts: 294
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.
Why should be a cast like this, there should be a constant as parameter, so why simply don't write as natural language Pascal impose?
Code: Pascal  [Select][+][-]
  1. const
  2.   ASIGNATURE = DWORD($abcd);
  3.  
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: 6479
Because the resulting value is not the same.

There are many signatures specified in C code as being 4 characters and simply having $abcd (or its equivalent) does not produce the same value as DWORD('abcd');

Run the code below if you need to see it yourself:
Code: Pascal  [Select][+][-]
  1.  
  2. var
  3.   TheSig : DWORD = $abcd;
  4.  
  5. var
  6.   TheSig2     : array[0..3] of char = 'abcd';
  7.   TheSigDword : DWORD absolute TheSig2;
  8.  
  9.   TheSig3     : DWORD;  { cannot do this = DWORD('abcd'); }
  10.  
  11. begin
  12.   TheSig3 := DWORD('abcd');  { cannot do this in the "var" section }
  13.  
  14.   writeln('TheSig     : ', TheSig);       { $abcd          }
  15.   writeln('TheSigDword: ', TheSigDword);  { 'abcd'         }
  16.   writeln('TheSig3    : ', TheSig3);      { DWORD('abcd'); }
  17. end.
  18.  
Strangely, TheSig3 cannot be initialzed in the "var" section with a constant value that is acceptable in the code section.  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.  The assignment works because the actual characters exist in storage (which should not be necessary in the case of a true constant.)

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

 

TinyPortal © 2005-2018