Recent

Author Topic: Why with allows assignment  (Read 39335 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 16516
  • Kallstadt seems a good place to evict Trump to.
Re: Why with allows assignment
« Reply #90 on: January 07, 2025, 11:42:53 am »
the "with" implementation in Delphi and FPC is an appalling atrocity, it is _irrelevant_ if that atrocity may be convenient to someone, it is wrong.  Just as wrong as the existence of writable constants.
There is one vaild use of with: to convert between an interface and its underlying class:
Code: Pascal  [Select][+][-]
  1. var Intf:IInterfaced;// this is from my interface tricks
  2. with Intf as TStringlist do begin
The alternative is writing things like
Code: Pascal  [Select][+][-]
  1. (intf as Tstringlist).Add('some string');
all the time.

Typed consts is just a misnomer, it could have been called static variable and static variables are very useful. Of course that should exist in one form or another.
« Last Edit: January 07, 2025, 12:02:48 pm by Thaddy »
But I am sure they don't want the Trumps back...

440bx

  • Hero Member
  • *****
  • Posts: 4981
Re: Why with allows assignment
« Reply #91 on: January 07, 2025, 01:32:40 pm »
Typed consts is just a misnomer, it could have been called static variable and static variables are very useful. Of course that should exist in one form or another.
Just a misnomer uh ?... it's totally fine to explain to someone (usually a programmer) that Pascal allows writing to constants... makes the language look so great.   Don't worry about it... just a "misnomer".

that FPC allows assigning a value to a function _outside_ the function itself, must be a "misnomer" too.

btw, there is no misnomer in typed constants, there is no reason why a constant couldn't be typed.  OTH, equating typed constants to writable constants is like equating a hammer to canine organic residue on a sidewalk... just a "misnomer", of course.  It must also be a misnomer that such variables are declared in a "const" section.   You're right... why would anyone have an issue with "writable constants" or assigning values to functions anywhere you want as long as you wrap it into a "with" statement... no problem!!!.  That's what computer science is all about... redefining logic and mathematics.

What really matters is that those things are convenient... that makes it right.  why don't other languages follow this "great" example ? particularly those that are standardized ?

I love Pascal, I wouldn't be here otherwise but, some of the things Borland and FPC have added to it are genuinely embarrassing.

Still, I'm very grateful FPC is available.  It would be really nice if some of the "misnomers" were removed from the language or, at least, be _rationally_ implemented (and some that need to be corrected but, that won't happen.)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

BrunoK

  • Hero Member
  • *****
  • Posts: 664
  • Retired programmer
Re: Why with allows assignment
« Reply #92 on: January 07, 2025, 01:57:40 pm »
I am not sure how you came to that conclusion Bruno. The first example I showed compiles and behaves exactly as I expect.
Code: Pascal  [Select][+][-]
  1.     if TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding = 0 then
  2.       TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding = 42;
Well, pussyfooting, how do I interpret ... Parastyle.LeftPadding = 42;
Quote
      
The second example, based on what Bart mentioned was a "proposal" would, IMHO be correct, would compile and would run as expected if it was implemented. Obviously, it has not been implemented so, bit hard to test right now.
   
Is problematic because as has the meaning of interpreting some field as a specific type (transtyping). Also in your example the aliased member is a property that has a getter and more specifically a setter which would require that the compiler does some implied macroing to reach the target of aliased variable.
Quote
@440bx, yes, same thing could be achieved with Macros but quite untidy code IMHO. In the case of my code, I have many identifiers similar to but usually slightly different, so, one macro would not suffice, multiple macros would start to look like C Code , yek !
 
Davo
Agree, as mentioned above, macro would loose the interest of the temporary scoped evaluation of the expression
Code: Pascal  [Select][+][-]
  1. with TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding
which reference is then used twice, once in the test and once in the assignment.

For aliasing, the following syntax could be interesting
with variable_ref [as type] [as alias] do ...
If something like that existed, instead of :
Code: Pascal  [Select][+][-]
  1.       lFI1 := TIntegerField(FieldByName('I1'));
  2.       lFI2 := TIntegerField(FieldByName('I2'));
  3.       for i := 0 to 9 do begin
  4.         Append;
  5.         lFI1.AsInteger := i;
  6.         lFI2.AsInteger := i;
  7.         Post;
  8.       end;
I could write :
Code: Pascal  [Select][+][-]
  1. with TIntegerField(FieldByName('I1')) alias FldI1,
  2.   TIntegerField(FieldByName('I2')) alias FldI2
  3. do begin
  4.   for i := 0 to 9 do begin
  5.     Append;
  6.     FldI1.AsInteger := i;
  7.     FldI2.AsInteger := i;
  8.     Post;
  9.   end;
  10. end;
  11.  
In case of table loops, resolving the extraction of field using FieldByName before the iterative loop is a very big speed winner when the number of iterations is high. But the lengthy writing / declaring temp variables as done in the non-aliased code above is acceptable.

simone

  • Hero Member
  • *****
  • Posts: 648
Re: Why with allows assignment
« Reply #93 on: January 07, 2025, 02:01:28 pm »
I love Pascal, I wouldn't be here otherwise but, some of the things Borland and FPC have added to it are genuinely embarrassing.

Still, I'm very grateful FPC is available.  It would be really nice if some of the "misnomers" were removed from the language or, at least, be _rationally_ implemented (and some that need to be corrected but, that won't happen.)

A "strict" mode could be introduced, in order to not allow some questionable features (to be diplomatic) and, at the same time, ensure backwards compatibility.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

440bx

  • Hero Member
  • *****
  • Posts: 4981
Re: Why with allows assignment
« Reply #94 on: January 07, 2025, 02:04:27 pm »
A "strict" mode could be introduced, in order to not allow some questionable features (to be diplomatic) and, at the same time, ensure backwards compatibility.
I like the suggestion, it sounds very reasonable to me but, to my chagrin, I don't think the developers are interested in such a mode.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

LV

  • Full Member
  • ***
  • Posts: 204
Re: Why with allows assignment
« Reply #95 on: January 07, 2025, 02:14:28 pm »
There is such a trick in Rust.
"
Unsafe Rust
All the code we’ve discussed so far has had Rust’s memory safety guarantees enforced at compile time. However, Rust has a second language hidden inside it that doesn’t enforce these memory safety guarantees: it’s called unsafe Rust and works just like regular Rust, but gives us extra superpowers.
"

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Why with allows assignment
« Reply #96 on: January 07, 2025, 03:01:29 pm »
I couldn't care less how FPC implements its scope resolution mechanism but that comment proves that you know less about compiler construction than the Pope knows about quantum mechanics.  Locals and parameters are in the same scope which is why locals cannot have the same name as parameters because that would cause a duplicate identifier.
I have worked with multiple compilers, amongst others clang, which I hope you agree is a mainstream compiler. I have never seen the parameter list not being in their own scope, even though it may not be semantically accessible in the language.

For example, while the following does not work right now in fpc:
Code: Pascal  [Select][+][-]
  1. procedure foo(i: Integer);
  2. var j: Integer = i;
  3. begin
  4.  
  5. end;
Because i and j are in different scopes, there is no semantic reason for it not to work. It's mainly that the way the FPC variable initialization is currently implemented it can only read constants directly written into the assembly.
But other languages allow exactly that.

Even FPC will tell you there is a duplicate identifier thereby conclusively proving the parameter and the local are in the same scope.
Do you know where FPC also complains with the exact same error message?
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$ModeSwitch advancedrecords}
  3. type
  4.   TTest = record
  5.     i: Integer;
  6.     procedure Foo(i: Integer);
  7.   end;
And I hope we both agree that these two i's are not in the same scope right?

As I suggested in the previous post, you need to read a few books about compiler construction.
I've taken multiple courses in Uni about compiler construction, read multiple books and papers about compiler construction, I've build my own Regex and LALR table generator, I've worked on the source code of multiple compilers including clang.
I regularly create small scripting languages to be used within my programs.

I'm by no means an expert on all areas of compiler construction, infact I rarely work on the backend side but usually do frontend work (i.e. lexing, parsing and AST construction/modification), but I certainly know more than enough about these topics for this discussion here.

Again you didn't know that shadowing is a commonly used term. About mainstream compilers, all common C compilers, gcc, clang, MSVC++ use the term. The Glasgow Haskell Compiler uses the term, the Python Documentation and linters use the term, the OpenJDK Documentation usese the term. Like I do not know how you can use any currently popular programming language and never encounter this term

Honestly I feel that your knowledge on the topic is just severly out of date, because I do not know a single language system (at least one conceived in the past 25 years) which does not use the term.

You tell me to read books, but be honest, have you read anything that came out in the past 10 years on the topic? Knowedge is not something you acquire once, especially in a field like computer science, which is a very young science, it's constantly evolving, to be knowlegable on a topic requires to keep up with the modern developments.
A language like Rust and the Rust compiler could not have existed 20 years ago, because the relevant research in Constraint Satisfaction Theories has just been discovered during the past 15 years. I know that, because I was a student of one of the Professors who did some of the most important discoveries in that area, at that time
Also over the past 10-20 thanks to the widespread access to well versioned and documented open source software, we are now finally able to have meta analysis on language features and how they impact programming behavior, alowing to analyze scientifically what patterns and development paradigms produce more or less bugs, are better maintainable, etc.
Those are things that 20 years ago were simply not possible. If you do not refresh your knowledge but only rely on the books on compiler theory from Wirth or Hoare from the 60s and 70s, while they are a very excellent introduction to the topic, they are just that, the very basics. Today the field is so much bigger, with so much more stuff to know and learn about...

I don't doubt that you once were a great programmer, but from how and what you write, not just here, it feels like your knowledge is stuck in the 80s and 90s, and you still rely on that knowledge alone, ignoring the past 20-30 years of development in the field

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Why with allows assignment
« Reply #97 on: January 07, 2025, 03:12:13 pm »
Agree, as mentioned above, macro would loose the interest of the temporary scoped evaluation of the expression
Code: Pascal  [Select][+][-]
  1. with TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding
which reference is then used twice, once in the test and once in the assignment.

For aliasing, the following syntax could be interesting
with variable_ref [as type] [as alias] do ...
If something like that existed, instead of :
Code: Pascal  [Select][+][-]
  1.       lFI1 := TIntegerField(FieldByName('I1'));
  2.       lFI2 := TIntegerField(FieldByName('I2'));
  3.       for i := 0 to 9 do begin
  4.         Append;
  5.         lFI1.AsInteger := i;
  6.         lFI2.AsInteger := i;
  7.         Post;
  8.       end;
I could write :
Code: Pascal  [Select][+][-]
  1. with TIntegerField(FieldByName('I1')) alias FldI1,
  2.   TIntegerField(FieldByName('I2')) alias FldI2
  3. do begin
  4.   for i := 0 to 9 do begin
  5.     Append;
  6.     FldI1.AsInteger := i;
  7.     FldI2.AsInteger := i;
  8.     Post;
  9.   end;
  10. end;
  11.  
In case of table loops, resolving the extraction of field using FieldByName before the iterative loop is a very big speed winner when the number of iterations is high. But the lengthy writing / declaring temp variables as done in the non-aliased code above is acceptable.

If you want to give it a try, check out this branch: https://gitlab.com/freepascal.org/fpc/source/-/merge_requests/860

Where I built exactly that, if you could test it and give recommendations, report bugs, etc. in that MR I would be very greatful :)

A "strict" mode could be introduced, in order to not allow some questionable features (to be diplomatic) and, at the same time, ensure backwards compatibility.
Thats what modeswitches are for. To change language behavior which is not backwards compatible. BUUUUT the problem with the FPC developers, which you can probably understand partly if you look at the code base, is more of the ever increasing complexity of the fpc source code. For example, take a look at this: https://gitlab.com/freepascal.org/fpc/source/-/blob/main/compiler/pexpr.pas#L373
Because in MacPas, you can use "leave" instead of "break" and "cycle" instead of continue, the FPC needs to basically double the code for continue and break just for that one mode pretty much no one is actively using

440bx

  • Hero Member
  • *****
  • Posts: 4981
Re: Why with allows assignment
« Reply #98 on: January 07, 2025, 04:28:22 pm »
For example, while the following does not work right now in fpc:
Code: Pascal  [Select][+][-]
  1. procedure foo(i: Integer);
  2. var j: Integer = i;
  3. begin
  4.  
  5. end;
Because i and j are in different scopes,
No, they are not in different scopes.  They are in the same scope.  However a compiler decides to implement its scopes and how it keeps track of what is in one scope or another is one thing but, the parameters and the locals are in the same scope otherwise you'd have to have a scope identifier to refer to the parameters.

Here is _your_ own code:
Code: Pascal  [Select][+][-]
  1.  procedure foo(x: Integer);
  2. var
  3.   x: Double;
  4. begin
  5. end;
IF, as you (erroneously) claim, the parameter "x" and the variable "x" are in different scopes then, please, explain why the compiler emits an error stating there is a "duplicate identifier".  If those identifiers are not in the same scope then they are not duplicates.  You got some explaining to do.

there is no semantic reason for it not to work.
Yes, that's true.

It's mainly that the way the FPC variable initialization is currently implemented it can only read constants directly written into the assembly.
No, it's because FPC does not automatically generate code to initialize one variable with the value of another or the value of a function (which C supports.)

But other languages allow exactly that.
You're mixing Apples and Mars rovers.

I've taken multiple courses in Uni about compiler construction, read multiple books and papers about compiler construction,
I find that very difficult to believe given that you have demonstrated having no grasp whatsoever of some of the most _basic_ concepts of compilers.  What scope things are in is one of the most basic things there is and, btw, what is/belongs in one scope or another is independent of implementation.  I don't care if you've read clang source or anything else.  It has nothing to do with it.

Again you didn't know that shadowing is a commonly used term. About mainstream compilers, all common C compilers, gcc, clang, MSVC++ use the term.
You can claim it's common all you want BUT, MSVC++ emits a message about a variable masking another one, not shadowing it.  I don't recall what gcc emits and I simply don't know (and don't care) what clang emits.

But, you know what, if it makes you feel good that I was unaware of the term "shadowing", you're right.  feel better now ?  The only compiler construction book I keep at hand at all times is "Per Brinch Hansen On Pascal Compilers" and that one doesn't mention shadowing (at least not that I remember and, I've read that book multiple times... but, I could still be wrong.)  (that book and Sedgewick's Algorithms are the two books that are always on my desk which made me realize just now that Sedgewick's book is not where it's supposed to be... )

Honestly I feel that your knowledge on the topic is just severly out of date, because I do not know a single language system (at least one conceived in the past 25 years) which does not use the term.
My knowledge isn't out of date but my terminology might be.  It also looks like correctness is "out of date" (trivial things like not allowing a function to have values assigned outside the function... things like that.)

You tell me to read books, but be honest, have you read anything that came out in the past 10 years on the topic?
Yes, I have.  The last book I read on compilers is "Engineering a compiler by Cooper and Torczon, 2nd edition" which was published in 2012.   It refers to shadowing when the compiler generates a hidden variable to control iterations in loops. I didn't find an instance where the term is used when one user defined variable mask another user define variable or parameter but, I could have missed it (though, the search function didn't reveal an instance of that.)

but only rely on the books on compiler theory from Wirth or Hoare from the 60s and 70s, while they are a very excellent introduction to the topic, they are just that, the very basics.
The foundations have not changed much (unfortunately.)

When it comes to scanning and parsing, very little has changed in the last 60 or so years.  There have been improvements but nothing that is a game changer.  Moreover, some of the "improvements" have resulted in poorer language quality ("creative" compilers...)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

BrunoK

  • Hero Member
  • *****
  • Posts: 664
  • Retired programmer
Re: Why with allows assignment
« Reply #99 on: January 07, 2025, 04:53:56 pm »
that FPC allows assigning a value to a function _outside_ the function itself, must be a "misnomer" too.
if you mean the OP program (revised) :
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. const
  4.   HighInt64 = int64(int64(-1) shr 1); // Typed const
  5.  
  6. type
  7.   TTest = record
  8.     V: int64;
  9.   end;
  10.  
  11. var
  12.   X: TTest;
  13.  
  14.   function Test: TTest;
  15.   begin
  16.     Result := X;
  17.   end;
  18.  
  19. var
  20.   i: qword;
  21. begin
  22.   with Test do begin
  23.     V := HighInt64; //No Error
  24.     WriteLn(X.V, ' ', {With Test.}V);
  25.   end;
  26.   Readln;
  27. end.
There is no assignment of a function outside it. The assignment is to the temporary TTest record returned by the Test function call. As my little snippet of code shows, the X.V record field is not changed, only the returned temporary record is altered to HighInt64.

440bx

  • Hero Member
  • *****
  • Posts: 4981
Re: Why with allows assignment
« Reply #100 on: January 07, 2025, 05:14:58 pm »
that FPC allows assigning a value to a function _outside_ the function itself, must be a "misnomer" too.
if you mean the OP program (revised) :
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. const
  4.   HighInt64 = int64(int64(-1) shr 1); // Typed const
  5.  
  6. type
  7.   TTest = record
  8.     V: int64;
  9.   end;
  10.  
  11. var
  12.   X: TTest;
  13.  
  14.   function Test: TTest;
  15.   begin
  16.     Result := X;
  17.   end;
  18.  
  19. var
  20.   i: qword;
  21. begin
  22.   with Test do begin
  23.     V := HighInt64; //No Error
  24.     WriteLn(X.V, ' ', {With Test.}V);
  25.   end;
  26.   Readln;
  27. end.
There is no assignment of a function outside it. The assignment is to the temporary TTest record returned by the Test function call. As my little snippet of code shows, the X.V record field is not changed, only the returned temporary record is altered to HighInt64.
Wrong and unacceptable!  The temporary represents the result of the function therefore it must be treated exactly the same as the result of the function.

The _correct_ way to do what that code atrocity above is doing is to assign the function result to a variable and then change the variable but, of course, that's too much work and worse, it is correct, we can't possibly have that.  In the code you present, V represents the result of the function therefore it MUST be treated as the function's result.

Assign a value to function results outside the function ?... no problem... assign values to constants ?... no problem...   it's all great as long as it's convenient... that's what really matters... correctness ?.... nah... who could possibly need that ?  (just in case, rhetorical.)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 16516
  • Kallstadt seems a good place to evict Trump to.
Re: Why with allows assignment
« Reply #101 on: January 07, 2025, 05:19:40 pm »
BrunoK and me (very early in this discussion) already pointed out you are barking up the wrong tree. The last contribution of Bruno is exactly the same as I wrote earlier.
We both disagree with you and we think you are wrong, with both the same reasoning.

Of course, with without context is a very bad idea, but there are other scenario's that warrant its use.
Same with your adversity to typed consts, which are simply static variables.
« Last Edit: January 07, 2025, 05:21:29 pm by Thaddy »
But I am sure they don't want the Trumps back...

BrunoK

  • Hero Member
  • *****
  • Posts: 664
  • Retired programmer
Re: Why with allows assignment
« Reply #102 on: January 07, 2025, 05:19:49 pm »
Functions returning a record do actually cause a copy of the result record to the result field, in this case the with Test temporary scoped variable.
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. const
  4.   HighInt64 = int64(int64(-1) shr 1); // Typed const
  5.  
  6. type
  7.   TTest = record
  8.     V: int64;
  9.   end;
  10.  
  11. var
  12.   X: TTest;
  13.  
  14.   function Test: TTest;
  15.   begin
  16.     Result := X;
  17.   end;
  18.  
  19. var
  20.   i: qword;
  21. begin
  22.   with Test do begin
  23.     WriteLn(X.V, ' ', {With Test.}V);
  24.     V := HighInt64; //No Error
  25.     WriteLn(X.V, ' ', {With Test.}V);
  26.   end;
  27.   Readln;
  28. end.

Thaddy

  • Hero Member
  • *****
  • Posts: 16516
  • Kallstadt seems a good place to evict Trump to.
Re: Why with allows assignment
« Reply #103 on: January 07, 2025, 05:22:13 pm »
Yes, with opens a block.
But I am sure they don't want the Trumps back...

440bx

  • Hero Member
  • *****
  • Posts: 4981
Re: Why with allows assignment
« Reply #104 on: January 07, 2025, 05:33:17 pm »
Functions returning a record do actually cause a copy of the result record to the result field, in this case the with Test temporary scoped variable.
The automatic creation of a temporary in the "with" turns the "with" statement into a hidden assignment statement.  The "with" statement is NOT an assignment statement.  It is a scope declaration statement.

god forbid we "force" programmers to assign the result of a function to a variable.  It's so much "easier" to create a hidden variable that represents the result and violate every principle of programming by allowing a value to be assigned to the functions' result outside the function.  Convenience over correctness... that's the way to go.

One thing is for sure, nothing I say is going to make any difference.  It isn't the only thing FPC does wrong that has survived correctness.  In favor of FPC, it must be mentioned that this atrocity was initiated by Delphi, that's the real culprit and compatibility leaves little choice.

Worse thing that has happened to Pascal is the absence of an evolving standard.  That absence is what allows this kind of stuff.  "Convenience Design".
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018