Recent

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

Fibonacci

  • Hero Member
  • *****
  • Posts: 1002
  • Behold, I bring salvation - FPC Unleashed
One major concern I have is that a union may hold several structures of different sizes, for instance, in the above example, there could be another struct that uses more than 1 byte, which is normal yet, since your union says "union of byte" it cannot accommodate another structure that is larger than a single byte and changing its declared size doesn't work either because, your comment states that every field in the bitpacked record has effectively "inherited" the size from the union.  There is a conflict. 

the logical solution I see is to remove the size from the "union" and instead have it in "bitpacked record of byte" because that is the bit field container

Heads up: of <type> currently works for both unions and records. So your form bitpacked record of byte ... end inside a plain union is already valid syntax. That work for you?



Yes—there is no data type specified for bit-fields and this is a huge problem to me. This is not consistent with either the verbose syntax of Pascal or even the syntax of C. In my opinion, it's a very bad idea to omit data types and rely on type inference in this case.

There is - of <type> on the surrounding container provides it. Each field: N inside is an N-bit slice of that type, so the type is fully determined, not inferred from nothing.

If you want it spelled out on each field anyway, the previously shown form is still available - <name>: <type> bitsize <N>; in a regular bitpacked record. Two ways to do it: implicit via container, or explicit per field.
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: 6542
Heads up: of <type> currently works for both unions and records. So your form bitpacked record of byte ... end inside a plain union is already valid syntax. That work for you?
Absolutely but, in addition to that, in the example you provided the compiler should require it in the "bitpacked record" clause because the bitfields should _not_ be "inheriting" type information from any other place but their container.  Allowing the type to be inherited from the outer union is unclear and a potential source of problems (there could be multiple other structs before the bitfield record which would obfuscate what type the bit fields container is.)
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

flowCRANE

  • Hero Member
  • *****
  • Posts: 986
There is - of <type> on the surrounding container provides it. Each field: N inside is an N-bit slice of that type, so the type is fully determined, not inferred from nothing.

If you want it spelled out on each field anyway, the previously shown form is still available - <name>: <type> bitsize <N>; in a regular bitpacked record. Two ways to do it: implicit via container, or explicit per field.

Ahh, now it is clear to me. The of <type> forces all grouped fields to be this type, so there is no need to specify the type per field. That sounds fine, however, such a declaration remains highly unusual in the context of general Pascal syntax.

What about the possibility of declaring a record or union with a size that doesn't match the byte layout? For example, a 20-bit union? Will a statement like union bitsize 20 be possible?
« Last Edit: May 13, 2026, 11:58:24 am by flowCRANE »
Lazarus 4.6 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

Thausand

  • Hero Member
  • *****
  • Posts: 560
Then is question separate: when record align set and make one field have other alignment then what is take precedence (e.g. is field align is all time must fit record align or can be more big for one field and ignore record align because this is small contradict with documentation that is exist)
All of this will end up in the docs. The Unleashed documentation acts as an "override" on top of the stock FPC documentation - by default you read the FPC docs, and where Unleashed adds or changes a feature, the Unleashed docs describe it in detail (including any place where the behaviour differs from stock).
Ok, thank you much for answer and considerate (and for implement  :) ) I wait how documentation is tell how is work exact.
A docile goblin always follow HERMES.md

creaothceann

  • Sr. Member
  • ****
  • Posts: 378
Just a note - array is a keyword that can be followed by square brackets to indicate a size. This could also apply to union.

So instead of "union of <type> size <size>" it could be written as "union[<size>] of <type>".
« Last Edit: May 13, 2026, 01:54:55 pm by creaothceann »

Thaddy

  • Hero Member
  • *****
  • Posts: 19278
  • Glad to be alive.
Depends on mode too... silly mode [], sane mode ().
objects are fine constructs. You can even initialize them with constructors.

Fibonacci

  • Hero Member
  • *****
  • Posts: 1002
  • Behold, I bring salvation - FPC Unleashed
Quick aside - I'm building a small dedicated installer for FPC Unleashed (lightweight fpcupdeluxe-style, but Unleashed-only). Host platforms are Windows and Linux at the moment. Question: how many of you would actually want it on a Mac too?

Disclaimer: I don't own a Mac, never have, and don't plan to. Apple and I aren't on friendly terms. I'd need a VM and someone willing to help validate it works. If the poll shows real interest, I'll look into setting up a macOS VM and giving it a shot. Otherwise stock fpcupdeluxe with the alias edit (see the first post) still works fine for installing Unleashed on Mac.

Cast your vote in the poll at the top of the thread. Comments / context welcome.



BTW - I added the poll to the main thread itself, but I can't find a "remove poll" option anywhere. Set the duration to 1 day for now - hoping that after it expires I'll be able to either remove it or at least reset it for a new question. If anyone knows the SMF poll mechanics better than I do, let me know.



Poll results

The poll ran for 24 hours, from 2026-05-14 05:48 CEST to 2026-05-15 05:48 CEST.

Question: Do you use MacOS (as an Unleashed user)?
  • 0 votes: Yes - I use Mac for development
  • 0 votes: No - but I'd want Unleashed installer on Mac
  • 6 votes (100%): No - I don't use Mac
« Last Edit: May 15, 2026, 08:02:43 am by Fibonacci »
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

Thaddy

  • Hero Member
  • *****
  • Posts: 19278
  • Glad to be alive.
I take it you mean Windows and Linux Intel? Or is ARM32/AARCH64 already catered for? Because that is not only Apple, but also Windows and Linux.
objects are fine constructs. You can even initialize them with constructors.

Fibonacci

  • Hero Member
  • *****
  • Posts: 1002
  • Behold, I bring salvation - FPC Unleashed
I take it you mean Windows and Linux Intel? Or is ARM32/AARCH64 already catered for? Because that is not only Apple, but also Windows and Linux.

x86_64 as host only (+ cross win32/win64, linux32/linux64, WASM). Aiming for the 90%+ of users first; the rest can be addressed later if there's demand and someone to validate the builds.
« Last Edit: May 14, 2026, 06:08:57 am by Fibonacci »
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

VisualLab

  • Hero Member
  • *****
  • Posts: 742
I'm very interested in this dialect because I'm tired of the language's archaic syntax. ...<cut>... Admittedly, I want to stick to the very basics of the language syntax and data types... <cut>

This is a contradiction. Or the syntax of a particular language is archaic -> so I don't want to use it. Or: I want to use it -> therefore the syntax is clearly not archaic. Besides, how can you recognize archaic or (its opposite) modern syntax? Because it is different from other languages? This would imply that (for example) C and C++ are very archaic because they were created a long time ago. They have a very conservative, even difficult to read syntax resulting from the hardware limitations of old computers used in the 1970s. And this has stuck, so they are archaic. Or that Python has no type declarations for variables, no constants, and no explicit (clearly visible) block boundaries—just like in the first experimental solutions from the 1950s. So the conclusion: Python is archaic. And if we look closely, the only thing really new in the last 20-15 years is borrow checking in Rust. So the term "archaic syntax" is very subjective.

However, in my opinion, this dialect is still missing a few features that would make writing code more convenient and improve its readability. So — @Fibonacci — can I suggest changes or additions to the language that I'm interested in?

Draft (so I don't forget):
  • named and unnamed unions (my old proposal),
  • C-style array declaration with the option to specify the number of items (no keywords needed),
  • bit fields with the option to specify the number of bits occupied by the field.
  • the ability to modify the for-loop iterator.

Of the above proposals, the following are interesting:
  • named and unnamed unions,
  • bit fields with the option to specify the number of bits occupied by the field.

Regarding unions and bit fields, it is important to take into account the comments and pitfalls that 440bx and Fibonacci wrote about.

The following are terrible "C-isms":
  • C-style array declaration with the option to specify the number of items (no keywords needed),
  • the ability to modify the for-loop iterator.

There's no point in adding an alternative way to declare arrays. The way it's done in C is flawed. When declaring arrays, you specify a number in square brackets, and when specifying the element index, you also specify a number in square brackets. This is error-prone. Secondly, the idea of ​​"tinkering" with the counter of a "for" loop within that loop is absurd. These two ideas should not be implemented under any circumstances, as they will cause various problems in the future.




1. Named and unnamed unions
...<cut>...


The idea is important, but the syntax needs to be carefully thought out.


2. Bit fields
...<cut>...

Code: Pascal  [Select][+][-]
  1. type
  2.   TFoo = bitpacked record
  3.     BitField1: Integer size 4; // four bits
  4.     BitField2: Boolean size 2; // two bits
  5.     BitField3: -2 .. 2 size 6; // six bits with s specific range of values
  6.   end;
  7.  


Also an important idea, but as before, the syntax needs to be carefully thought out. In particular, take into account what 440bx and Fibonacci have written, among others.


This way, the compiler will not only know what data type we are referring to, but also exactly how many bits the field should occupy. The size specified in bits is to be the target size of the field, regardless of the data type used. If we manually specify the allowed range of values, the size in bits specified at the end of the declaration must be used, even if the range of values requires fewer bits (if the range requires more bits than specified, a compilation error occurs). If you specify a data type instead of a range (e.g., Integer), values ranging from zero up to the maximum supported by that data type or up to the specified field size in bits are allowed. The compiler should have no trouble deducing the range of values based on the specified field size in bits, and then use it to verify the validity of values during range checks.


3. Abbreviated array declaration

The current syntax for declaring arrays is extremely verbose and unnecessarily requires specifying every detail. I propose changing the way arrays are declared so that only key information, such as the type and number of elements, is required:

Code: Pascal  [Select][+][-]
  1. var
  2.   Array1: Integer[5];    // array of five integers, indexing from 0 to 4
  3.   Array2: Integer[5, 5]; // 2D array of integers, indexing from 0 to 4 for both dimensions
  4.   Array3: Integer[];     // dynamic array of integers, indexing from 0
  5.   Array4: Integer[,];    // dynamic 2D array of integers, indexing from 0 for both dimesions
  6.  

Of course, the standard ranges should still be supported:

Code: Pascal  [Select][+][-]
  1. var
  2.   Array1: Integer[-2 .. 2];
  3.  

Instead of specifying a range of indices, it should also be possible to specify a constant that defines the number of elements, as well as the data type (as is currently supported):

Code: Pascal  [Select][+][-]
  1. const
  2.   ITEMS_NUM = 10;
  3.  
  4. var
  5.   Array1: Integer[ITEMS_NUM]; // array of 10 integers, indexing from 0 to 9
  6.   Array2: Integer[Boolean];   // array of 2 integers, indexing from False to True
  7.   Array3: Integer[Char];      // array of 256 integers, indexing from #0 to #255
  8.  

The general idea is to be able to declare arrays by specifying the number of elements (rather than a range of indices), as well as to simplify the syntax to a form familiar from other programming languages, since the current one is bloated. In any case, this shorthand syntax is not unfamiliar to Free Pascal, since it is used to declare short strings, such as Foo: String[10]; (short string with 10 characters).


This idea is redundant, error-prone, and difficult to read compared to the current one. A typical C-ism. A clear syntax for declaring arrays already exists. There's no justification for introducing it or replacing the current way of declaring arrays. In short - a terrible idea, it should not be implemented under any circumstances.


Unleash the for-loop iterator!

Currently, the for-loop iterator is protected, which means that its value cannot be modified inside the loop body—neither by directly assigning it to the iterator variable nor via a pointer (taking the address of the iterator is illegal). This makes absolutely no sense, because if we need to modify the iterator’s value inside the loop, the current nonsensical restrictions force us to use a while or repeat loop. I therefore propose that the iterator be freed from any restrictions and that the programmer be allowed to decide how the loop should work. Example:

Code: Pascal  [Select][+][-]
  1. for var I := 0 to 10 do
  2. begin
  3.   // some instructions
  4.  
  5.   if {condition} then
  6.   begin
  7.     I += 2;   // skip testing next two iterator values
  8.     continue; // go to the next loop iteration
  9.   end;
  10.  
  11.   // some instructions
  12. end;
  13.  

Second, the condition for exiting the for loop should also be modifiable (as another variable):

Code: Pascal  [Select][+][-]
  1. for var Current := 0 to var Last := 10 do
  2. begin
  3.   // some instructions
  4.  
  5.   if {condition} then
  6.     Last += 1; // change the iterator value for the last iteration
  7.    
  8.   // some instructions
  9. end;
  10.  

An additional variable can also apply to the stepper:

Code: Pascal  [Select][+][-]
  1. for var Current := 0 to var Last := 10 step var Stride := 2 do

...<cut>...


Another terrible idea. Especially the one with two or three variables in the loop header. If someone thinks they need this language construct, they should probably rethink their code, because something is flawed. It's a completely ill-conceived, error-prone design, some kind of hybrid of C and Pascal (with some exceptionally bad constructions). It should not be implemented under any circumstances.

If it's necessary to manipulate the counter value within a loop, the safest (least error-prone) variant is by far the "while" loop and the counter (variable) controlled (modified) by the programmer. The counter is then not directly linked to the loop itself. If someone tries to manipulate the counter of a "for" loop, it usually means the programmer didn't think carefully about something in their code (design).

Khrys

  • Sr. Member
  • ****
  • Posts: 458
Speaking on the topic of arrays, I have a (tangential) feature request: Generic type helpers.

I have a library of functional pseudo-methods for arrays, e.g.:

Code: Pascal  [Select][+][-]
  1. /// Applies a function to each element and collects the results into a new array.
  2. function ArrayMap<T, U>(const Self: TArray<T>; Lambda: TArrayMap<T, U>): TArray<U>;
  3. var
  4.   I: SizeInt;
  5. begin
  6.   Result := Nil;
  7.   SetLength(Result, Length(Self));
  8.   for I := 0 to Length(Result) - 1 do Result[I] := Lambda(Self[I]);
  9. end;

It would be nice to have these functions available as actual methods without having to write tons of boilerplate for each array type - something like the following should be possible:

Code: Pascal  [Select][+][-]
  1. type
  2.   TArrayMap<T, U> = reference to function (const Value: T): U;
  3.  
  4.   TFunctionalMethods<T> = type helper for TArray<T>
  5.   public
  6.     function Map<U>(Lambda: TArrayMap<T, U>): TArray<U>;
  7.   end;
  8.  
  9.   TStringFunctionalMethods = TFunctionalMethods<String>;
  10.  
  11. function Upper(const Items: TStringArray): TStringArray;
  12. begin
  13.   Result := Items.Map<String>(AnsiUpperCase); // Specialization can even be omitted with {$modeswitch implicitfunctionspecialization}
  14. end;

Fibonacci

  • Hero Member
  • *****
  • Posts: 1002
  • Behold, I bring salvation - FPC Unleashed
Composable Records - feature branch ready for testing

Pushed feat/composable-records to the FPC Unleashed repo. Code is on the branch, reference doc is at unleashed/docs/composable-records.md, README updated.

The Lazarus IDE side also has a matching feat/composable-records branch (fpc-unleashed/lazarus) with autocomplete and syntax highlighting for the new constructs (union, embed, etc.) - so if you build the IDE off that branch you get full editor support out of the box.

I expect bugs - it's a sizable feature and I probably missed something. If you can, please grab the branch, rebuild the compiler, throw weird things at it and tell me what breaks.

Not going to main yet - I'm keeping feat/composable-records open for bugfixes and adjustments based on what comes back from testing. Code is yours, I'm waiting for expert feedback.

If the doc isn't enough - the branch also ships 211 ready tests in unleashed/tests/testfiles/composable_records. Use them as a reference, try them, tweak them, mess around with your own variants. Have fun.

You can run them with the bundled test runner (unleashed/tests/testtool, lazbuild it once and it lives at unleashed/tests/testtool.exe). Sample run:

Code: Text  [Select][+][-]
  1. > testtool --filter=composable_records
  2. compiler: fpc
  3. tests dir: ...\unleashed\tests\testfiles
  4. discovered 211 test file(s)
  5. filter: composable_records
  6. parallel: 8 workers
  7.  
  8. [1/211] composable_records\composable_records_aligned_heap_freemem_nil_01.pp ... PASS
  9. ...
  10. [211/211] composable_records\composable_records_with_inline_anon_01.pp ... PASS
  11.  
  12. 211 tests, 211 passed, 0 failed (7391 ms)
  13. logs: ...\unleashed\tests\tests.log
  14.  
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

flowCRANE

  • Hero Member
  • *****
  • Posts: 986
I'm very interested in this dialect because I'm tired of the language's archaic syntax. ...<cut>... Admittedly, I want to stick to the very basics of the language syntax and data types... <cut>

This is a contradiction. Or the syntax of a particular language is archaic -> so I don't want to use it. Or: I want to use it -> therefore the syntax is clearly not archaic.

It’s not a contradiction, because it has nothing to do with whether I want to use a particular syntax or not. The fact that I prefer to stick to basic syntax and data types (e.g., no OOP, tuples, pattern matching) doesn’t mean that this basic syntax suits me. And it doesn’t suit me, for example, when it comes to unions, bit fields, arrays, etc.—these are basic data types whose syntax is overly complicated.

Quote
Besides, how can you recognize archaic or (its opposite) modern syntax? Because it is different from other languages?

Mainly because it hasn't changed in decades, it's clunky and deviates from the norm. If a particular syntax can be improved, it should be improved, and I'm glad that work is underway on these aspects (at least some of them).

Quote
When declaring arrays, you specify a number in square brackets, and when specifying the element index, you also specify a number in square brackets. This is error-prone.

Why exactly would that be error-prone? An array declaration is a separate and unambiguous context, so it’s impossible to confuse specifying the number of array elements with accessing a specific element. It is not without reason that other languages have a syntax completely different from Pascal’s, because it is simpler, shorter, and still unambiguous.

When I declare an array, I do so for a specific number of elements, and I almost always use zero-based indexing. And since the indexing is the same in 99.9% cases, requiring the index range to be specified in 99.9% of declared arrays is a waste of time and unnecessarily lengthens the code.

Quote
Secondly, the idea of ​​"tinkering" with the counter of a "for" loop within that loop is absurd. These two ideas should not be implemented under any circumstances, as they will cause various problems in the future.

It is absurd to prohibit the use of the alter iterator in for loops and force users to use other loops. Not only does this fail to prevent incorrect implementations (since exactly the same problems exist with while or repeat loops), but it also forces a longer implementation and annoys the user by treating them like an underdeveloped child.

A programming language is a tool that is meant to serve the user. Programming isn’t kindergarten—either you know how to program or you don’t, and if you don’t, the language’s features don’t matter, because you won’t be able to use them correctly anyway, regardless of what’s allowed and what isn’t. If you can't implement the algorithm using a for with altering its iterator, you won't be able to implement it using a while loop either.

Quote
This idea is redundant, error-prone, and difficult to read compared to the current one.

Absolutely not, and that is precisely why most modern programming languages use exactly this syntax, whereas the one found in Pascal is redundant and rarely found anywhere. In contrast, the Pascal syntax is error-prone because it requires specifying the upper index, which makes it much easier to make a mistake by forgetting the -1 for 0-based indexing.

Quote
A typical C-ism.

No, it's just a simplification of what is redundant. In contrary, yours is a typical case of C-phobia (or even modern-phobia as such syntax is commonly used in nearly all modern programming languages).

Quote
Another terrible idea. Especially the one with two or three variables in the loop header. If someone thinks they need this language construct, they should probably rethink their code, because something is flawed.

What are you talking about? You write as if you've never written a loop in your life where the iterator needs to be modified dynamically and on which the final number of iterations depends. Of course such algorithms exist (and I even gave an example of one I recently implemented), and of course it would be easier and simpler to implement it using a for loop rather than a while loop.

And the funniest part is that you can easily implement loops in C or C++ this way, dynamically modifying not only the for loop iterator but also its termination condition. This gives you full control over how the loop behaves and reduces the amount of code you need to write, and this is exactly what my proposal is about. But C/C++ is a tool that supports the programmer, while Pascal is an overprotective mom, unjustifiably forbidding her child from doing this and that so the poor thing doesn’t hurt itself. 8)
« Last Edit: May 15, 2026, 07:36:17 pm by flowCRANE »
Lazarus 4.6 with FPC 3.2.2, Windows 11 — all 64-bit

Working solo on a top-down retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

440bx

  • Hero Member
  • *****
  • Posts: 6542
But C/C++ is a tool that supports the programmer, while Pascal is an overprotective mom, unjustifiably forbidding her child from doing this and that so the poor thing doesn’t hurt itself. 8)
Pascal, C and C++ are extremely loose languages and, that's not an exaggeration at all.

A programming language is a tool that, at least in theory, is supposed to help the programmer ensure the code works as intended.  C and C++ are simply bad jokes in that area, there is no concept in those things of what a compiler is actually supposed to accomplish and, if you think that's an exaggeration, I wish it were.  Those two things let programmers insert bugs in the code because their syntax allows radically different semantic constructs such as "=", "==", "|", "||" and many others I don't care to type, in the same statement, which means a simple typo can land the programmer in a debugger and, that's just the start, there are famous bugs that were caused by the programmer forgetting to put a "break" in a switch statement.

C and C++ are the perfect examples of how NOT to design a programming language.  They are _garbage_.  The reasons they've become popular are: 1. a capable operating system was developed using C.  2. there was not a language out there that had all the features (not the syntactic disgraces but, the features) it provided, that resulted in a lot of code written in C, which made it difficult to stop using it because of the cost of abandoning millions upon millions of lines of code.  3. lots of programmers take a rather misplaced pride in using those two languages, because it is extremely unfortunate that someone who is well versed in C and C++ and uses them, is often looked up at as a very competent programmer, which in the majority of cases, is very different from the reality. 

A programmer who impresses me is the programmer who can write code I can understand with a minimum of effort, that programmer impresses me.  The many self-proclaimed programmers who are proud of writing code I find hard to understand, more often than not, I don't even consider them programmers.  Very impressive... nice try.. but, if you want a cigar, try again.

Ada, Rust, Go, Eiffel and a few other programming languages are the languages that should be noticed and features imported from.

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

Curt Carpenter

  • Hero Member
  • *****
  • Posts: 759
I'm old and crabby and think most of the innovations here just pollute an otherwise elegant language that struck (and this is really important in my view) a great compromise between the interests of the program writer and the program reader. 

Who is going to document all of these wonders?  And in a way that will take them accessible to a new generation of programmers (assuming there is one)?   

Marco Cantu's Object Pascal Handbook (10.1) is already 547 pages long.  I'm not sure adding another hundred pages describing relatively esoteric features (that are after all eventually going to be mapped into a very limited assembly language anyway) makes a lot of sense. 

We seem to be close to a time when everyone could create his/her own personal programming language and add features at will with the help of a Claude-like AI.   The downside of that future is that nobody but the author will be able to read the programs in  that language (unless they are very fully documented -- and we all know the history of that).   

 

TinyPortal © 2005-2018