Recent

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

LV

  • Full Member
  • ***
  • Posts: 206
Re: Why with allows assignment
« Reply #120 on: January 08, 2025, 10:16:11 am »
I reread the documentation https://www.freepascal.org/docs-html/ref/refsu62.html
and made an example according to this documentation.
I don't see any errors.  :-[

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. type
  4.   TTest = record
  5.     V: integer;
  6.   end;
  7.   TP = ^TTest;
  8.  
  9. var
  10.   X, Y: TTest;
  11.  
  12.   function Test: TP;
  13.   begin
  14.     Result := @X;
  15.   end;
  16.  
  17.   function Test2: TP;
  18.   begin
  19.     Result := @Y;
  20.   end;
  21.  
  22. begin
  23.  
  24.   WriteLn('X.V = ', X.V);
  25.   WriteLn('Y.V = ', Y.V);
  26.   WriteLn('with Test^, Test2^');
  27.  
  28.   with Test^, Test2^ do
  29.   begin
  30.     V := 1;
  31.     WriteLn('X.V = ', X.V);
  32.     WriteLn('Y.V = ', Y.V);
  33.   end;
  34.   WriteLn('X.V = ', Test^.V);
  35.   WriteLn('Y.V = ', Test2^.V);
  36.   WriteLn('with Test2^, Test^');
  37.  
  38.   with Test2^, Test^ do
  39.   begin
  40.     V := 2;
  41.     WriteLn('X.V = ', X.V);
  42.     WriteLn('Y.V = ', Y.V);
  43.   end;
  44.   WriteLn('X.V = ', Test^.V);
  45.   WriteLn('Y.V = ', Test2^.V);
  46.   WriteLn('with Test^, Test2^ and Test^ := Test2^');
  47.  
  48.   with Test^, Test2^ do
  49.   begin
  50.     V := 3;
  51.     Test^ := Test2^;
  52.     WriteLn('X.V = ', X.V);
  53.     WriteLn('Y.V = ', Y.V);
  54.   end;
  55.   WriteLn('X.V = ', Test^.V);
  56.   WriteLn('Y.V = ', Test2^.V);
  57.   WriteLn('with Test2^, Test^ and Test2^ := Test^');
  58.  
  59.   with Test2^, Test^ do
  60.   begin
  61.     V := 4;
  62.     Test2^ := Test^;
  63.     WriteLn('X.V = ', X.V);
  64.     WriteLn('Y.V = ', Y.V);
  65.   end;
  66.   WriteLn('X.V = ', Test^.V);
  67.   WriteLn('Y.V = ', Test2^.V);
  68.   WriteLn('Test^.V := 5; Test2^.V := 6;');
  69.  
  70.   Test^.V := 5;
  71.   Test2^.V := 6;
  72.  
  73.  
  74.   WriteLn('X.V = ', X.V);
  75.   WriteLn('Y.V = ', Y.V);
  76.  
  77.   readln;
  78. end.    
  79.  

Output:
Code: Text  [Select][+][-]
  1. X.V = 0
  2. Y.V = 0
  3. with Test^, Test2^
  4. X.V = 0
  5. Y.V = 1
  6. X.V = 0
  7. Y.V = 1
  8. with Test2^, Test^
  9. X.V = 2
  10. Y.V = 1
  11. X.V = 2
  12. Y.V = 1
  13. with Test^, Test2^ and Test^ := Test2^
  14. X.V = 3
  15. Y.V = 3
  16. X.V = 3
  17. Y.V = 3
  18. with Test2^, Test^ and Test2^ := Test^
  19. X.V = 4
  20. Y.V = 4
  21. X.V = 4
  22. Y.V = 4
  23. Test^.V := 5; Test2^.V := 6;
  24. X.V = 5
  25. Y.V = 6
  26.  

TRon

  • Hero Member
  • *****
  • Posts: 3936
Re: Why with allows assignment
« Reply #121 on: January 08, 2025, 11:05:17 am »
I don't see any errors.  :-[
It is not the same situation as used by TS.

Returning pointers allow for manipulating the record-fields. It is not a copy (anymore).
I do not have to remember anything anymore thanks to total-recall.

LV

  • Full Member
  • ***
  • Posts: 206
Re: Why with allows assignment
« Reply #122 on: January 08, 2025, 11:11:48 am »
It is not the same situation as used by TS.

Where is this situation in the documentation?

TRon

  • Hero Member
  • *****
  • Posts: 3936
Re: Why with allows assignment
« Reply #123 on: January 08, 2025, 11:24:05 am »
Where is this situation in the documentation?
afaik it currently isn't described.

However, I seem to remember that when the with behaviour changed It was mentioned in the release notes (But I have no idea what release version that was).
« Last Edit: January 08, 2025, 11:38:50 am by TRon »
I do not have to remember anything anymore thanks to total-recall.

LV

  • Full Member
  • ***
  • Posts: 206
Re: Why with allows assignment
« Reply #124 on: January 08, 2025, 11:34:57 am »
I see, we are talking about undocumented experiments. Thanks for the clarification.

TRon

  • Hero Member
  • *****
  • Posts: 3936
Re: Why with allows assignment
« Reply #125 on: January 08, 2025, 11:41:50 am »
I see, we are talking about undocumented experiments. Thanks for the clarification.
No, it is not exactly an undocumented experiment. This way of manipulating record fields exist since the existence of the with statement and the way that was shown by TS did work as expected at one time in history. The behaviour was changed because the old hehaviour was unsustainable. Delphi changed it so FPC followed.

That this situation is not explicitly mentioned in the documentation does not by default mean it is an experiment. If that would to be the case then around 50% of my current used code-base would be an experiment (which it isn't). Same would be true for the compiler itself, all the tools, Lazarus and the LCL as you currently know them.
« Last Edit: January 08, 2025, 11:48:54 am by TRon »
I do not have to remember anything anymore thanks to total-recall.

LV

  • Full Member
  • ***
  • Posts: 206
Re: Why with allows assignment
« Reply #126 on: January 08, 2025, 11:59:30 am »
Thank you. I have to be careful about this. Speaking of Delphi https://blogs.embarcadero.com/delphi-with-statements-and-local-variables/
« Last Edit: January 08, 2025, 12:03:43 pm by LV »

TRon

  • Hero Member
  • *****
  • Posts: 3936
Re: Why with allows assignment
« Reply #127 on: January 08, 2025, 12:13:54 pm »
Yes, I am aware of marco's blogposts and view on this particular matter but I do thank you for the reminder/link.

I simply do not understand what the fuzz is about. Once it worked, behaviour changed, now it behaves differently. Burned once, burned twice, then never again.

That the compiler is (currently) unable to detect the wrong usage as in TS' example and not warn about it is another matter (there are plenty of other unwanted situations 
that the compiler does not complain/warn about).

I would say: file a report that the compiler is not able to detect the wrong access of the record field(s) and wait for it to be fixed (or fix yourself in case it is upsetting) and be done with it.

It seems that every such situation lately is discussed over and over again while wasting all that time could imho have been better spend. But, that is probably just me.
I do not have to remember anything anymore thanks to total-recall.

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Why with allows assignment
« Reply #128 on: January 08, 2025, 02:47:14 pm »
Nobody should take my word for it, instead read the chapter on scopes in Per Brinch Hansen's book which you can find at:
http://pascal.hansotten.com/uploads/pbh/brinch%20hansen%20on%20pascal%20compilers%20OCR.pdf

The chapter starts at page 95 (book page number) or page 105 (online pdf reader page number)

Specifically, read section "6.3 COMPILATION METHOD" and pay particular attention to Figure 1's first column which clearly shows that parameters, local variables, types and constants are all in the same scope _within_ a procedure or function.  These are pages 110 & 111 (online pdf reader page numbers.)

You actually for the first time in this thread provided some evidence on your own... I'm proud of you. I mean you still did not provide a definition for scope, infact the section you've referenced specifically talks about how you can implement scoping by a stack of symbols...
But wait a minute, haven't you argued that I shouldn't bring up a specific implementation, now you do the exact same. You literally just do the same thing you said was wrong when I did it. You bring up a specific way of implementing a compiler as proof on how scopes should work.
With the small difference that I brought up the implementation in the FPC the compiler for the language this discussion is about, while you bring up the work of a guy who built a pascal compiler 40 years ago that no one is using anymore.

Do you really think that the way Brinch Hansen implemented a pascal compiler nearly half a decade ago is more of an authority on modern day pascal than than the way modern pascal compilers are implemented today?



But because I am a pedant, let's look further in that book, because there is the section "Scoping Rules" which contains a sentence thats most closely to a definition for a scope:
Quote
To make this idea precise we need a set of rules that enable a programmer (and a compiler!) to associate every occurrence of a name with a definition of the corresponding object.
So a scope is some concept that allows for the resolution of names according to a certain set of rules. This is actually the same definition that clang uses, so it's not just some weird thing in a book from the 80s, but something that is acutally used by real world compilers.

So if two objects resolve names differently, they are in different scopes. There are two ways to interpret this, either pedantically, so as soon as there is any discrepency between name resolution of two objects they are in a different scope, e.g.:
Code: Pascal  [Select][+][-]
  1. procedure foo(x: Integer);
  2. var
  3.   y: Integer = sizeof(x);
  4. begin end;
This works fine, but the following doesn't:
Code: Pascal  [Select][+][-]
  1. procedure foo(x: Integer = SizeOf(y));
  2. var
  3.   y: Integer;
  4. begin end;
So x and y clearly have different rules for resolving the name, because y can reference x but x can't reference y. While this would be from a formal point of view probably be the best interpretation, as this allows for formal verification over properties. This hase the side effect that any identifier introduces a new scope:
Code: Pascal  [Select][+][-]
  1. var
  2.   x: Integer;
  3.   y: Integer = sizeof(x);
  4.   z: Integer = sizeof(y);
From a strictly formal perspective x creates a new scope for all following definitions such that x can be used. Same for y and z. So if my goal is to write a formal definition of the Pascal semantic, this would be the way to go.

Now I know why you didn't go with that definition, because this while being very formal, is not very useful in practice when building a compiler (because here you can enforce the scoping rules through the order of parsing the code top to bottom). That said it's great that your own source says that you are wrong :)



And lastly, because you bring that very bad argument up again and again not realizing how it makes you look stupid:

For the record, in the following code:
Code: Pascal  [Select][+][-]
  1.  procedure foo(x: Integer);
  2. var
  3.   x: Double;
  4. begin
  5. end;
the parameter "x" and local variable "x" are in the same scope which is the reason any Pascal compiler, including FPC, will declare there is a duplicate identifier.  This is rather simple stuff, no rocket science here.

[...]


Now, let's give the obvious answer: the reason FPC emits a "duplicate identifier" error message is because the parameter and the local variable are in the same scope.  It's that simple.  Period.
Again this argument is just fallacious. Your argument is formalized:
1. If two objects in the same scope have the same name, they will cause a duplicate identifier error
2. the parameter and variable in this example cause a duplicate identifier error
3. Therefore these two objects are in the same scope.

But 3 does not follow from 1 and 2, because this is just an implication not an equivalence. If two objects are in the same scope they get a duplicate identifier. But this does not mean that if you get duplicate identifier they are in the same scope. To prove that this argument is fallacious a simple proof by contradiction is enough, in that I just need to find a single example where I get the same error but the two variables are not in the same scope:
Code: Pascal  [Select][+][-]
  1. type
  2.   TTest = object
  3.     i: Integer;
  4.     procedure foo(i: Integer);
  5.   end;
Here the parameter i and the object field i are not in the same scope, the parameter is in the scope of the function definition and the field is in the scope of the object. Still there is a duplicate identifier. Therefore you're argumentation is wrong. Just flat out provably wrong.

Yeah and you are right, it's not rocket science, it's a logical fallacy you are proposing here. I know implication vs equivalence is something many first semester students struggle with, so I don't feel to bad about missing this part
« Last Edit: January 08, 2025, 02:56:49 pm by Warfley »

440bx

  • Hero Member
  • *****
  • Posts: 4993
Re: Why with allows assignment
« Reply #129 on: January 08, 2025, 02:56:04 pm »
What I had to say, I said in my previous post and I stand by every word in it.

Do the world a favor, stop posting your garbage.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Why with allows assignment
« Reply #130 on: January 08, 2025, 02:57:44 pm »
What I had to say, I said in my previous post and I stand by every word in it.

Do the world a favor, stop posting your garbage.

Of course you do, you never accept any evidence that goes against your believes, you never do.

One last thing: you like to talk about books, but people who write books are usually not the people who maintain compilers. Brinch Hansen is a great example, he was a professor, a researcher. Sure he worked on a  few compilers in his time, but compilers weren't even his main work.
But also then very little people who do research on compilers acutally write compilers used in the real world. Look at Wirth, he pumped out programming languages with reference compilers like no one else. Yet any of his languages only found actual use after others picked up the work and built their own compilers updating the languages and compilers to be more align with the needs real programmers face in the real world.

Books are great to get an insight into how compilers work. But if you want to learn really how compilers operate, you need to look at the actual compilers in the field. And the great thing is, today most languages and compilers are open source. You want to look how a C compiler works, go and look at the clang or g++ source. You want to know how a Pascal compiler operates, go and look at the FPC sources.

A person who only has their knowledge from books can never really know how things work practically. So maybe instead of reading 40 year old books over and over again, go and crack open some actual compilers and start working with them... Then you may get some actual knowledge about compiler construction.

440bx

  • Hero Member
  • *****
  • Posts: 4993
Re: Why with allows assignment
« Reply #131 on: January 08, 2025, 02:59:05 pm »
Re-read my previous post as many times as necessary.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Why with allows assignment
« Reply #132 on: January 08, 2025, 03:01:46 pm »
Re-read my previous post as many times as necessary.

Do you really believe your logical fallacies of not knowing the difference between implication and equivalence get less wrong when I read them again?

Like all claims you made were provably wrong

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Why with allows assignment
« Reply #133 on: January 08, 2025, 03:16:22 pm »
Infact, let me make a list of things you claimed in this thread that were provably wrong:
1. That with is writable is a bug:
Provably wrong as you can see by the comments in the code it's intended behavior
2. With doesn't create a temporary object
Provably wrong with the fpc code creating a tempnode
3. it's not with that creates a temporary variable for the function result
Provably wrong from the fpc source
4. Every function call creates a tempnode it just happens that this is in with
Provably wrong as you don't understand the difference between the node tree and the assembly (btw. great look on your knowledge about compiler construction if you don't even know what an AST is)
5. Saying shadowing isn't a real term used
Provably wrong by it having even it's own wikipedia page
6. Saying no major compiler is using the term shadowing
Provably wrong by at least 5 major compilers I've found in 10 minutes using that term
7. With changes the return value of a function
Provably wrong, it changes a local copy of the return value of a function
8. The ide that "duplicate identifier" error only occurs when two identifiers are in the same scope
Provably wrong by counter example
9. The whole discussion on scope
Provably wrong by your own source

Even if you don't concede the last one, all of the ones above were just plainly and provably wrong claims by you about the function of the FPC compiler, the use of the term shadowing, the implementation of with, etc. Pretty much every single post of you at least in the first half of this thread contained at least one provably wrong statement.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10794
  • Debugger - SynEdit - and more
    • wiki
Re: Why with allows assignment
« Reply #134 on: January 08, 2025, 03:52:28 pm »
2. With doesn't create a temporary object
Provably wrong with the fpc code creating a tempnode

Now I am intrigued. Is that so? (And I don't actually know, so that is an open question).
But, I suspect it may not... Yet, it may even depend on some unclear parts in that statement.


First of all, it should be easy for you to show, that this is the case with the FPC compiler (at a version of your choice, with settings of your choice).
- Provide the Pascal code for which this happens
- Provide the fpc version and command line args
- Provide the generate asm with register allocation  -alr



Anyway, before you do, lets talk about what constitutes "WITH creates a temp var" => How to we determine that the temp var (if there is one) was created by WITH?

Let me explain in an example:
Code: Pascal  [Select][+][-]
  1. function Foo: record_or_classInstance;

If you call
Code: Pascal  [Select][+][-]
  1. MyVar := Foo;
then there may or may not be a temp var. If there is, then we would say that for such a case the temp var is created for the call to foo, and when doing "with Foo do" such a temp var would still be for the call, and not for the "with". Agreed?

But then
Code: Pascal  [Select][+][-]
  1. Foo().b := 1; {or} if foo().b = 1 then

There is no "with" but if that creates a temp var, then that means a temp var was created for operating on the result of the call to foo.
From that again we should IMHO then say that "with foo do" is just operating on the result, and that therefore it is not the "with" but the  for operating on the result that creates the temp var. Still agreed?

If not agreed, then include an explanation as to why not.

Then based on that, show the code as asked above. Thanks.


---
Also, a register (from which a value is used) is as much a temp var, as a slot allocated on the stack. The diff is a matter of optimization. Both are a place of storage for the value.
« Last Edit: January 08, 2025, 03:54:08 pm by Martin_fr »

 

TinyPortal © 2005-2018