Recent

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

flowCRANE

  • Hero Member
  • *****
  • Posts: 911
Re: Why with allows assignment
« Reply #45 on: January 04, 2025, 03:03:00 am »
This thread is funny. The temporary object is allocated, which is clearly indicated in the compiler sources, many of us have already used it in our programs, and yet I see denial and claim that it is a bug. What you are writing about is not a bug, but "bs".

I've used a with block to create an instance of a class that would do a few things and then be destroyed. Like this:

Code: Pascal  [Select][+][-]
  1. with TSomeClass.Create(nil) do
  2. try
  3.   DoThis();
  4.   DoThat();
  5. finally
  6.   Free();
  7. end;

This is convenient because there is no need to declare an additional local variable since the compiler allocates it automatically. So I suggest stop talking nonsense and don't call something a bug that is not only implemented on purpose, but also useful in practice.

Peace.
« Last Edit: January 04, 2025, 03:04:42 am by flowCRANE »
Lazarus 3.6 with FPC 3.2.2, Windows 10 — all 64-bit

Working solo on a retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

simone

  • Hero Member
  • *****
  • Posts: 648
Re: Why with allows assignment
« Reply #46 on: January 04, 2025, 10:53:13 am »
This thread is very interesting and clarifies some points for me. I have always interpreted the meaning of the with statement as 440bx does. I think in principle, he is right.

Given my interpretation, I have always wondered why this code (stylistically very questionable) works:

Code: Pascal  [Select][+][-]
  1. with TSomeClass.Create do
  2.   begin
  3.     Mehod1OfTSomeClass;
  4.     Mehod2OfTSomeClass;
  5.     Free;
  6.   end;

I was also amazed to see these results:

Code: Pascal  [Select][+][-]
  1. program test;
  2. uses classes;
  3. begin
  4.   with TObject.Create do
  5.      writeln(GetHashCode);
  6.   with TObject.Create do
  7.      writeln(GetHashCode);
  8.      
  9.   writeln;
  10.  
  11.   with TObject.Create do
  12.     begin
  13.       writeln(GetHashCode);
  14.       writeln(GetHashCode);
  15.     end;
  16.  
  17.   readln;
  18.  end.
  19.  

Output:
22443709157664
22443709157696

22443709157728
22443709157728


The implicit creation of a temporary object, clarified by Warfley, justifies this behavior. I think this is implementation dependent and not correct according to the original language specification. It is not officially documented anywhere. However, like other long-standing deviations, the problem is not solvable, because it would break backwards compatibility.
« Last Edit: January 04, 2025, 12:14:59 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Warfley

  • Hero Member
  • *****
  • Posts: 1870
Re: Why with allows assignment
« Reply #47 on: January 04, 2025, 12:35:19 pm »
The implicit creation of a temporary object, clarified by Warfley, justifies this behavior. I think this is implementation dependent and not correct according to the original language specification. It is not officially documented anywhere. However, like other long-standing deviations, the problem is not solvable, because it would break backwards compatibility.

What original language specification? Originally the with statement was only allowed over variables and constants not over return values of functions. But also, original Pascal didn't have units, bit operations and many other stuff.
We are programming in Free Pascal, which is its own version of Pascal with its own Syntax and semantics. If you want to program in ISO or ExtPas, you can do that, you can even do that to some degree with the FPC (but it's not fully compatible), but then you are programming in a different programming language than the rest of us

VisualLab

  • Hero Member
  • *****
  • Posts: 639
Re: Why with allows assignment
« Reply #48 on: January 04, 2025, 12:53:30 pm »
This thread is funny. The temporary object is allocated, which is clearly indicated in the compiler sources, many of us have already used it in our programs, and yet I see denial and claim that it is a bug. What you are writing about is not a bug, but "bs".

I don't see anything funny about it. The argument is between: readability + clarity of the language and a quirk present in the compiler.

I've used a with block to create an instance of a class that would do a few things and then be destroyed. Like this:

Code: Pascal  [Select][+][-]
  1. with TSomeClass.Create(nil) do
  2. try
  3.   DoThis();
  4.   DoThat();
  5. finally
  6.   Free();
  7. end;

This is convenient because there is no need to declare an additional local variable since the compiler allocates it automatically. So I suggest stop talking nonsense and don't call something a bug that is not only implemented on purpose, but also useful in practice.

I understand that for some people it is probably convenient. But at the same time it is quite unreadable and weird. Relying on oddities is not a good idea (see: C). The more such "functionalities" in a language, the more confusing and inconsistent it is. The variable will be created anyway, so what's the problem with declaring it explicitly?

Warfley

  • Hero Member
  • *****
  • Posts: 1870
Re: Why with allows assignment
« Reply #49 on: January 04, 2025, 01:02:36 pm »
I understand that for some people it is probably convenient. But at the same time it is quite unreadable and weird. Relying on oddities is not a good idea (see: C). The more such "functionalities" in a language, the more confusing and inconsistent it is. The variable will be created anyway, so what's the problem with declaring it explicitly?

That's just your personal opinion, if you read with as a macro that's on you, for me it always read like: "with this thing do the following" and not "in the following prepend all the terms with this macro" IMHO if it had the second semantic it should use the keyword prepend not with. Also with allows to read the code from top to bottom, first execute the with clause, then do the following using the result of the with clause. If it was a macro it would be for each line you must look what happens in the with clause to understand how it's working.

Lastly and more importantly, Pascal specifically does not have powerful macros like C does, so it would be extremely untypical to introduce them through with

Also your hint at C, how do I have to understand that? C is, compared to Pascal, standardized, you do never need to rely on some implementation quirks of C because first comes the standard then the implementations follow that standard (I mean I know how to understand this, you have shown time and time again in the past that you fundamentaly.misunderstand C and how standardized languages work, or how standardization committees and meetings are done, I just want to point it out here again)
« Last Edit: January 04, 2025, 01:04:55 pm by Warfley »

flowCRANE

  • Hero Member
  • *****
  • Posts: 911
Re: Why with allows assignment
« Reply #50 on: January 04, 2025, 01:24:49 pm »
and a quirk present in the compiler.

It's not a quirk, it's a useful feature. I've used this many times without even thinking about who thinks what about it, because it's useful and was intentionally implemented to expand the capabilities of this block. I wouldn't be surprised at the existence of a protest if it was the UB, but since it's a defined feature, stop whining already.

Quote
I understand that for some people it is probably convenient. But at the same time it is quite unreadable and weird.

The with do block is by its nature an abomination that destroys syntactic readability (especially when more than one parameter is involved), which is why I never use it to shorten syntax. The only reason I ever use it is precisely its ability to automatically allocate a temporary object on which I execute several methods or copy data from to other variables. So what bothers you is also the only sensible advantage of the with do block.

But since I gave up using this block many years ago, because it only obfuscates the code, I don't care what you do with it. The only thing that bothers me about this thread is the stupid denial that it is a feature and calling it a quirk or even a bug, which is ridiculous because some of you are gaslighting yourselves. If you really want to remove the automatic allocation of temporary objects from the compiler, then go ahead. Although backward compatibility will be broken, so it's better to think about it (it's a bit too late for this type of discussion).

Quote
The variable will be created anyway, so what's the problem with declaring it explicitly?

Why use this block at all if it does nothing except make the code harder to analyze? Screw it.
« Last Edit: January 04, 2025, 01:27:01 pm by flowCRANE »
Lazarus 3.6 with FPC 3.2.2, Windows 10 — all 64-bit

Working solo on a retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

simone

  • Hero Member
  • *****
  • Posts: 648
Re: Why with allows assignment
« Reply #51 on: January 04, 2025, 01:47:13 pm »
The implicit creation of a temporary object, clarified by Warfley, justifies this behavior. I think this is implementation dependent and not correct according to the original language specification. It is not officially documented anywhere. However, like other long-standing deviations, the problem is not solvable, because it would break backwards compatibility.

What original language specification? Originally the with statement was only allowed over variables and constants not over return values of functions. But also, original Pascal didn't have units, bit operations and many other stuff.
We are programming in Free Pascal, which is its own version of Pascal with its own Syntax and semantics. If you want to program in ISO or ExtPas, you can do that, you can even do that to some degree with the FPC (but it's not fully compatible), but then you are programming in a different programming language than the rest of us

I don't want to use some standard that almost no one in the real world knows. I would like what you describe to be documented. For the rest, I confirm what I think.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

LV

  • Full Member
  • ***
  • Posts: 239
Re: Why with allows assignment
« Reply #52 on: January 04, 2025, 01:57:05 pm »
Yes. If you follow the documented features of Free Pascal, there should be no issues.
"The with statement serves to access the elements of a record or object or class, without having to specify the element’s name each time."
https://www.freepascal.org/docs-html/ref/refsu62.html
It seems like the discussion is about undocumented capabilities.

440bx

  • Hero Member
  • *****
  • Posts: 5080
Re: Why with allows assignment
« Reply #53 on: January 04, 2025, 02:31:58 pm »
"The with statement serves to access the elements of a record or object or class, without having to specify the element’s name each time."
https://www.freepascal.org/docs-html/ref/refsu62.html
Nice to know the proper behavior is documented.

It seems like the discussion is about undocumented capabilities.
Not just undocumented but atrociously wrong.  When did it become acceptable to assign a value to a function outside the function ?  must have been after "writable constants" became a thing in Pascal (I wonder why no standard has been updated to include this "great feature"... totally genial... kind of like creating temporaries as a result of using a "with" statement... a couple of other such features come to mind... "progress" never stops.)

These are the kinds of things that make it embarrassing to promote Pascal.  That is extremely unfortunate.
(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: 1870
Re: Why with allows assignment
« Reply #54 on: January 04, 2025, 02:56:44 pm »
I wonder why no standard has been updated to include this "great feature"...
Probably because the last version of the extended Pascal standard is nearly 35 years old. The last update was closer to the invention of Pascal than it is to today. Probably half of all people programming in Pascal today are younger than that standard. It's ancient and the reason it's not updates anymore is because no one uses it.

simone

  • Hero Member
  • *****
  • Posts: 648
Re: Why with allows assignment
« Reply #55 on: January 04, 2025, 03:22:39 pm »
As already said, I completely agree with 440bx. I don't care if I'm in the minority.

I sometimes don't understand the philosophy behind fpc's choices. New features, like inline variables (which I don't particularly like either), are rejected, due to inconsistency with the fundamental principles of Pascal, but are tolerated atrocities like this.

Moreover, I don't find it normal that to understand the behavior of an elementary and ancient construct, like "with", one has to examine the compiler internals.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

BrunoK

  • Hero Member
  • *****
  • Posts: 684
  • Retired programmer
Re: Why with allows assignment
« Reply #56 on: January 04, 2025, 04:33:54 pm »
Expand the following project.

What is it you don't understand with with ?

Rewrite it without if, is it clearer ?

+ there are quite a few natural optimizations done when correctly using with.

Okoba

  • Hero Member
  • *****
  • Posts: 616
Re: Why with allows assignment
« Reply #57 on: January 04, 2025, 04:48:56 pm »
Why the first test raise no error like the second one?

Because for with it's simply not implemented yet. After all from a language point of view both are valid. However current Delphi versions forbid both due to wrong expectations of the users and FPC up to now only errors out on the function result, because it's something that the compiler needs to actively check for.

And on the same topic, is there a way in Pascal that I can return a record by the reference so any change to the result, changes the source?

Use a managed record.

As for the WITH control statement, I've ported D code over that uses that WITH with returning items from a function that seem to work just fine in D and also FPC. Basic facts about WITH is it creates a local branch of identifiers. In this case a RECORD where that record maybe referenced several times read or written while inside the WITH.

*sigh* Current Delphi versions forbid this code as well, because it does not do what you expect it to do.

@PascalDragon  can you give me a sample of how it can be done with managed records?

VisualLab

  • Hero Member
  • *****
  • Posts: 639
Re: Why with allows assignment
« Reply #58 on: January 04, 2025, 05:09:42 pm »
I understand that for some people it is probably convenient. But at the same time it is quite unreadable and weird. Relying on oddities is not a good idea (see: C). The more such "functionalities" in a language, the more confusing and inconsistent it is. The variable will be created anyway, so what's the problem with declaring it explicitly?

That's just your personal opinion, if you read with as a macro that's on you, for me it always read like: "with this thing do the following" and not "in the following prepend all the terms with this macro" IMHO if it had the second semantic it should use the keyword prepend not with. Also with allows to read the code from top to bottom, first execute the with clause, then do the following using the result of the with clause. If it was a macro it would be for each line you must look what happens in the with clause to understand how it's working.

I have never written anywhere:
  • "with" is a macro, nor
  • I treat "with" as a macro.

Lastly and more importantly, Pascal specifically does not have powerful macros like C does, so it would be extremely untypical to introduce them through with

And it's a good thing that it is. Macros are an invention from the early days of computer science. As "good" as monkey patching. Ad hoc, home-made, and makeshift solutions cause stagnation and are not a good solution.

Also your hint at C, how do I have to understand that? C is, compared to Pascal, standardized, you do never need to rely on some implementation quirks of C because first comes the standard then the implementations follow that standard (I mean I know how to understand this, you have shown time and time again in the past that you fundamentaly.misunderstand C and how standardized languages work, or how standardization committees and meetings are done, I just want to point it out here again)

1. I understand your point of view, but I don't share it entirely. We all know that C is a mixture of good, weird and stupid ideas. And it won't get any better. In my statement, I meant its unreadability and some weird rules.

2. I don't have a religious approach to standards. They are useful, as long as they are well designed. Perhaps GCC or MSVC compilers strictly adhere to the standard. It may be different with others. For example, Microchip itself states in its documentation that you should carefully check the documentation of their C compilers, because there are some differences from the standard. And I'm not surprised at all, because their compilers support microcontrollers, not large computers. So there may be some differences in the case of other C compilers as well.

3. I may not be a C expert, but I can really live without it :) When I have doubts, I check the details in the documentation.

egsuh

  • Hero Member
  • *****
  • Posts: 1563
Re: Why with allows assignment
« Reply #59 on: January 05, 2025, 03:00:39 am »
I don't know why this issue is a big issue. Personally I like "with" very much.

- Scoping and readability

   Sometimes I was confused of "with" scope, and made some mistakes. But confusion is only when same identifiers are used within and outside "with" scope. Now I understand exactly how it works and love even using nested "with"s. Backward checking is all that is necessary.

I might have different attitude because I do not write many programs but use one program frequently. So once functions/procedures are written correctly, I seldom have to look into it again line by line. Instead, I only have to see it again to find out my "logic" or alrorithm of the routine. In this case, "with" improves readability by large, as I do not have to worry about any inconsistencies within there. Compare following example.

             V1 := SQLQuery1.FieldByName('F1').AsString;
             V2 := SQLQuery1.FieldByName('F2').AsString;
             V3 := SQLQuery1.FieldByName('F3').AsString;
             V4 := SQLQuery1.FieldByName('F4').AsString;
             V5 := SQLQuery2.FieldByName('F5').AsString;

            vs.

            with SQLQuery1 do begin
                   V1 := FieldByName('F1').AsString;
                   V2 := FieldByName('F2').AsString;
                   V3 := FieldByName('F3').AsString;
                   V4 := FieldByName('F4').AsString;
            end;
            V5 := SQLQuery2.FieldByName('F5').AsString;

I can promptly see that V5 comes from different dataset from other variables.


- Regarding Temporary Storage

    Function results are maintained temporarily. But this is not true if a memory space is allocated from heap, not local stack. Object Orinted Programming approach was not easy at first for me. It didn't have much meaning than simply collecting codes in one place. But now I came to a conclusion that it's not that superficial. Instances of classes, i.e. objects, exist at some place in a world created by me - my program space, until I destoy it. Function result is temporary but not the object (or any record or integer to which heap memory has been allocated). So in the case of "with Test do ... " we are not accessing function result but the persistent object created by the function. The object created with "with" is temporary but not always if the object has reference to its container, etc. For example,

Code: Pascal  [Select][+][-]
  1. type
  2.    TMyObject = class
  3.          ...
  4.          FPGMap: TFPGMapObject<integer, TMyObject>;
  5.          var1, var2: string;
  6.          ..
  7.     end;
  8.  
  9. var
  10.      AFPTMapObject : TFPGMapObject<integer, TMyObject>;
  11.  
  12. implementation
  13.  
  14. constructor  TMyObject.Create(AnIndex: integer; FMap: TFPGMapObject);
  15. begin
  16.       inherited;
  17.       FPGMap := FMap;
  18.       FPGMap.Add(AnIndex, Self);  
  19. end;
  20.  
  21. begin
  22.      with DataSet do begin
  23.           First;
  24.           while not eof do begin
  25.                with TMyObject.Create(FieldByName('index').AsInteger, AFPGMapObject)
  26.                do begin            
  27.                   var1 := FieldByName('Title').AsString;
  28.                   var2 := FieldByName('Description').AsString;
  29.                end;
  30.                Next;
  31.           end ; // while
  32.       end; // with DataSet
  33.          .........
  34.  
  35.       AFPGMapObject.Free;
  36. end.
  37.  


I love this kind of codes, as this reduces the number of key typings, and is much easier to understand what this part of codes try to do.


- Overall trends

  Recently popular programming languages seem to allow more features. The only other language I know than Pascal is javascript, but anyway its systax like

                if (a=2) 

is valid and returns always true (which caused me many mistakes. I should have written "a==2").   Pascal has tradition but I believe we don't have to resist new trends too strongly.  Further, sometimes I wish pascal had feature like :

               with (aclass := TMyClass.Create) do begin
                       .......

               end;
               ......
               aclass.free; 


Of course I can write

                aclass := TMyClass.Create;
                with aclass do begin
                             .....
                end;
                aclass.free;


But this requires reading whole routine to find where aclass is created.


Conclusion: I love "with" because it lessens my cognitive efforts, except at the first writing of codes.

 

TinyPortal © 2005-2018