Recent

Author Topic: Ann: Deinline: a de-inline-var-alyzer  (Read 3362 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 19155
  • Glad to be alive.
Ann: Deinline: a de-inline-var-alyzer
« on: April 11, 2026, 05:22:37 pm »
For those who do not like inline vars or those that need to port Delphi code that introduced the unfortunate inline vars, me and Claude wrote Deinline: a de-inline-var-alyzer:
It de - inline var's your Object Pascal code... It puts the declaration firmly where it belongs. The attached version is 0.1. and considered Alpha, but it is already very useful.
You have to make a few changes yourself, though.
(Later this will be mitigated by type checking the inferenced var, code already testing here, no RTTI used)

Oh, and the code stays Delphi compatible!


An example, given the following code:
Code: Pascal  [Select][+][-]
  1. {$apptype console}
  2. {$ifdef fpc}{$mode objfpc}{$endif}
  3. uses sysutils,classes;
  4.  
  5. procedure UseSomeInlineVars;
  6. begin
  7.   var list := TStringlist.Create;
  8.   for var i := 0 to 10 do
  9.    begin
  10.      var s := 'string'+i.toString;
  11.       for var j := 0 to 9 do List.Add(Random(100).ToString);
  12.    end;
  13.    writeln(list.text);
  14.    List.free;
  15.    readln;
  16. end;
  17.  
  18. begin
  19.   UseSomeInlineVars;
  20. end.

Deinline will translate / de-mistify that into:
Code: Pascal  [Select][+][-]
  1. $ifdef fpc}{$mode objfpc}{$endif}
  2. uses sysutils,classes;
  3.  
  4. procedure UseSomeInlineVars;
  5. var
  6.   list: ; { TODO: add type }
  7.   i: ; { TODO: add type }
  8.   s: ; { TODO: add type }
  9.   j: ; { TODO: add type }
  10. begin
  11.   list := TStringlist.Create;
  12.   for i := 0 to 10 do
  13.    begin
  14.      s := 'string'+i.toString;
  15.       for j := 0 to 9 do List.Add(Random(100).ToString);
  16.    end;
  17.    writeln(list.text);
  18.    List.free;
  19.    writeln;
  20. end;
  21.  
  22. begin
  23.   UseSomeInlineVars;
  24. end.

Let me know what you think.

There is good explanation - I hope - on how to use the program in the introductory header in the source and a more complex example is included.

And it is fully cross platform.

« Last Edit: April 11, 2026, 05:36:22 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

LemonParty

  • Sr. Member
  • ****
  • Posts: 466
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #1 on: April 11, 2026, 06:20:05 pm »
Nice. I would call it "Dechickenizer".
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

paweld

  • Hero Member
  • *****
  • Posts: 1616
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #2 on: April 11, 2026, 06:20:33 pm »
That's a great idea. I think that once it can recognize variable types, it would be worth adding it to the "convert projects/packages from Delphi to Lazarus" tool.
Best regards / Pozdrawiam
paweld

Thaddy

  • Hero Member
  • *****
  • Posts: 19155
  • Glad to be alive.
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #3 on: April 11, 2026, 09:14:54 pm »
@paweld

By now I have version that recognizes and fills in simple vars like integers and strings and classes, but it needs some work: manual, not Claude. That insists on using 3.2.2.
Like something like h2pas it will likely never be perfect but it is a great help.
(the lll is intended)

The old version already recognizes var :integer/string/tstringlist, though, which is valid inline declaration too. I am now just working on inferred types.
The same first example with the types filled in works. Like :
Code: Pascal  [Select][+][-]
  1. {$apptype console}
  2. {$ifdef fpc}{$mode objfpc}{$endif}
  3. uses sysutils,classes;
  4.  
  5. procedure UseSomeInlineVars;
  6. begin
  7.   var list:TStringlist := TStringlist.Create;
  8.   for var i:integer := 0 to 10 do
  9.    begin
  10.      var s:string := 'string'+i.toString;
  11.       for var j:integer := 0 to 9 do List.Add(Random(100).ToString);
  12.    end;
  13.    writeln(list.text);
  14.    List.free;
  15.    readln;
  16. end;
  17.  
  18. begin
  19.   UseSomeInlineVars;
  20. end.
Already makes a clean translation into:
Code: Pascal  [Select][+][-]
  1. {$apptype console}
  2. {$ifdef fpc}{$mode objfpc}{$endif}
  3. uses sysutils,classes;
  4.  
  5. procedure UseSomeInlineVars;
  6. var
  7.   list: TStringlist;
  8.   i: integer;
  9.   s: string;
  10.   j: integer;
  11. begin
  12.   list := TStringlist.Create;
  13.   for i := 0 to 10 do
  14.    begin
  15.      s := 'string'+i.toString;
  16.       for j := 0 to 9 do List.Add(Random(100).ToString);
  17.    end;
  18.    writeln(list.text);
  19.    List.free;
  20.    readln;
  21. end;
  22.  
  23. begin
  24.   UseSomeInlineVars;
  25. end.
« Last Edit: April 11, 2026, 09:59:04 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Thaddy

  • Hero Member
  • *****
  • Posts: 19155
  • Glad to be alive.
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #4 on: April 11, 2026, 09:37:18 pm »
Forgot to mention:
It is already useful if only to determine what you need to change in sourcecode:
deinline  --dry-run <some pas file>
With that option, it shows if inline vars are used and otherwise shows how many.

FOR OTHER USERS: ALL EXAMPLES ARE DISTINCT!!!
« Last Edit: April 11, 2026, 09:59:56 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

LeP

  • Sr. Member
  • ****
  • Posts: 304
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #5 on: April 12, 2026, 12:32:32 am »
Code: Pascal  [Select][+][-]
  1. var
  2.    i ???
  3. begin
  4.   for var i in Something do
  5.     begin
  6.        // do something
  7.     end;
  8.   for var i in SomethingElse do
  9.     begin
  10.        // do something else
  11.     end;
  12. end;                  
  13.  
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #6 on: April 12, 2026, 12:47:46 am »
I must say, I find the Thaddy's idea great. Better correct bad code.




Not that I plan to come close enough to such code to even have to use it.  An alternative is PERL ("Practical Extraction and Reporting Language" is better than "Pascal Extended to Random Lunacy").
And with the former a regex can be run, that could correct much of those issues.

SCNR

440bx

  • Hero Member
  • *****
  • Posts: 6488
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #7 on: April 12, 2026, 01:16:34 am »
De-inlining is fraught with problems.   It is very common to use a generic name such as "i" to index into arrays of different types which means "i" has multiple different types depending on what it is indexing.  This will be "problematic" for something that attempts to de-inline variables.

One of the many reasons for inline variables is to use "junk names" for "junk variables" whose existence is limited to just a few statements and that's the reason they should NOT be made function/procedure global.

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

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #8 on: April 12, 2026, 01:31:23 am »
One of the many reasons for inline variables is to use "junk names" for "junk variables" whose existence is limited to just a few statements and that's the reason they should NOT be made function/procedure global.

This is yet one of the clearest descriptions: Support (and make easier) to have unreadable code.

This is exactly what those opposing it have been saying all along.
(Except that I didn't know you consider part of your code to be junk)

440bx

  • Hero Member
  • *****
  • Posts: 6488
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #9 on: April 12, 2026, 01:47:12 am »
(Except that I didn't know you consider part of your code to be junk)
Not just in my code. :)

Maybe I should be more sensitive to other people's code and call those junk variables simply "noise".  Maybe even "desirable noise" since now there is a utility to generate them.  Somehow, this utility sounds like a substance to add to gasoline for cars to emit more smog because we don't want clean emissions... god forbid.
« Last Edit: April 12, 2026, 01:56:19 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 19155
  • Glad to be alive.
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #10 on: April 12, 2026, 06:10:55 am »
Code: Pascal  [Select][+][-]
  1. begin
  2.   for var i in Something do
  3.     begin
  4.        // do something
  5.     end;
  6.   for var i in SomethingElse do
  7.     begin
  8.        // do something else
  9.     end;
  10. end;                  
  11.  
You code would not be valid Delphi, but:
I am working on what is possible for the case where i is an element of a collection,
e.g. where i is an object in an object collection/array. If that is what you mean.
Translation of your code already works, just type to fill in:
Code: Pascal  [Select][+][-]
  1. var
  2.   i: ; { TODO: add type }
  3. begin
  4.   for i in Something do
  5.     begin
  6.        // do something
  7.     end;
  8.   for i in SomethingElse do
  9.     begin
  10.        // do something else
  11.     end;
  12. end.
See the documentation in the sourcecode.
[edit]
See also what Delphi does:

E2430 for-in statement cannot operate on collection type 'Something'
E2430 for-in statement cannot operate on collection type 'SomethingElse'


Ergo, the bogus is handled as bogus.

The parser really online fails on the exceptions mentioned in the documentation.
(One of which is silly - var should be on the same line - because that is a whitespace error and doesn't count to code. No priority, first find the types)

« Last Edit: April 12, 2026, 06:59:26 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Thaddy

  • Hero Member
  • *****
  • Posts: 19155
  • Glad to be alive.
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #11 on: April 12, 2026, 07:06:20 am »
De-inlining is fraught with problems.   It is very common to use a generic name such as "i" to index into arrays of different types which means "i" has multiple different types depending on what it is indexing.  This will be "problematic" for something that attempts to de-inline variables.

The "Both of my twins are called Bob" logic?

Actually, that was easier than you think: Delphi won't accept that when inferred, so the least of my worries. On typed inline vars everything is already parsed correctly.

So yes, the problematic part is merely understanding the degrees of freedom a compiler can handle and that is often less than you think  %) :D
Btw Just like LeP's code: a solid illustration of why inline vars are evil: the programmer him/herself can not even determine what was meant or how it works. And then imaginary features turn into real problems because things don't happen to fit expectations.

It would be helpful if you show me real world Delphi code that fails to parse, because I haven't found it yet. I had to write the contrived examples that fail the parser but work in Delphi myself. Just as you and LeP seem to think that things work in Delphi that are impossible to solve (inferrance conflicts)

Anyway, writing this tool gave me a much deeper understanding of this "feature" and made me dislike it even more. It is fraught with gotcha's, thus eventually unreadable code.

But I am a great Hives fan and again playing https://www.youtube.com/watch?v=Uz1Jwyxd4tE
« Last Edit: April 12, 2026, 07:34:24 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Thaddy

  • Hero Member
  • *****
  • Posts: 19155
  • Glad to be alive.
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #12 on: April 12, 2026, 07:43:06 am »
Info, here's the solve table I fed to Claude:
Code: Text  [Select][+][-]
  1.   Handles:
  2.     for var <n> : <type> in <expr> do    -> for <n> in <expr> do   + var block entry
  3.     for var <n> in <expr> do             -> for <n> in <expr> do   + var block entry (inferred)
  4.     for var <n> : <type> := <lo> to <hi> -> for <n> := <lo> to <hi> + var block entry
  5.     var <n> : <type> := <expr>           -> <n> := <expr>           + var block entry
  6.     var <n> := <expr>                    -> <n> := <expr>           + var block entry (inferred)
There is only one(1) problem I can not solve and keeps a { TODO }.
All typed inline vars are already solved in this alpha version, though.
« Last Edit: April 12, 2026, 08:12:44 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

LeP

  • Sr. Member
  • ****
  • Posts: 304
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #13 on: April 12, 2026, 11:35:41 am »
Code: Pascal  [Select][+][-]
  1. begin
  2.   for var i in Something do
  3.     begin
  4.        // do something
  5.     end;
  6.   for var i in SomethingElse do
  7.     begin
  8.        // do something else
  9.     end;
  10. end;                  
  11.  
You code would not be valid Delphi, but: .............

This is a valid code (like I proposed) in Delphi 13.1 (see attach).

The issue is this: how to resolve the declaration of two different kind inline variables (with the same name) with one declaration in the method section ?
You have to change the code and substitute the variables.
I agree that this is the only way if you want to have compatibility with standard FPC syntax.
« Last Edit: April 12, 2026, 11:51:22 am by LeP »
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

LeP

  • Sr. Member
  • ****
  • Posts: 304
Re: Ann: Deinline: a de-inline-var-alyzer
« Reply #14 on: April 12, 2026, 12:14:31 pm »
Btw Just like LeP's code: a solid illustration of why inline vars are evil: the programmer him/herself can not even determine what was meant or how it works. And then imaginary features turn into real problems because things don't happen to fit expectations.

Who cannot determinate what it's doing ? The things are simple and clears, no doubts about that. But I accept of course that others cannot understand this ... so may be others are wrong, not me or the compiler for sure.
I don't know how the compiler (FPC, Delphi, etc....) works, and I don't mind. I use (and many others like me) simply the instruments that are available, of course trying to write more clear and comprensible code.

And for sure the code now is more comprensible, instead to have dozen of variables used only "temporary" (but globally inside the method) and declared many and many lines before.
Un Sistema per domarli, un IDE per trovarli, un codice per ghermirli e nel framework incatenarli.
An operating system to tame them, an IDE to find them, a code to catch them and in the framework chain them.

 

TinyPortal © 2005-2018