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

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12760
  • Debugger - SynEdit - and more
    • wiki
Delphi has the "Split" mode of the IDE, where you can see the same "unit" but with different views (as this case, one view is in the declaration section, another is in the cdoe editing).

Ah, well. A bit like in Excel (and other spreadsheets). I had the idea to add it for a long time. But as for the time, I longed for an idea where to find it.

But, we have multiple source edits (as many as you like), all showing the same unit => dock them and it "looks" the same.

As for navigation => Lazarus has "lock page" (context menu of the tab). And that will prevent that editor from being scrolled by the IDE (you can still scroll it while working in it, but codetools etc will not scroll it). So "lock" the editor with the declarations, and it stays in view. And with the correct settings in Tools > Options > Editor > "pages and windows" ( https://wiki.lazarus.freepascal.org/IDE_Window:_Editor_Options_MultiWindow ) code navigation to/from that area will work well.

LeP

  • Guest
@Martin_fr
So, you have the solution for this question. No inline vars involved and you can view and modifiy your unit very easy without jump around (you must stil jump around the windows ...  :D)

d2010

  • Sr. Member
  • ****
  • Posts: 264
FPC Unleashed
  var s := 'hi there';
  var i := 42;
  // or
  var s2: string := 'hello';
  var i2: integer := 66;

Please , please Can you implement "attribuinctyon -function"?
I need replace := with a function?  please , please . . . . .
Eg1.  from Basic-z81 exists LET? In python? In Lisp exists Setq..
Code: Pascal  [Select][+][-]
  1. Var n, i:integer;
  2. Begin  i:=00;
  3.   f:=open(nymf,"a");
  4.      foreach(n,lsta,princ(n,f),setq(i,i+1));
  5.    close(f);
  6. End;
  7.  
Var poz:integer;
Begin
     for len:=strlen(ring)+1 downto 01 do
          if (LET(poz,vl.string_search(ring,s144))) then writeln('Great Function');
End;
[/code]
 :P




Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12760
  • Debugger - SynEdit - and more
    • wiki
@Martin_fr
So, you have the solution for this question. No inline vars involved and you can view and modifiy your unit very easy without jump around (you must stil jump around the windows ...  :D)
I have my workflow (I don't actually use the dual window for local vars, but I do when I refactor larger code blocks, and need unit interface and implementation parts in view).

And also never mind how you organize your code (OO or not, sub-routines or not, new language or not), if have more than a certain amount of lines of code they don't fit onto one screen. That is a given.
And also, there will always be some point where you need 2 parts in the code that don't show on the screen if you just have the full text show in a single window.

But, that wasn't my question.

For me, I do much more often look on what a block of code does with a variable, than I need to check what type that variable is. If I really need that type, then that usually is a one time lookup at the start (takes a few seconds at most), and then I may spend (many) minutes to understand the code acting on it.
So to me, I want that code acting on it, as close together as I can, in order to *not* having to scroll it.

But, from the fact that other do want that code containing inlined var declarations, I must take it that they have some workflow were that differs? Or do others never have to look at code and figure out what it does?
So, if it comes to that, how to they deal with the extra space taken?




Btw, to me, the ability to see as much continuous code as possible went so far, that I added features to the source editor to eliminate any "dilution".
If you right click the fold part of the gutter (where the +/- fold symbols are), then it will offer you to fold/hide all comments (if you have a selection then in the selection). And if there are inactive ifdef, it will offer to fold them too.
So one or two clicks, and all that disappears from view.

So that then explains why I would go and ask: Why would someone add more interruptions into the code base?
Again, clearly some people want that. And that is their deal, whatever helps them. All I ask is, how does it help?

creaothceann

  • Sr. Member
  • ****
  • Posts: 471
Code: Pascal  [Select][+][-]
  1. for var j := 1 to 5 do writeln('j = ', j);

While I applaud the effort, there's a big problem here: the control variable /has/ to look like a standard declaration since

(a) if it doesn't then there is no indication that the reader should not look earlier in the code to find the type and scope, and
(b) in the absence of an explicit type it's unclear whether the control variable should be interpreted as signed or unsigned (etc.).

(a) Unless for statements would gain the requirement that its control variable must be declared in the for statement itself, automatically eliminating the possibility that the variable was declared much earlier.
(b) Unless I'm overlooking something, this can be derived from the initial and final value expressions (for ... to) or from the enumerable (for ... in).


Making sure that the control variable is properly declared (i.e. with a type) might possibly go some way to preventing the reactionaries from arguing that it's being used without declaration

Declarations are not limited to const/type/var. The for statement itself can be a declaration, just like functions declare Result.


If the programmer wants the value to be defined on completion of the statement, then he uses the "traditional" form

For these cases the programmer could be explicit and add an assignment of the control variable to a previously declared variable.


I believe that a programming language is more than just a long list of features. The syntax should be (relatively) simple and unambiguous [...]. Maybe even fractal, where a general syntax pattern holds from a simple "for" loop all the way to program level like in Mark's example above.

Wirth even proposed declaring program parameters after the program keyword, to realize this 'fractal' pattern. Since then this idea has been abandoned, just like other historic restrictions of the original Pascal language.

In my opinion, a programming language first and foremost has to allow me to solve real-world problems. This is technically possible in Borland/Turbo/Delphi/Free Pascal implementations since they allow for ASM blocks and the inclusion of externally compiled code, but I'd really like a nicer syntax than that.


whats wrong with having a const declaration at the beginning of your function [...] If you need local constructs like this, your function is definitely to [sic] long

Or you just have never been in a situation where a long function is the best solution to the problem.


How does one prevent (for lack of better / more neutral words) "code dilution". That is, how does one prevent to have to many declarations amidst the code that expresses the algorithm?
Or how do others deal with reading code, that requires continued skipping forward over inlined declarations? And eventually extra scrolling just to see the remainder of the code?
[...] (lets assume, even if not always true, that for understanding "what the code does" the exact type of each variable is not immediately needed / i.e. can be checked at a later/different time)

Declarations are part of the algorithm. It does matter if I declare a variable as byte or qword, in relation to speed, memory usage, and behavior.
I guess if you really don't want to see the declarations you could put them into macros or include files.
« Last Edit: March 28, 2026, 01:56:52 am by creaothceann »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12760
  • Debugger - SynEdit - and more
    • wiki
(b) in the absence of an explicit type it's unclear whether the control variable should be interpreted as signed or unsigned (etc.).
(b) Unless I'm overlooking something, this can be derived from the initial and final value expressions
Quote
How does one prevent (for lack of better / more neutral words) "code dilution". That is, how does one prevent to have to many declarations amidst the code that expresses the algorithm?
Or how do others deal with reading code, that requires continued skipping forward over inlined declarations? And eventually extra scrolling just to see the remainder of the code?
[...] (lets assume, even if not always true, that for understanding "what the code does" the exact type of each variable is not immediately needed / i.e. can be checked at a later/different time)

Declarations are part of the algorithm. It does matter if I declare a variable as byte or qword, in relation to speed, memory usage, and behavoir.

Interesting, that you should bring up range issues in the 2nd part, yet overlooking them in the first.

Code: Pascal  [Select][+][-]
  1. for n := func_qword_A to func_qword_B - 1 do ....;  // or func_cardinal, if your target arch does not support qword

What would the loop var be?
- qword? That overflows to $FFFFFFFFFFFFFFFF if the func_qword_B returned zero. A long running loop. (And cheap work around will fail, -1 is also a computed value and can be much bigger substraction)
- int64? That overflows if the func_qword_* return a bigger value. (and if used in expressions in the loop, the sign may matter a lot)



As for the relation to my question. I get your point, but in my way of working it does not apply.
Looking at the 2 probably most common cases that I may read the code:
- general understanding
- searching a bug (by code review, instead of debugger / though in some cases that may matter for a debugger run too)

In (1) I can simple rely that ordinal types have proper size, and it wont matter. At best it will matter if I see that code intentional over/underflows to wrap around. (e.g. a pointer into a roundbuffer with size 2^8, 2^16, 2^32). But then the algorithm/code will tell me that it does rely on the overflow, and again I know the size must be chosen to match.
EDIT: yes, you could conceive some highly optimized math code that shortcuts stuff by using overflows... For me that makes a "below tiny" fraction of my readings (currently 0 / but of course may happen / see gain/loss calculations)

In (2), I will have to check that size, there you are right I have to travel the extra distance.

But then in (2) that is a once off check.   I loose 1 or 2 seconds in this case. Most of the reading I have to do is for (1), so I do save a lot more time in those readings than I loose in the few cases of (2).

So yes, I can and do understand specific cases where (leaving all else aside) it "makes sense". But I can't get the overall math to work. I can't just leave away that there are other tasks too.

But maybe that mix is different for everyone.... I do work on code-bases that
- are worked on by teams
- have considerable age (decades)
So encountering code I either don't know or don't remember is frequent.
Any time saved in "reading for understanding" far outweighs any time used when I need to know the type or declare it.

I guess, if I only did small stuff, that I finish in a month or two, and then never need to change again => then the amount of time for reading would be less.
Actually, that is occasionally the case (and I do have experience with inline declares). When I need a "one off throw away tool/script" I may do that in some script language, and I may do inline vars. But, I only work on that code for usually less than an hour, maybe 2 or 3 in extreme cases. Hardly any reading of code needed.
When I had to recover such code later (really rare), it has bitten me... (When I done bigger stuff in JS, I moved declarations to the top whenever possible)

The most common issues (and that is inline other than "for" vars) is that I know there is a variable "foo", I don't see where it is declared, and I try using it before its declared. And I then spend time on resolving that error.

Again, not wanting to stop anyone, if they feel its better for them (as long as no one expects me to read it). Just broadening my understanding of what/why others do...
« Last Edit: March 27, 2026, 10:48:07 pm by Martin_fr »

creaothceann

  • Sr. Member
  • ****
  • Posts: 471
(b) in the absence of an explicit type it's unclear whether the control variable should be interpreted as signed or unsigned (etc.).
(b) Unless I'm overlooking something, this can be derived from the initial and final value expressions
Quote
How does one prevent (for lack of better / more neutral words) "code dilution". That is, how does one prevent to have to many declarations amidst the code that expresses the algorithm?
Or how do others deal with reading code, that requires continued skipping forward over inlined declarations? And eventually extra scrolling just to see the remainder of the code?
[...] (lets assume, even if not always true, that for understanding "what the code does" the exact type of each variable is not immediately needed / i.e. can be checked at a later/different time)

Declarations are part of the algorithm. It does matter if I declare a variable as byte or qword, in relation to speed, memory usage, and behavior.

Interesting, that you should bring up range issues in the 2nd part, yet overlooking them in the first.

Code: Pascal  [Select][+][-]
  1. for n := func_qword_A to func_qword_B - 1 do ....;  // or func_cardinal, if your target arch does not support qword

What would the loop var be?
- qword? That overflows to $FFFFFFFFFFFFFFFF if the func_qword_B returned zero. A long running loop. (And cheap work around will fail, -1 is also a computed value and can be much bigger substraction)
- int64? That overflows if the func_qword_* return a bigger value. (and if used in expressions in the loop, the sign may matter a lot)

Free Pascal already chooses qword: Running

Code: Pascal  [Select][+][-]
  1. function question1 : qword;  begin  ReadLn(Result);  end;
  2. function question2 : qword;  begin  ReadLn(Result);  end;
  3.  
  4. var
  5.         i : qword;
  6.  
  7. begin
  8.         WriteLn('a');
  9.         for i := (question1) to (question2 - 1) do WriteLn('x ', i, ' y');
  10.         WriteLn('b');
  11.         ReadLn;
  12. end.

... and entering 0 for both prompts does display a long list of values.
EDIT 1: Using for i := (question1 - 1) to (     question2) do ... and entering 0 for both prompts does not execute the loop.
EDIT 2: Using for i := (question1    ) to (-1 + question2) do ... causes "Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)".

Also, over-/underflows would be detected when overflow checks are enabled.
« Last Edit: March 28, 2026, 12:33:26 pm by creaothceann »

Fibonacci

  • Hero Member
  • *****
  • Posts: 1103
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
New feature: Indexed Labels

Labels now support indexes.

Example

Code: Pascal  [Select][+][-]
  1. label
  2.   mylabel1,
  3.   mylabel2[1, 2, 3],
  4.   mylabel3[1..10],
  5.   mylabel4['foo', 'bar'];
  6.  
  7. begin
  8.   goto mylabel4['foo'];
  9.  
  10.   writeln('you should not see this');
  11.  
  12.   mylabel1:
  13.   mylabel2[2]:
  14.   mylabel3[10]:
  15.   mylabel4['foo']:
  16.  
  17.   writeln('hello!');
  18. end.



New feature: Lazy Label Declarations

Labels no longer need to be declared before use.

Example

Code: Pascal  [Select][+][-]
  1. begin
  2.   goto mylabel;
  3.  
  4.   writeln('you should not see this');
  5.  
  6.   mylabel:
  7.  
  8.   writeln('hello!');
  9. end.



New feature: Compound Assignment for Pascal Operators

Compound assignment is now supported for Pascal operators such as "div", "mod" and "xor", without requiring "{$COPERATORS ON}".

Example

Code: Pascal  [Select][+][-]
  1. var
  2.   i: integer = 10;
  3. begin
  4.   i div= 2;   // equivalent to: i := i div 2
  5.   writeln(i); // prints "5"
  6. end.

Available: div=, mod=, and=, or=, xor=, shl= and shr=.
« Last Edit: March 31, 2026, 07:44:27 pm by Fibonacci »
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub ⭐

440bx

  • Hero Member
  • *****
  • Posts: 6619
I'm curious...

Would you like programmers to use the new features you add into the compiler , i.e, use the features in their own "release" quality software ? or you add them just for fun to have your own toy compiler ?

I ask because that makes a big difference.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Fibonacci

  • Hero Member
  • *****
  • Posts: 1103
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
I'm curious...

Would you like programmers to use the new features you add into the compiler , i.e, use the features in their own "release" quality software ? or you add them just for fun to have your own toy compiler ?

Anyone who wants can use these features in their own software. If there is any problem, they should open an issue on GitHub and I will fix it.

I primarily build this for myself, for my own production-grade software that generates revenue for me. That is where I use FPC Unleashed, and the stability is on the same level as standard FPC - zero issues. I make heavy use of inline variables, statement expressions and no-RTTI.

I ask because that makes a big difference.

Elaborate?
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub ⭐

440bx

  • Hero Member
  • *****
  • Posts: 6619
I ask because that makes a big difference.

Elaborate?
Sure.  PascalDragon mentioned somewhere (might even be in this thread) that the trunk version is not release quality, as such, myself, I would be very uncomfortable using software that is below release quality to produce software that is supposed to be release-quality.   Succinctly, there is a reason the thing is "trunk" and not a formal release.

I believe you thoroughly test the code you add but, odds are good there are problems in the code you are using as the base (trunk.)  To put it in simple terms, release-quality software needs to be produced with a release-quality compiler.  It's likely I'm not the only one who sees it that way.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Fibonacci

  • Hero Member
  • *****
  • Posts: 1103
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
So is FPC fixes supposed to be the bug-free, stable version of FPC?

I built FPC fixes from sources for the first time in my life, and here we go... you call this stable?

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. var
  4.   c: char;
  5.   s: string;
  6.  
  7. begin
  8.   Str(c, s); // Error: Internal error 2013032603
  9. end.

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. procedure proc(arg: array of const);
  4. var
  5.   p: TVarRec absolute arg; // Error: Internal error 99080501
  6. begin
  7.   writeln(PtrInt(@p));
  8. end;
  9.  
  10. begin
  11.   proc([100, 'foo', 'bar']);
  12.   readln;
  13. end.

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. procedure proc;
  4. begin
  5. end;
  6.  
  7. procedure test(const o);
  8. begin
  9. end;
  10.  
  11. begin
  12.   test(proc); // Error: Internal error 2011010304
  13. end.

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. generic procedure proc<T>(arg: T); external 'lib';
  4. // project1.lpr(3,45) Error: Compilation raised exception internally
  5. // Verbose: Compilation aborted
  6. // Debug: An unhandled exception occurred at $00000001000EE7A2:
  7. // Debug: EAccessViolation: Access violation
  8. // Debug:   $00000001000EE7A2
  9. // Debug:   $00000001000EF870
  10. // Debug:   $00000001000EFFEB
  11.  
  12. begin
  13.   specialize proc<Integer>(1);
  14. end.

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. procedure proc(arg: array of const);
  4. var
  5.   p: pointer absolute arg; // Error: Internal error 99080501
  6. begin
  7. end;
  8.  
  9. begin
  10. end.

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. type
  4.   tt = class
  5.     ff: byte;
  6.     property NewInstance: byte read ff;
  7.     constructor Create;
  8.   end;
  9.  
  10. constructor tt.Create;
  11. begin // Error: Internal error 200305108
  12. end;
  13.  
  14. begin
  15. end.

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. // project1.lpr(8,10) Error: Assignments to formal parameters and open arrays are not possible
  4. // project1.lpr(8,13) Error: Internal error 99080501
  5.  
  6. procedure proc(var values: array of string);
  7. begin
  8.   values := ['hi'];
  9. end;
  10.  
  11. begin
  12. end.
  13.  

Worst of all is this:

Code: Pascal  [Select][+][-]
  1. program test_fpc_fixes;
  2.  
  3. procedure test1(arg: integer); inline;
  4. begin
  5.   arg := 1234;
  6. end;
  7.  
  8. procedure test2; inline;
  9. var
  10.   i: integer;
  11. begin
  12.   i := 555;
  13.   test1(i);
  14.   writeln(i); // prints "1234" ????????????????
  15.   readln;
  16. end;
  17.  
  18. begin
  19.   test2;
  20. end.

Stable as hell >:D FPC is a toy.

PascalDragon mentioned somewhere (might even be in this thread) that the trunk version is not release quality

No FPC version is really "release quality".

Tested on "stable", "fixes" and "fixes-3.2" - same bugs everywhere.
« Last Edit: March 31, 2026, 07:13:59 pm by Fibonacci »
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub ⭐

Fibonacci

  • Hero Member
  • *****
  • Posts: 1103
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
May I add - these are just the bugs I found myself (and only some of them - I found more), and they are already fixed in trunk. Just not the worst one - I’ll probably fix that myself.

IMHO, trunk is actually more stable than the old fixes/stable versions.
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub ⭐

440bx

  • Hero Member
  • *****
  • Posts: 6619
There is no doubt there are a good number of bugs in the stable/release version of FPC, currently 3.2.2 and there is no doubt in my mind that there are a good number of them in 3.2.4RC1 which makes it rather likely that a version, trunk in this case, which has added features which have not been extensively used, has even more bugs.

Yes, I really wish 3.2.2 had fewer bugs but, the fact that its got bugs is no reason to use another version which is likely to have even more bugs.

Aside from that, another concern I have is that you're implementing features without discussing how they should be implemented with other programmers (ideally with people who know how to write a compiler and design a computer language.)  Case in point, inline variables should be scope local, making them function/procedure global from the point they are defined is a conceptual mistake.

Also, there are _much_ better (significantly clearer) ways of implementing the functionality of computed gotos without using gotos. 

I think it is great that you want to put the time and effort of pushing FPC forward but, honestly, I don't think you're going about it the right way.

Question for you: did you make the necessary corrections in the compiler to eliminate the internal errors you showed in your previous posts ?

I suggest the following entirely in good faith, read the standard for the original Ada language and the standard for some of the subsequent versions.  The reason I suggest that is, 1. Ada derived a great deal from Pascal which makes it, at least, somewhat familiar to a Pascal programmer.  2. Ada is a very carefully designed language, there is a lot to learn about language design in it.  3. the progression from one standard to another gives you a good idea of what they missed in the previous standards and what the improved (maybe even correct) implementation is.

For someone who wants to add features to FPC, I really believe you could benefit a great deal from taking the above suggestion and, I want to emphasize, it is a suggestion made in good faith.

HTH.

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

Fibonacci

  • Hero Member
  • *****
  • Posts: 1103
  • Behold, I bring salvation - Unleashed Pascal
    • fibo.gg
Question for you: did you make the necessary corrections in the compiler to eliminate the internal errors you showed in your previous posts ?

Most of them no longer exist in FPC trunk. Fixing them is not my responsibility - these are FPC issues and should be addressed by FPC developers. My role is to sync with upstream from time to time.

I suggest the following entirely in good faith, read the standard for the original Ada language and the standard for some of the subsequent versions.  The reason I suggest that is, 1. Ada derived a great deal from Pascal which makes it, at least, somewhat familiar to a Pascal programmer.  2. Ada is a very carefully designed language, there is a lot to learn about language design in it.  3. the progression from one standard to another gives you a good idea of what they missed in the previous standards and what the improved (maybe even correct) implementation is.

Duly noted. I'll probably take a look at Ada. What interests me more, however, is taking the FPC trunk, adding features, and ensuring there are no regressions. Indexed labels were added because they were requested (for state machines). Lazy label declarations are my idea - they allow labels to be used without prior declaration, which I consider a useful improvement.

If there are specific features from Ada that you think are missing in FPC and would be useful, submit a feature request. Describe what you want, provide examples or pseudo-code, explain the use case, and justify it. If it makes sense, the feature will be added.



Bonus: GOTO can use pointers

Something I did not mention earlier - you can use pointers with goto.

Code: Pascal  [Select][+][-]
  1. label mylabel1, mylabel2;
  2.  
  3. begin
  4.   var ptr := @mylabel1;
  5.   goto ptr;
  6.  
  7.   // or
  8.   goto @mylabel2;
  9.  
  10.   writeln('you should not see this');
  11.  
  12.   mylabel1:
  13.  
  14.   writeln('hello1');
  15.  
  16.   mylabel2:
  17.  
  18.   writeln('hello2');
  19.   readln;
  20. end.
« Last Edit: March 31, 2026, 09:21:06 pm by Fibonacci »
Unleashed Pascal: async/await, parallel for, match, tuples, string interpolation, inline vars, autofree, no-RTTI & tons more. Star on GitHub ⭐

 

TinyPortal © 2005-2018