Recent

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

440bx

  • Hero Member
  • *****
  • Posts: 6488
Pascal emphasizes keeping like things together, that is, a section for types, a section for constants, a section for local variables and IMO, persistent variables are different enough to merit their own section.  The thought of having to read the entire variable section to determine if there are persistent variables is time consuming and error prone, therefore unappealing.

Because of the above, I would prefer seeing those variables in their own section, that way there is a pattern that is immediately identifiable and, in addition to that, any "absolute"(s) that may apply to any of them should also be declared in that section.

It's about keeping like-things together instead of mixing them with other things, in this case, non-persistent local variables.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Fibonacci

  • Hero Member
  • *****
  • Posts: 949
  • Behold, I bring salvation - FPC Unleashed
It's great that you're discussing the proposed static/persistent variable feature - I'm happy to see where this conversation is going. Just keep one thing in mind: this would be an Unleashed feature (let's be realistic - there's no way this lands in upstream FPC).

One of the main features in Unleashed, disliked by many, are inline vars. So if we're talking about special kinds of variables and the blocks/sections where they should be declared, it would be nice if they could also be declared inline.

From what I've read and figured out in this thread, the best approach would be to use the static keyword in three contexts. You can't make everyone happy - we need to find a compromise. My current proposal is to allow static in 3 places:

1. static as a declaration section (alternative to writable typed constants, which stay for backward compatibility):

Code: Pascal  [Select][+][-]
  1. procedure Foo;
  2. static
  3.   counter: Integer = 0;
  4. begin
  5.   Inc(counter);
  6. end;
  7.  

2. static as an attribute in a var section:

Code: Pascal  [Select][+][-]
  1. procedure Foo;
  2. var
  3.   counter: Integer = 0; static;
  4. begin
  5.   Inc(counter);
  6. end;
  7.  

3. static as an attribute in an inline-var:

Code: Pascal  [Select][+][-]
  1. procedure Foo;
  2. begin
  3.   var counter: Integer := 1; static;
  4.   Inc(counter);
  5. end;
  6.  

Since static works as an attribute in inline-var, there's no reason it couldn't be used in a regular var section too - that's just a natural extension.

And since we're introducing a keyword in a new context anyway (well, an existing keyword, but used in new circumstances), why not add type inference for static vars while we're at it? For example:

Code: Pascal  [Select][+][-]
  1. // inline-var
  2. var counter := 1; static;
  3.  
  4. // static section
  5. static
  6.   counter := 0;       // inferred as Integer
  7.   name := 'default';  // inferred as String
  8.  

No need to spell out the type - the compiler figures it out from the initial value (integer literals as Int32, strings always as String even if the value is a single character)

This gives us the clean separation from const that @440bx is asking for, it naturally extends to inline declarations and regular var sections - the direction Unleashed is heading anyway - and as a bonus we get a more convenient syntax with type inference.

Sure, that's 3 places where static can appear - but as I've mentioned earlier in this thread, it's the programmer's responsibility to keep their code readable. You can write code with inline vars that is perfectly clear to someone reading it for the first time, and for some of us inline vars actually improve readability compared to having variables declared somewhere far away in a single block at the top (myself included). It's the programmer's choice and responsibility to write clean code. The syntax should make it possible - how people use it is up to them.

On top of that, this is great for small programs, personal unpublished projects, quick prototyping - and when it's time to publish, you can always move those variables into proper sections. Maybe even use @Thaddy's de-inliner to do it for you :D
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
From what I've read and figured out in this thread, the best approach would be to use the static keyword in three contexts. You can't make everyone happy - we need to find a compromise.

As mentioned above, I'd be fine without static as an attribute. I'm not sure if there's currently someone who prefers that; maybe this could then be added later.


My current proposal is to allow static in 3 places: [...]

Could static simply be allowed wherever var is allowed?

Code: Pascal  [Select][+][-]
  1. procedure Foo1;
  2. static
  3.         Counter : Integer = 0;
  4. begin
  5.         Inc(Counter);
  6. end;
  7.  
  8.  
  9. procedure Foo2;
  10. begin
  11.         static Counter : Integer = 0;
  12.         Inc(Counter);
  13. end;
  14.  

Thaddy

  • Hero Member
  • *****
  • Posts: 19156
  • Glad to be alive.
That would be my favourite too.
objects are fine constructs. You can even initialize them with constructors.

Fibonacci

  • Hero Member
  • *****
  • Posts: 949
  • Behold, I bring salvation - FPC Unleashed
So that's 2 votes for static as a declaration keyword (like var) rather than a trailing attribute.

Code: Pascal  [Select][+][-]
  1. // as a section
  2. procedure Foo1;
  3. static
  4.   counter: Integer = 0;
  5.   flags := 42; // inferred as Int32
  6. begin
  7. end;
  8.  
  9. // inline
  10. procedure Foo2;
  11. begin
  12.   static counter: Integer := 0;
  13.   static flags := 0;
  14. end;
  15.  

That's clean and consistent - I like it. Keep the feedback coming.
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

ccrause

  • Hero Member
  • *****
  • Posts: 1117
Quote from: creaothceann link=topicode=pascal
c=73678.msg580665#msg580665 date=1775998851]
Could static simply be allowed wherever var is allowed?
Then also in this case?
Code: Pascal  [Select][+][-]
  1. procedure someProc(static a: integer);
I suppose this would then enforce passing a reference to a static only.  But then do one accept assigning a static to a normal parameter if it is type compatible?

Maybe this seems absurd and the urge would be to make an arbitrary decision, however my consideration is to make the syntax and language rules as internally consistent as possible.

Thaddy

  • Hero Member
  • *****
  • Posts: 19156
  • Glad to be alive.
That would replace constref?
objects are fine constructs. You can even initialize them with constructors.

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
Then also in this case?
Code: Pascal  [Select][+][-]
  1. procedure someProc(static a: integer);
I suppose this would then enforce passing a reference to a static only.  But then do one accept assigning a static to a normal parameter if it is type compatible?

Maybe this seems absurd and the urge would be to make an arbitrary decision, however my consideration is to make the syntax and language rules as internally consistent as possible.

No, because var parameters don't have to be global variables.

The "var" keyword is just unfortunately named.

ASerge

  • Hero Member
  • *****
  • Posts: 2492
Case 1 may be confused with the currently valid syntax:
Code: Pascal  [Select][+][-]
  1. class procedure TSome.Foo; static;
or
Code: Pascal  [Select][+][-]
  1. class procedure TSome.Foo;
  2.   static
  3. ;

Thaddy

  • Hero Member
  • *****
  • Posts: 19156
  • Glad to be alive.
Yes. good catch. That makes it infeasible.
objects are fine constructs. You can even initialize them with constructors.

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
Afaik an empty var block is not allowed, so an empty static block would mark the subroutine itself as static.

dseligo

  • Hero Member
  • *****
  • Posts: 1683
Now, about the keyword itself - static, persistent, or keep?

I'd go with either static or keep. Both are short, easy to type, and immediately clear in meaning. persistent is descriptive but annoying to type (and easy to mistype) - not a great quality for a keyword you'll use regularly. Between the two, static has prior art in C/C++ and maps to the exact same concept. keep is a fresh alternative if we want to avoid the C baggage. Either way, both are better than persistent purely from a practical standpoint.

I suggest you use const, so it would differentiate from C, and we are all used to it. So it would mean 'variable' which is 'persistent' (constant). It would look like this:
Code: Pascal  [Select][+][-]
  1. var x: Integer = 1; const;
  2.  

440bx

  • Hero Member
  • *****
  • Posts: 6488
Case 1 may be confused with the currently valid syntax:
Code: Pascal  [Select][+][-]
  1. class procedure TSome.Foo; static;
or
Code: Pascal  [Select][+][-]
  1. class procedure TSome.Foo;
  2.   static
  3. ;
I was concerned about that.  Anytime a keyword is re-used for something else it opens the door to ambiguities.



So that's 2 votes for static as a declaration keyword (like var) rather than a trailing attribute.

Code: Pascal  [Select][+][-]
  1. // as a section
  2. procedure Foo1;
  3. static
  4.   counter: Integer = 0;
  5.   flags := 42; // inferred as Int32
  6. begin
  7. end;
  8.  
  9. // inline
  10. procedure Foo2;
  11. begin
  12.   static counter: Integer := 0;
  13.   static flags := 0;
  14. end;
  15.  

That's clean and consistent - I like it. Keep the feedback coming.
Make that 3 votes.

The keyword, whatever it may end up being, can be used to create sections that consist of a single identifier.  IOW, it is still a section identifier that just like "var", "type" and "const" may be repeated as many times as desired/necessary and may consist of one or more declarations but, when inline, I suppose it would be forced to consist of 1 and only 1 declaration, just like "var" though, strictly speaking, I don't see why it should be limited to a single declaration, there doesn't seem to be a syntactically valid reason for that limitation.  Can someone with Delphi check if it supports an inline "var" section or is it limited to a single declaration per "var" ?

As far as the possible ambiguity with other uses of "static", I still support "persistent", for those who find it too long to type, I suggest allowing it to be abbreviated, IOW, have it as "per[sistent]".  IOW, either "per" (3 letters, just like "var") or fully spelled "persistent".  This is not unusual but it has the downside of creating two new keywords instead of only one.  If "per" or "persistent" is used as a variable name (in existing code) then the variable name can simply be prefixed with "&" to make it valid code (a feature already present in FPC.)  IOW, it may require a very simple change to make it compatible. 



Static (or whatever its name ends up being) has nothing to do with parameter passing conventions.  Using it in parameter declarations makes no sense. 

In parameter passing "var" does _not_ indicate space allocation, it indicates passing by reference.  IOW, the "var" keyword is semantically overloaded, that doesn't mean, "static" (or whatever it ends up being) should be overloaded too.


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

creaothceann

  • Sr. Member
  • ****
  • Posts: 361
I don't see a technical limitation, but maybe a usability issue: if you use type inference, the type is omitted and the result is visually similar to an assignment.

This may hide errors when you want to declare a static variable but accidentally use the name of an already existing one, or if you want to continue with an assignment but accidentally create a new static variable.

Code: Pascal  [Select][+][-]
  1. procedure P;
  2. var
  3.         s_a : string;
  4. static
  5.         s_b : string = '2';
  6. begin
  7.         static
  8.                 s_c : string := '3';  // static inline variable
  9.                 s_d          := '4';  // static inline variable with type inference
  10.                 s_a          := '1';  // already existing name --> assigment
  11.                 s_e          := '5';  // error: not in static block
  12. end;

Fibonacci

  • Hero Member
  • *****
  • Posts: 949
  • Behold, I bring salvation - FPC Unleashed
if you use type inference, the type is omitted and the result is visually similar to an assignment.

You still need the var (or static) keyword before it.

This may hide errors when you want to declare a static variable but accidentally use the name of an already existing one, or if you want to continue with an assignment but accidentally create a new static variable.

Code: Pascal  [Select][+][-]
  1. procedure P;
  2. var
  3.         s_a : string;
  4. static
  5.         s_b : string = '2';
  6. begin
  7.         static
  8.                 s_c : string := '3';  // static inline variable
  9.                 s_d          := '4';  // static inline variable with type inference
  10.                 s_a          := '1';  // already existing name --> assigment
  11.                 s_e          := '5';  // error: not in static block
  12. end;

Code: Pascal  [Select][+][-]
  1. procedure P;
  2. var
  3.         s_a : string;
  4. static
  5.         s_b : string = '2';          // <-- this is static
  6. begin
  7.         static
  8.                 s_c : string := '3'; // <-- this too is static
  9.                 s_d          := '4'; // <-- invalid syntax (missing var, static, or an existing variable to assign to)
  10.                 s_a          := '1'; // <-- normal assignment to an existing var
  11.                 s_e          := '5'; // <-- invalid syntax (missing var, static, or an existing variable to assign to)
  12. end;
  13.  

There are no "sections" inside begin..end - inline static (just like inline var) is a single statement, not a block header.
FPC Unleashed - inline vars, tuples, statement expressions, array equality, compound assignments, indexed/lazy labels, no-RTTI & more. ⭐ Star it on GitHub!

 

TinyPortal © 2005-2018