Author Topic: Unleashed Pascal (async/await, parallel for, match, string interpolation & more)  (Read 59528 times)

creaothceann

  • Sr. Member
  • ****
  • Posts: 445
Have you redefined the meaning of this modifier, and in Unleashed Pascal, is it not a hint but an order to be unconditionally obeyed?

With some exceptions.

https://github.com/unleashedpascal/compiler/blob/devel/unleashed/docs/optimizations.md
https://github.com/unleashedpascal/compiler/blob/devel/unleashed/docs/forced-inline.md

Akira1364

  • Hero Member
  • *****
  • Posts: 570
@Akira1364:

I see you deleted your post - but I got it by mail ;) Part of the log was in there, and it does point at what could be wrong.

I pushed a fix to the installer, so grab the nightly and give it a try: https://github.com/unleashedpascal/installer/releases/tag/nightly
Yeah it was picking up another copy of FPC from an environment variable I realized. So I was able to fix it myself. But if you added some kind of extra guard for that, that's cool.

Also, feature proposal I'd personally find highly useful, as I often port C / C++ code to Pascal:

Basically, these, with the same exact semantics / return values, but done rather as freestanding compiler intrinsic "functions" that work just like the existing `Inc` and `Dec` do (meaning, they're generic but in the magic compiler way, as opposed to literally). I think the same function names (just without the class namespace obviously) would be fine and would fit in with existing `Inc` and `Dec` well:

Code: Pascal  [Select][+][-]
  1. class function Util<T>.PreInc(var P: T): T;
  2. begin
  3.   Inc(P);
  4.   Result := P;
  5. end;
  6.  
  7. class function Util<T>.PostInc(var P: T): T;
  8. begin
  9.   Result := P;
  10.   Inc(P);
  11. end;
  12.  
  13. class function Util<T>.PreDec(var P: T): T;
  14. begin
  15.   Dec(P);
  16.   Result := P;
  17. end;
  18.  
  19. class function Util<T>.PostDec(var P: T): T;
  20. begin
  21.   Result := P;
  22.   Dec(P);
  23. end;

Fibonacci

  • Hero Member
  • *****
  • Posts: 1089
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
Good idea. I have found myself missing it at times without really realising it - I have been coding everything in FPC for so long that habit just took over.

Will add it soon :)
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub

creaothceann

  • Sr. Member
  • ****
  • Posts: 445
Code: Pascal  [Select][+][-]
  1. class function Util<T>. PreInc(var P : T) : T;  begin  Inc(P);  Result := P;           end;
  2. class function Util<T>. PreDec(var P : T) : T;  begin  Dec(P);  Result := P;           end;
  3. class function Util<T>.PostInc(var P : T) : T;  begin           Result := P;  Inc(P);  end;
  4. class function Util<T>.PostDec(var P : T) : T;  begin           Result := P;  Dec(P);  end;

It's unlikely to be noticeable except in benchmarks, but this might produce some very slightly faster results (some nanoseconds):

Code: Pascal  [Select][+][-]
  1. class function Util<T>. PreInc(var P : T) : T;  begin  Result := P + 1;  P := Result;      end;
  2. class function Util<T>. PreDec(var P : T) : T;  begin  Result := P - 1;  P := Result;      end;
  3. class function Util<T>.PostInc(var P : T) : T;  begin  Result := P;      P := Result + 1;  end;
  4. class function Util<T>.PostDec(var P : T) : T;  begin  Result := P;      P := Result - 1;  end;

Fibonacci

  • Hero Member
  • *****
  • Posts: 1089
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
devel merged to main - what's new

A bigger batch than usual - the devel branch just landed on main. Highlights below.

New intrinsics: PreInc / PostInc / PreDec / PostDec

On by default in {$mode unleashed}; elsewhere {$modeswitch prepostincdec}. Pre/post increment and decrement as value-returning builtins: the Pre pair returns the value after the update, the Post pair the value read before it. Optional step like inc/dec, same operand types (integers, enums, chars, currency, pointers, records with class operator Inc/Dec), side-effecting operand address evaluated once, properties hit the getter and setter exactly once.

Code: Pascal  [Select][+][-]
  1. var i := 10;
  2. a := PostInc(i);       // returns old value: a = 10, i = 11
  3. a := PreInc(i);        // returns new value: a = 12, i = 12
  4. a := PostDec(i, 3);    // optional step: a = 12, i = 9
  5. a := PreDec(i, 4);     // a = 5, i = 5

Pattern-detected only when no symbol of that name is in scope, so your own PreInc keeps working. Docs: introduced-functions.md

Inline overhaul: inline is now forced in unleashed mode

In {$mode unleashed}, inline means inline - not "if the compiler feels like it". Cases stock FPC silently gives up on now expand: routines with embedded asm statements, pure-assembler routines (spliced at the call site), open-array and array-of-const parameters, inherited calls, a body defined after the call site, and forward combined with inline. When an inline still can't happen, you get one clear report at the definition instead of silence. Docs: forced-inline.md

Optimizer: auto-inlining and devirtualization

Procvar calls with a constant target are devirtualized into direct calls (and can then inline). Auto-inlining and devirtualization decisions are reported as hints, so you can see what the optimizer did. {$inline off} now genuinely stops all inline expansion, and {$optimization} accepts trailing +/- on a switch. Docs: optimizations.md

Indexed labels: dispatch upgrade

@name[index] is now supported, variable-index dispatch prefers a jump table, a goto to an undefined member falls through instead of warning, and the label family is frozen once a variable-index goto is generated. Reference doc expanded.

Fixes
  • Inline declarations in nested bodies, and as the sole body of a control-flow statement (#21).
  • IE 200405231 on an inline call inside finally - also present in stock FPC (upstream #41842).
  • win64 external linking: .pdata/.xdata mapped in the ld script + -m i386pep passed - also in stock FPC (upstream #41839).
  • Constant folding of add/sub/mul now respects {$q-} - also in stock FPC (upstream #41843).
  • zeroinit covers block-scoped locals too.
  • Statement-expression branches retype correctly in a set context; constant propagation no longer leaks a constant out of a dead if branch; @label loads survive node copies.

Under the hood
  • Heap: more empty fixed arenas cached.
  • New reference pages: array-equality.md, forced-inline.md, optimizations.md; docs polish across the board.
  • Test suite consolidation: fifteen-odd scattered test groups moved into the unleashed suite, i386 suite green again.

Three of the fixes address bugs that exist in stock FPC as well (#41839, #41842, #41843) - reported upstream.
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub

Akira1364

  • Hero Member
  • *****
  • Posts: 570
devel merged to main - what's new

A bigger batch than usual - the devel branch just landed on main. Highlights below.

New intrinsics: PreInc / PostInc / PreDec / PostDec

On by default in {$mode unleashed}; elsewhere {$modeswitch prepostincdec}. Pre/post increment and decrement as value-returning builtins: the Pre pair returns the value after the update, the Post pair the value read before it. Optional step like inc/dec, same operand types (integers, enums, chars, currency, pointers, records with class operator Inc/Dec), side-effecting operand address evaluated once, properties hit the getter and setter exactly once.

Code: Pascal  [Select][+][-]
  1. var i := 10;
  2. a := PostInc(i);       // returns old value: a = 10, i = 11
  3. a := PreInc(i);        // returns new value: a = 12, i = 12
  4. a := PostDec(i, 3);    // optional step: a = 12, i = 9
  5. a := PreDec(i, 4);     // a = 5, i = 5

Pattern-detected only when no symbol of that name is in scope, so your own PreInc keeps working. Docs: introduced-functions.md

Inline overhaul: inline is now forced in unleashed mode

In {$mode unleashed}, inline means inline - not "if the compiler feels like it". Cases stock FPC silently gives up on now expand: routines with embedded asm statements, pure-assembler routines (spliced at the call site), open-array and array-of-const parameters, inherited calls, a body defined after the call site, and forward combined with inline. When an inline still can't happen, you get one clear report at the definition instead of silence. Docs: forced-inline.md

Optimizer: auto-inlining and devirtualization

Procvar calls with a constant target are devirtualized into direct calls (and can then inline). Auto-inlining and devirtualization decisions are reported as hints, so you can see what the optimizer did. {$inline off} now genuinely stops all inline expansion, and {$optimization} accepts trailing +/- on a switch. Docs: optimizations.md

Indexed labels: dispatch upgrade

@name[index] is now supported, variable-index dispatch prefers a jump table, a goto to an undefined member falls through instead of warning, and the label family is frozen once a variable-index goto is generated. Reference doc expanded.

Fixes
  • Inline declarations in nested bodies, and as the sole body of a control-flow statement (#21).
  • IE 200405231 on an inline call inside finally - also present in stock FPC (upstream #41842).
  • win64 external linking: .pdata/.xdata mapped in the ld script + -m i386pep passed - also in stock FPC (upstream #41839).
  • Constant folding of add/sub/mul now respects {$q-} - also in stock FPC (upstream #41843).
  • zeroinit covers block-scoped locals too.
  • Statement-expression branches retype correctly in a set context; constant propagation no longer leaks a constant out of a dead if branch; @label loads survive node copies.

Under the hood
  • Heap: more empty fixed arenas cached.
  • New reference pages: array-equality.md, forced-inline.md, optimizations.md; docs polish across the board.
  • Test suite consolidation: fifteen-odd scattered test groups moved into the unleashed suite, i386 suite green again.

Three of the fixes address bugs that exist in stock FPC as well (#41839, #41842, #41843) - reported upstream.

Really cool to see the Pre / Post thing I suggeste added. Nice. About the forced inlining though.

Quote
The model is three states, not four: inline means expand it, noinline means never expand it, and no directive leaves the decision to the optimizer (-OoAUTOINLINE at -O3).

It's not really clear what you mean by this at all. The "no directive leaves" part is poorly worded. Like, I'm seeing it inline things (in mode ObjFPC, not mode Unleashed) that certainly AREN'T marked inline (even things like FormResize and such), even when OoAUTOINLINE is not turned on. So it seems like it just ALWAYS happens even if you explicitly don't want it to, even for code outside your project. This is not really necessarily desirable especially if it happens even in debug builds, as inline basically makes it impossible to step over things properly in the debugger.
« Last Edit: August 10, 2026, 02:26:22 am by Akira1364 »

Fibonacci

  • Hero Member
  • *****
  • Posts: 1089
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
It's not really clear what you mean by this at all. The "no directive leaves" part is poorly worded. Like, I'm seeing it inline things (in mode ObjFPC, not mode Unleashed) that certainly AREN'T marked inline (even things like FormResize and such), even when OoAUTOINLINE is not turned on.

Good catch. Auto-inlining (and devirtualization) applied in every mode - it was supposed to be an unleashed-mode thing. Fixed on main: both are now gated on the unit's mode. A unit in {$mode objfpc} gets none of it, at any -O level, even with -OoAUTOINLINE spelled out. Your FormResize stays a real call and the debugger steps through it again.

The docs are also reworded. The model, in short:

inline - forced. You wrote it, it gets expanded, at every optimization level, debug builds included. No size heuristic overrides you. If an expansion is truly impossible, you get one warning naming the routine and the reason, never silence.

noinline - never expanded. The opposite order.

no directive - the routine is a normal call, unless the optimizer picks it up: -OoAUTOINLINE, on at -O3, unleashed units only. And that one is not forced - it is a heuristic with a head on its shoulders: tiny bodies (getters, clamps, thin wrappers), no loops, no exception frames, and every call site still goes through the stock size budget, so it cannot bloat a build the way a forced chain can. Every decision is reported as a hint, so the log shows exactly what stopped being a call.

Devirtualization is the same story: unleashed units only, and it is not inlining - call rax just becomes call doubler.

For debugging: {$inline off} around the code you are stepping through kills every expansion in that region - forced, auto and devirt alike - so breakpoints and stack traces line up with the source again. Or just build with -O1, which FPC itself calls "quick and debugger friendly".
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub

creaothceann

  • Sr. Member
  • ****
  • Posts: 445
Typing {$embed } and using syntax completion shows only EmbedBytes, but not EmbedStr.

EDIT: {$EmbedStr abc 'ab' + 'c.txt'} doesn't work. Not sure it's worth the trouble fixing though.
« Last Edit: August 10, 2026, 05:16:43 pm by creaothceann »

Fibonacci

  • Hero Member
  • *****
  • Posts: 1089
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
Thanks, fixed.

EDIT: {$EmbedStr abc 'ab' + 'c.txt'} doesn't work. Not sure it's worth the trouble fixing though.

It uses the same mechanism as {$I}/{$include}, does it work there?
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub

creaothceann

  • Sr. Member
  • ****
  • Posts: 445
EDIT: {$EmbedStr abc 'ab' + 'c.txt'} doesn't work. Not sure it's worth the trouble fixing though.

It uses the same mechanism as {$I}/{$include}, does it work there?

Code: Pascal  [Select][+][-]
  1. {$include 'ab' + 'c.inc'}                // doesn't work either
  2. const abc = {$EmbedStr 'ab' + 'c.inc'};  // Error: Cannot open include file "+".

So it seems like it's a Free Pascal limitation... The documentation says that using quotes is only intended as a workaround for spaces in a file name / file path.

Fibonacci

  • Hero Member
  • *****
  • Posts: 1089
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
What would you say to making the IDE look a bit more modern?

First things first: this is not in the IDE and it is not public - the code lives in my private repo. I just want to show what could be done, and that it actually works and looks better than the current stock IDE.

Preview here - about 4 minutes of me clicking around: https://streamable.com/pemm2g :)
  • The lazideminimap package is gone. The minimap is now part of the IDE itself - not a package, not optional, nothing to install or remove.
  • The docking packages are gone as well. Docking and the docked form designer are built directly into the IDE now. The IDE is one single window, with panels that can be moved, minimized or closed using buttons in their title bars.
  • Built with Qt6. Currently there are 2 styles - Light and Dark. More could be added.
  • The IDE itself is 100% portable. Start it, point it at the compiler source and binary directories, and that is basically it. The entire IDE directory can be moved wherever you want. Its config lives in config_lazarus next to lazarus.exe, so there is no need for shortcuts carrying "--pcp=" around.
  • I also played with the idea of a simple syntax-highlighting editor: pick a base color palette, let the IDE generate a scheme from it, then fine-tune whatever you want. A few more ready-made highlighting presets would probably make sense too.
I started this because, for a moment, I had a vision of what the IDE could look like. But this is where it ends: two screenshots, a short video, and a prototype.

The reason is simple: finishing it properly would take far more time than I am willing to put into it, and I have other things I would rather spend that time on. For a fork with just 77 GitHub stars, spending weeks or months doing UI gymnastics just to make the IDE prettier is hard to justify. I could turn it into a polished, modern IDE with an integrated form designer and everything else, and realistically maybe 10 people would end up using it :D

So this particular IDE modernization experiment stops here. The fork itself is not going anywhere and will continue to be maintained as usual. I just do not plan to touch the IDE beyond what is actually necessary for Unleashed itself, such as autocomplete and support for Unleashed-specific syntax.

Why am I even posting this here if it is not public and probably never will be?

Because work has already gone into it, so I want to show the result. And, more importantly, to show that the existing IDE can be made to look much more modern without rewriting it from scratch.

But that is not really my role. Lazarus has its own maintainers, and Unleashed is primarily an FPC fork, not a Lazarus fork.
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub

440bx

  • Hero Member
  • *****
  • Posts: 6585
  • The docking packages are gone as well. Docking and the docked form designer are built directly into the IDE now. The IDE is one single window, with panels that can be moved, minimized or closed using buttons in their title bars.
For this reason alone, I'd never use it. 

The docked IDE wastes way too much screen real estate for things I either never use or very rarely use.

That said, what you produced looks nice and I'm fairly sure there will be folks interested in what you've done.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12715
  • Debugger - SynEdit - and more
    • wiki
Agree with 440bx => using a multi monitor desktop, I don't need and don't want docking. It just adds docking headers that I don't need.

Also, from a user point of view, it shouldn't really matter that it is a package. If the IDE was a hundred packages, wouldn't matter to the person who uses the IDE. And the fact that docking can be toggled on/off shouldn't matter either. First install explicitly asks, so everyone gets what they want.

Sorry, just failing to see your point in that. (unless you mean it not modern to ask and have a config option).


Same about minimap. Never used, never needed, never missed. But glad it exists, so those who want it can use it. Only point to be considered on this one would be if pre-installed and with similar options like docking.


Dark scheme, well if you have healthy eyes and really want to change that => go ahead.
No light scheme is not to bright **IF** the ergonomics of your workspace are ok. If you can't afford proper ergonomic setup, well then dark scheme may be the lesser damage to your health.

Yes, whatever fake info is out there: Dark schemes are harmful, compared to an ergonomical correct and proper setup light scheme (which judging by the usual replies 99% of people do not have)


portable: nice. Congrats on that one.


More HL, I agree would be nice. But look at the wiki with user supplied schemes. Very nice, but most suppliers can't even manage to update the one scheme they did.
In the IDE we must update 5 schemes. And most of the times, that means a choice is made based one the default light theme and blindly copied to the other light ones. An often less good choice is made for one dark scheme and applied to the other dark ones.
So with the current maintenance we have for them, more themes would very quickly degrade.
Congrats to you if you spent the time on maintaining all the schemes you add. Maybe you will be considerate towards the users of the original IDE and supply them (with updates) as loadable user schemes. If so: thank you.

creaothceann

  • Sr. Member
  • ****
  • Posts: 445
I do have a multi-monitor setup, but the main one is a 4k display connected via Display Port (so it "disappears" from Windows when turned off),  and an older & slower 2k VA LCD panel connected via HDMI (so it "stays" as a virtual screen even when turned off). The 2k screen is bad enough that I need to increase font scaling to 125% to make it more readable, while the 4k one always stays at 150%. Also, I frequently turn off both displays and sometimes connect remotely via Parsec, and on the remote computer I switch the 2k display back to 100% font scaling.

Of course this mixture of resolutions, font scalings and desktop sizes is poison for getting reliable window positions at all times, so I've reverted to a docked layout with the Unleashed Pascal IDE. With my current project I don't do any GUI work right now, so the only "MDI" windows are the editor window, the Project Inspector to the left of it (making most of the code a bit more centered), and the Messages/Assembler/etc. window below the editor. If and when I buy a second 4k display though I might go back to free-floating windows.

About the minimap - most (not all) of my units only contain a single class and its methods, so Ctrl+Shift+Up/Down is enough to jump to the list of methods etc. The Code Explorer would be useful too, if it wouldn't collaps its tree structure all the time.

What I did like about the video is the clearly distinguishable file tabs, and the quick switch between light and dark mode. The default Lazarus IDE needs a restart, and kinda breaks when switching to Light or CustomDark mode.


Dark scheme, well if you have healthy eyes and really want to change that => go ahead

I usually have a cozy dark environment at home after a bright day in the office, and I use the classic Turbo Pascal colors (background = #0000AA, current line = pure blue, text = yellow by default, symbols = white). A dark color scheme is very useful with it.

440bx

  • Hero Member
  • *****
  • Posts: 6585
OFF TOPIC

@creaothceann,

could you tell us the size of your 2k and 4k monitors ?

I've considered getting one of those but, I don't want to change the font scaling to make the text readable.  I've often wondered if a 32" monitor @ 4k would render text that is readable without having to scale it, hence my question to you.

Currently my largest monitor is 27" with a resolution of 1920x1200 and I find the text to be readable but, it is probably at the edge of what I can read for hours at a time.  27" with res of 1920x1080 is easily readable for hours at a time.  I'd like to have text to be no smaller than what appears in the 1920x1200 in a 2k or 4k setup and I've often wondered if 32" is enough or would I need something larger ?

Thank you and apologies to everyone for the OT question.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018