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?Records are copied by value, so no, that's why we use pointers or 'var' parameters, which are basically pointers to the value...
For example changing V changes the original X.
I know I can return the pointer, but is there any other way?
No. The left side of an ":=" statement must have a (non temporary?) memory address and be writable. A function result doesn't.
HiQuoteAnd 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?Records are copied by value, so no, that's why we use pointers or 'var' parameters, which are basically pointers to the value...
For example changing V changes the original X.
I know I can return the pointer, but is there any other way?
Regards Benny
https://forum.lazarus.freepascal.org/index.php/topic,39961.msg275471.html#msg275471QuoteNo. The left side of an ":=" statement must have a (non temporary?) memory address and be writable. A function result doesn't.
For the part with "With Test": I'm with egsuh on this.
"With" starts a new scope, and in this case (probably?) evaluates the "Test"-Function and returns the Result, getting an Address in Memory.
The moment the code leaves the "With"-scope that memory is discarded
Then why the first test using with returns no error?!
Because it has a valid and writable address in memory, allowing you to access "V" and write to it.https://forum.lazarus.freepascal.org/index.php/topic,39961.msg275471.html#msg275471Then why the first test using with returns no error?!QuoteNo. The left side of an ":=" statement must have a (non temporary?) memory address and be writable. A function result doesn't.
For the part with "With Test": I'm with egsuh on this.
"With" starts a new scope, and in this case (probably?) evaluates the "Test"-Function and returns the Result, getting an Address in Memory.
The moment the code leaves the "With"-scope that memory is discarded
I think that "I can not set the result of function directly" and "with gives you direct access to that variant". But what I think you are saying is that `with` is copying the result of function so it can allow setting the value of that temp silently. It seems wrong from the point of a reader like me. I get the technicality of it, but it leads to dangerous results.That's exactly the reason why i have never used "with" in my life.
So you can not make something like String with records?Well, yes and no - it depends on what you're doing... %)
I believe you found a compiler bug. "with Test do V := 1;" should be _exactly_ the same as "Test.V := 1;". "with" is basically a way to abbreviate, it's not supposed to have any side effect. IMO and formally, that is a bug.
program Project1; { removed } var T: TTest; begin with Test do V := 1; //No Error Test.V := 1; //Error: Argument cannot be assigned to end.
Why the first test raise no error like the second one?
Let's see what the FPC developers say.There are posts from PascalDragon in the link I have provided. It is the same topic.
I see nothing wrong with it and it would break code like it's going out of style otherwise.Other than FPC doing it _wrong_, there is nothing wrong with it. Fixing that bug can only break code that is wrong... no great loss there and wrong code should go out of style anyway.
Please don't compare d with fpc when d can't do something fpc can.I remember at least one case where you compared FPC to Delphi to imply there was a bug in FPC but, of course, it's ok when you do it but not others.
I see nothing wrong with it and it would break code like it's going out of style otherwise.Other than FPC doing it _wrong_, there is nothing wrong with it. Fixing that bug can only break code that is wrong... no great loss there and wrong code should go out of style anyway.Please don't compare d with fpc when d can't do something fpc can.I remember at least one case where you compared FPC to Delphi to imply there was a bug in FPC but, of course, it's ok when you do it but not others.
You say whatever you want but if compiler can do something useful where the other cannot, I prefer that to be a bonus.It's not a bonus, it's a bug. "with" is simply shorthand to specify a scope for one or more statements. Whether the scope is specified using a "with" or explicitly in the statement should not make any difference. FPC is _wrong_, period. That's not an opinion, it's a fact.
Why the first test raise no error like the second one?
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?
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.
In Delphi, both the assignment within the WITH and the direct assignment are indicated as errors.
I believe (but I am the last one to give credence to) that a similar situation should be handled and the error should be reported to the developer.
That assignment is an error, and therefore it should be reported, even if it does not produce any effect, and that is precisely the point: the developer writing that code expects it to be executed (ok, he wrote a stupid thing) and the fact that it is not executed (or that it cannot be executed) MUST be reported by the compiler.
with Test do
V := 1; //No Error
Test.V := 1; //Error: Argument cannot be assigned to
I believe you found a compiler bug. "with Test do V := 1;" should be _exactly_ the same as "Test.V := 1;". "with" is basically a way to abbreviate, it's not supposed to have any side effect. IMO and formally, that is a bug.
program Project1; { removed } var T: TTest; begin with Test do V := 1; //No Error Test.V := 1; //Error: Argument cannot be assigned to end.
Why the first test raise no error like the second one?
Let's see what the FPC developers say.
I see nothing wrong with it and it would break code like it's going out of style otherwise.Other than FPC doing it _wrong_, there is nothing wrong with it. Fixing that bug can only break code that is wrong... no great loss there and wrong code should go out of style anyway.Please don't compare d with fpc when d can't do something fpc can.I remember at least one case where you compared FPC to Delphi to imply there was a bug in FPC but, of course, it's ok when you do it but not others.
You say whatever you want but if compiler can do something useful where the other cannot, I prefer that to be a bonus.It's not a bonus, it's a bug. "with" is simply shorthand to specify a scope for one or more statements. Whether the scope is specified using a "with" or explicitly in the statement should not make any difference. FPC is _wrong_, period. That's not an opinion, it's a fact.
Pretty simple, with creates a new temporary variable where the function result is copied into.That's nonsense.
It creates a scope for an object. If the object is referencable it just creates a scope around the existing object. If it is the result of some expression, it copies it into a new temporary object to make it referencable: https://gitlab.com/freepascal.org/fpc/source/-/blob/main/compiler/pstatmnt.pas#L659
"with" doesn't create anything. The "with" statement is used to establish a scope, _nothing_ more, nothing less. It's information for the parser.
It creates a scope for an object. If the object is referencable it just creates a scope around the existing object. If it is the result of some expression, it copies it into a new temporary object to make it referencable: https://gitlab.com/freepascal.org/fpc/source/-/blob/main/compiler/pstatmnt.pas#L659What FPC is doing is simply _wrong_. The presence or absence of a "with" should _never_ alter the semantics. If it does, it's a bug, it's that simple.
that's a opinion you can have, but it's specifically not how with is intended to be used for decadesNice try. That's _not_ an opinion.
Find a formal Pascal standard that supports what you're saying. Good luck!! Just in case, FPC is _not_ a Pascal standard.
BTW, do you think assigning a value to a function should be allowed outside of the function ? Are function results lvalues ? (looks like in some cases, to FPC, they are.)
I don't care what the Pascal standards state,and that's one of the many reasons Pascal has been going nowhere for years now.
most people never write standard Pascal.Most people do write standard Pascal, admittedly with a lot of extensions but, a lot of FPC is standard Pascal, e.g, compound statements, if statements, while statements, etc, etc, etc. Wow!! unknowingly, you've been writing standard Pascal.
ISO Pascal does not even support units. Pascal, at least the dialects people use in the real world, is not standardized, it's a quasi standard like java, where the major distributions define the functionality through their implementations and documentation.A lot of that is true but, if you knew how to write a compiler you'd know that "with" does _not_ create any temporaries and you'd also know that, outside of a function, function results cannot be treated as lvalues and, not only that, you'd also know why.
This is intended behavior for FPC, like it or not, but it's how the language worksI don't know if it is intended or not but, one thing is absolutely certain, it is wrong.
And what cases do you mean? I only know of cases where the result of a function will be written into a temporary variable, like with does.It is NOT the "with" that causes the function result to be held into a temporary variable. The result will be held in a temporary variable if it does not fit into a register (or sometimes, two) whether or not there is a "with". You should know that, it is _obvious_ and the reason why is obvious too.
Functions don't Return lvalues,Of course they don't and for that very reason a value cannot be assigned to them outside of the function. You cannot have "FunctionName.FunctionRecordFieldname := somevalue" whether there is a "with" or not because as you stated, function results cannot be treated as lvalues outside of the function.
It is NOT the "with" that causes the function result to be held into a temporary variable. The result will be held in a temporary variable if it does not fit into a register (or sometimes, two) whether or not there is a "with". You should know that, it is _obvious_ and the reason why is obvious too.
With creates a new temporary object for the result of the function, to be referenced within the with scope.A temporary will be created whether or not "with" is used simply because the function result must be usable whether or not a "with" is present.
No that's simply wrong, you do not need to create a temp node. The FPC node tree is implemented in a way you cann use the call node directly. Infact if you go to line 640 (https://gitlab.com/freepascal.org/fpc/source/-/blob/main/compiler/pstatmnt.pas#L640) and skip the if (just replace the long condition with a simple true) no temp object will be created in the node tree, and with behaves exactly as you intend it to.With creates a new temporary object for the result of the function, to be referenced within the with scope.A temporary will be created whether or not "with" is used simply because the function result must be usable whether or not a "with" is present.
No that's simply wrong,Really ??? where do you think the result of a function that returns a type that does not fit in a register goes ??? in a sardine can ? a ziploc bag ? a mailing envelop ???
Really ??? where do you think the result of a function that returns a type that does not fit in a register goes ??? in a sardine can ? a ziploc bag ? a mailing envelop ???
or might it just be a metaphysical "ethereal' entity ? of course, it cannot possibly be go into a temporary area... (unless there is a "with")... unbelievable!!!!
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.
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:
with TSomeClass.Create(nil) do try DoThis(); DoThat(); finally Free(); 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?
and a quirk present in the compiler.
I understand that for some people it is probably convenient. But at the same time it is quite unreadable and weird.
The variable will be created anyway, so what's the problem with declaring it explicitly?
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
"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."Nice to know the proper behavior is documented.
https://www.freepascal.org/docs-html/ref/refsu62.html
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.)
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.
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.
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)
with VarWithVeryLongNameSoLongThatItAlmostFeelsLikeYoureUsingC as myvar do
begin
myvar.somefield := somevalue;
...
end;There is/was a proposal for something like:The as Syntax is not working, because as expressions are already allowed in with statements. But yeah if you look at the MR I've linked above it can do:Code: [Select]with VarWithVeryLongNameSoLongThatItAlmostFeelsLikeYoureUsingC as myvar do
begin
myvar.somefield := somevalue;
...
end;
That could make sense to me (in order to not having to type VarWithVeryLongNameSoLongThatItAlmostFeelsLikeYoureUsingC over and over again, and at the same time not having scope issues (not knowing wether e.g Width points to VarWithVeryLongNameSoLongThatItAlmostFeelsLikeYoureUsingC or to e.g. the form it is in.
Bart
With as it was originally is one of these weird features that just shortens typing without enabling any new way of doing things."with" is just a way to establish a scope. Nothing "weird" about it.
Simultaneously it introduced shadowing.Shadowing ??? what are you talking about ? and where did you get that stuff from ? references please!.
But the programming environment has changed. If you now write a method for a form event handler, you are in the context of the TForm class, having hundreds of symbols with very generic names (e.g. name, width, height, top, etc.) and with is used to access other classes which also have hundreds of symbols.and magically, somehow, abracadabra... now it is possible to assign a value to a function result _outside_ of the function. The computer science field needed that about as much as writable constants. Welcome to Alice in Wondercode.
So IMHO the creation of a scoped temporary object is pretty much the only reason why with is actually useful. Since code completion is a thing, there is no reason to have to avoid writing out a few more characters, so using with just to shorten code is a bad practiceThere is absolutely nothing wrong about using "with" but, there are obviously programmers who are totally clueless about how to use it correctly but, why would anyone care about that ? (just in case, that's rethorical.)
Shadowing ??? what are you talking about ? and where did you get that stuff from ? references please!.
and magically, somehow, abracadabra... now it is possible to assign a value to a function result _outside_ of the function. The computer science field needed that about as much as writable constants. Welcome to Alice in Wondercode.Imagine a world in which you can't change any result of a function, then the following would also not work:
First, what you are calling "shadowing" is normally referred to as _masking_.
type TTest = record x: Integer; end; procedure Foo(x: Integer); var t: TTest; begin with t do x := 42; // t.x shadows param x end;
Shadowing means overriding some identifier with another one. Sometimes shadowing can be disambiguated, e.g. when one unit shadows definitions of another unit you can write unit1.x to disambiguate.
Free Pascal does not allow shadowing without disambiguation, e.g. the following is not allowed.for.exactly that reason:You really need to learn basic compiler construction theory. In that code there is no masking (or shadowing as you call it), what there is, is a _duplicate_ identifier. No correctly implemented compiler would allow that code because the parameter "x" and the local variable "x" are in the _same_ scope, therefore they cannot use the same name.With statements allow to shadow symbols without disambiguation (as in the example above), which is why it's bad.
procedure foo(x: Integer); var x: Double; begin end;
It's so bad that languages that used to have with, like JavaScript, deprecated it, because it's a syntactic concept that's born out of pure laziness, gives no semantic benefits but due to shadowing can introduce errors.Yes, allowing duplicate identifiers is so bad that no correctly implemented compiler allows it. Duplicate identifiers have been "deprecated" since the birth of compilers and interpreters.
Imagine a world in which you can't change any result of a function, then the following would also not work:Nice try but "t" is most definitely NOT the result of a function. "t" is where the result of the function is copied to. That's VERY different. The result of the function is NOT being changed, the location where the result of the function has been COPIED to is being changed.In this example t is the result of a function but is changed outside the function. Oh no hell breaks lose, how can this be acceptable!!!!
t := MyFunc; t.x := 42;
But I mean you do not know what shadowing is, which is absolutely basic knowledge about programming language design, so I guess there is no real reason to continue to argueLet's engage in "basic knowlege"... it's not called "shadowing" (at least not by those who know a little compiler theory), it's called masking. if you need confirmation of that, write a C program that masks one variable or parameter and you'll get a hint or warning telling you that some variable is _masking_ another one.
First, what you are calling "shadowing" is normally referred to as _masking_.No it's not: https://en.m.wikipedia.org/wiki/Variable_shadowing
You really need to learn basic compiler construction theory. In that code there is no masking (or shadowing as you call it), what there is, is a _duplicate_ identifier. No correctly implemented compiler would allow that code because the parameter "x" and the local variable "x" are in the _same_ scope, therefore they cannot use the same name.No it's not, because I know about basic Compiler construction and know that parameters are in their own symtable and there by spawn their own scope. In the FPC sources it's called the paramst.
Nice try but "t" is most definitely NOT the result of a function. "t" is where the result of the function is copied to. That's VERY different. The result of the function is NOT being changed, the location where the result of the function has been COPIED to is being changed.First, technically speaking, anything to big for a register will be passed by reference, so the function literally constructs the result in place. But even putting that technicality aside: congratulations you exactly got the point I was making all along. When you use with, you don't change the result of the function, you change a temporary object where the result of the function is assigned to
No it's not: https://en.m.wikipedia.org/wiki/Variable_shadowingInteresting... second time (first was you) I see it referred to as shadowing. Find a compiler that emits a message stating that some variable is "shadowing" another one... good luck but, you can find a compiler that warns about a variable masking another one (that's what every C compiler I've used emitted as a message.)
No it's not, because I know about basic Compiler construction and know that parameters are in their own symtable and there by spawn their own scope. In the FPC sources it's called the paramst.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.
So thank you for agreeing with me. So what's your problem?I couldn't possibly agree with you. I don't have a problem but, I suggest, again, you read the books I previously mentioned.
imho you are both saying exactly the same only using other words and viewing it from another standpoint/angle (each with their own believes).No, what he is saying is very different than what I'm saying and totally opposite of what a correctly implemented compiler would do.
More problematic is clouding the topic with objects which wasn't part of the original question to begin with.You got that part right.
No, what he is saying is very different than what I'm saying and totally opposite of what a correctly implemented compiler would do.What I see/read and believe that matters is the end result which is the same. Aside whether or not that is correct behaviour for a compiler.
Creating a temporary as a result of a "with" statement is absolutely incorrect in all cases. No exceptions. Period. The _only_ purpose of a "with" is to establish a scope, nothing more and nothing less.If I recall correctly that was a decision made for FPC by being Delphi compatible (which thus changed that behaviour).
What I see/read and believe that matters is the end result which is the same. Aside whether or not that is correct behavior for a compiler.But the end result isn't the same. The result is that it is possible to assign a value to a function outside the function which is not just incorrect, it's appalling. see the OP's code (first post), one statement is accepted while the other isn't in spite of the fact that the two are supposed to be semantically identical.
There is/was a proposal for something like:Code: [Select]with VarWithVeryLongNameSoLongThatItAlmostFeelsLikeYoureUsingC as myvar do
begin
myvar.somefield := somevalue;
...
end;
That's already available by defining a 'LeftPad' macro, no need to change the "with" statement to get that funcitonality.verses :
if TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding = 0 then TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding = 42;
with TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding as LeftPad do begin if LeftPad = 0 then LeftPad = 42; X := Y; .... end;
Saves a lot of error prone typing but more importantly, much, much easier to read. The use of "as LeftPad" leaves no doubt what object is being addressed, no one has to wonder the X or Y is also getting the "with treatment".
Davo
But the end result isn't the same.There you are a bit in the wrong my friend or at least not precise enough. The value is assigned to in the scope but not outside that scope.
And that's not the only problem creating a temporary as a result of a "with" statement creates. if the "with" states multiple scopes, are there supposed to be temporaries for each one ?... it's so wrong, it's beyond belief it is being done. Is the "with" statement going to create temporaries in some cases and not in others ? ... where are those cases documented ?Yes, that is indeed problematic (or at least can be especially when in the case of the formentioned anonymous functions which by default introduces a new scope when created).
Another problem seems to be that there are people who are very willing to accept/support incorrect behavior because they find it convenient. That's not a good thing but, admittedly that's a different problem though, it certainly doesn't help matters.The problem is more that the compiler should flag it it as incorrect for both cases in OP's example (but at the same time OP's code is trying to hide the manipulation just as the absolute trick that once allowed for modifying an iterator) . For sure it is confusing which can been seen by the people running into these kind of things (remember/note that the compiler flagged the assignment as illegal only recently (in the grant scheme of its existence that is)).
In comparison to this topic, quantum dynamics appears to be more comprehensible. :o
There you are a bit in the wrong my friend or at least not precise enough. The value is assigned to in the scope but not outside that scope.But, inside or outside the scope, a function result, outside the function, is _not_ an lvalue, therefore cannot be assigned to and, there should be no temporary and if there is a temporary representing the function result then it should behave exactly the same as the function result otherwise, the programmer should have copied the function result into a separate variable then, anything goes because it no longer represents the function's result.
But, inside or outside the scope, a function result, outside the function, is _not_ an lvalue, therefore cannot be assigned to and, there should be no temporary and if there is a temporary representing the function result then it should behave exactly the same as the function result otherwise, the programmer should have copied the function result into a separate variable then, anything goes because it no longer represents the function's result.Exactly right. We seem to agree on that (so was Warfley as far as I understood)
Summary: a temporary should most definitely not exist as a result of the "with" but, if for the sake of argument, we accept the existence of a temporary to represent the function's result then it must behave exactly as the function's result which means, it cannot be changed because the temporary isn't in the scope of the function.I am very tempted to agree to that but then, I am not a compiler developer or someone calling the shots (nor do I have any idea if the obfuscation of TS's code can be detected in an easy manner).
But the programming environment has changed. If you now write a method for a form event handler, you are in the context of the TForm class, having hundreds of symbols with very generic names (e.g. name, width, height, top, etc.) and with is used to access other classes which also have hundreds of symbols.
For example, if you use with to access a canvas in the form paint function, a canvas has a width, height, font, etc. All shadowing the properties of the form.
It is either this or that and not one time this and another time that. But as explained the OP's code obfuscate things probably to such an extend that the compiler is unable to pick up in that.
BUT, please, do prove me wrong... find a mainstream compiler that refers to a masked variable as a shadowed variable.
-Wshadow
Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C) or whenever a built-in function is shadowed. Note that in C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum. If this warning is enabled, it includes also all instances of local shadowing. This means that -Wno-shadow=local and -Wno-shadow=compatible-local are ignored when -Wshadow is used. Same as -Wshadow=global.
But, if you want to argue that, try compiling this:Even FPC will tell you there is a duplicate identifier thereby conclusively proving the parameter and the local are in the same scope.
procedure DuplicateIdentifier(Parameter : integer); var Parameter : boolean; begin end;
Creating a temporary as a result of a "with" statement is absolutely incorrect in all cases. No exceptions. Period. The _only_ purpose of a "with" is to establish a scope, nothing more and nothing less.
Some people may support Alice in Wonderland compilers, I'm not one of them.
1
12
2
Out of curiosity what would be the syntax for the said ''LeftPad' macro' ?That's already available by defining a 'LeftPad' macro, no need to change the "with" statement to get that funcitonality.
with TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding as LeftPad do begin if LeftPad = 0 then LeftPad := 42; // bk corrected syntax error X := Y; .... end;
To quote GCC's help (https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html):Ok, I've been programming for over 40 years and this is the third time I came across the term "shadow" to refer to masking but, fair enough, to my surprise, variable shadowing is a thing.Quote-Wshadow
Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance variable (in Objective-C) or whenever a built-in function is shadowed. Note that in C++, the compiler warns if a local variable shadows an explicit typedef, but not if it shadows a struct/class/enum. If this warning is enabled, it includes also all instances of local shadowing. This means that -Wno-shadow=local and -Wno-shadow=compatible-local are ignored when -Wshadow is used. Same as -Wshadow=global.
I think we can agree that GCC is considered a "mainstream compiler"? ;)Yes, we can agree to that.
Not really your fault, but to be fair, it's a bad example, cause as far as the implementation in FPC is concerned the parameter and the locals are different symbol tables and the compiler actively needs to check that an identifier inserted into the local symbol table isn't conflicting with one in the parameter symbol table.How FPC deals with its symbol tables is completely irrelevant. What's relevant is that the parameters and the locals are in the same scope. Slice it however you like but THAT is a fact and, if you compile that, FPC correctly claims there is a duplicate identifier. Therefore, regardless of how FPC fiddles with its symbols tables, it reaches the correct conclusion: duplicate identifier, which can only happen when two identifiers are in the same scope.
Then please take your grievances up with the developers at Borland, because Delphi is where this behaviour originates and it is implemented in FPC to follow that behaviour:You're right, I just tested it with Delphi 2 and it behaves as you stated. Another "breakthrough" from the folks that contributed writable constants to computer science.
Oh, and just for the sake of it, replacing the with-statement with the following:I tried it because I had to see it to believe it and, you're right, that's the output. It's _appalling_. oh well... I wonder what N. Wirth would say if he saw this stuff.
with Test, Test do begin
Will result in this output:Code: [Select]2
2
@BrunoK,
it would be something like this (untested because I cannot test it):
{$define LeftPad:=TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding}
and, IMO, it would be better to name the macro "LeftPadding" instead of "LeftPad" as this would make it more evident that the field being referenced is "LeftPadding".
Sadly, it seems that the shown example is syntactically incorrect thus not adding anything constructive to the discussion.
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:
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".
I am not sure how you came to that conclusion Bruno. The first example I showed compiles and behaves exactly as I expect.
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.
@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 !Agree, as mentioned above, macro would loose the interest of the temporary scoped evaluation of the expression
Davo
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.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.
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.
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?
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.
Agree, as mentioned above, macro would loose the interest of the temporary scoped evaluation of the expressionwhich reference is then used twice, once in the test and once in the assignment.
with TKMemoParagraph(KMemo1.Blocks[ABlockNo]).Parastyle.LeftPadding
For aliasing, the following syntax could be interesting
with variable_ref [as type] [as alias] do ...
If something like that existed, instead of :I could write :
lFI1 := TIntegerField(FieldByName('I1')); lFI2 := TIntegerField(FieldByName('I2')); for i := 0 to 9 do begin Append; lFI1.AsInteger := i; lFI2.AsInteger := i; Post; end;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.
with TIntegerField(FieldByName('I1')) alias FldI1, TIntegerField(FieldByName('I2')) alias FldI2 do begin for i := 0 to 9 do begin Append; FldI1.AsInteger := i; FldI2.AsInteger := i; Post; end; end;
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
For example, while the following does not work right now in fpc: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.Because i and j are in different scopes,
procedure foo(i: Integer); var j: Integer = i; begin end;
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.
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.)
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) :
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.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) :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.
program Project1; const HighInt64 = int64(int64(-1) shr 1); // Typed const type TTest = record V: int64; end; var X: TTest; function Test: TTest; begin Result := X; end; var i: qword; begin with Test do begin V := HighInt64; //No Error WriteLn(X.V, ' ', {With Test.}V); end; Readln; end.
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.
It is a scope declaration statement.Yes, intentionally.
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.)What I meant it that the way the FPC is currently implemented, initialization cannot be dynamic, because the code that parses the initialization directly spits out an assembly list (there is no intermediate layer like the node tree which allows the initialization to represent more complex concepts). It's literally: Read number -> Write to assembly.
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.What do you think a scope is? A scope is a set of symbols, represented through a symbol table. Scopes are spanned through syntax structures, in a strictly formal compiler (usually based on parsing tables), they would be strictly associated with AST nodes (which correspond to reduction rules in the grammar definition), while in a less formal compiler like a hand crafted recursive decent LL parser such as the FPC, scopes can be more dynamically managed (e.g. with statements do not have their own representation in the AST, they are basically macros based on an ephemeral symtable). But let's stick to the formal case.
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...)
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.With is what it is built to be. There is no fundamental rule on what with is supposed to be. Yes with declares a scope, but it declares a scope around an object. Either an already existing object, in case of a variable, or a newly allocated temporary object.
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.
As I asked you in the previous post, IF the parameter "x" is not in the same scope as the local variable "x" then explain why the compiler claims "x" is a duplicate identifier. As I stated in the previous post, you got some explaining to do.I already answered that. Because the message "duplicate identifier" has nothing to do with scope.
BTW, you are correct that the procedure _name_ is not in the same scope as its parameters and its locals.So we agree that local variables and function name are in a different scope, so this is why the FPC does not throw a "duplicate identifier" error right?
BTW, you are correct that the procedure _name_ is not in the same scope as its parameters and its locals. I can show you a post that is a few years old where I make that point along with showing that FPC does not always resolve scopes correctly.I was talking about the function name as the result variable. So the function name as function symbol, used to call the function is semantically different from the function name as return variable symbol, depending on the scope. In the scope where the function is registered, it's solely the symbol for calling the function, in the scope of the function body it doubles as a symbol for the result variable.
No, you did not. Additionally, it has _everything_ to do with scopes because there can only be duplicates if they are in the same scope. if they were in different scopes they wouldn't be duplicates... doh!As I asked you in the previous post, IF the parameter "x" is not in the same scope as the local variable "x" then explain why the compiler claims "x" is a duplicate identifier. As I stated in the previous post, you got some explaining to do.I already answered that. Because the message "duplicate identifier" has nothing to do with scope.
Are the parameter "x" and local variable "x" in the same scope ? Answer that first.I answered this before. The local variable is in the local var symtable and the parameter x is in the param symtable. These two symtables are independent entities in the symbol search hierachy and therefore are different scopes.
if your answer is "no", which would be obviously incorrect then, how do you explain that the compiler is stating there is a "duplicate identifier" ?It's not because the compiler uses the "duplicate identifier" for any kind of name collision, including when two symbols in the same scope have the same name, but also, as I have demonstrated above, if two symbols from different scopes violate the shadowing rules of the FPC.
You got some explaining to do. Try again.
I answered this before. The local variable is in the local var symtable and the parameter x is in the param symtable. These two symtables are independent entities in the symbol search hierachy and therefore are different scopes.No, you didn't answer then and the above is not an answer. I don't want implementation b.s.
Simple as that.
That's it. No more b.s., answer the question.
are different scopes.If you cannot comprehend 3 words and need me to boil it down to one, I can't help you.
I answered that question multiple times, and if you don't understand the answer thats not my problem.I understand, you want to hide your ignorance and mistakes under a thick coat of b.s.
I understand, you want to hide your ignorance and mistakes under a thick coat of b.s.You are the one avoiding to answer the questions. I gave you exactly what you ask for, I gave a clear definition of what a scope is and why from that definition it follows that parameters and variables are in a different scope.
I answered this before. The local variable is in the local var symtable and the parameter x is in the param symtable. These two symtables are independent entities in the symbol search hierachy and therefore are different scopes.It is irrelevant whether the local variable is in some symbol table or in Beijing.
Simple as that.
Read Per Brinch Hansen On Pascal Compilers. It covers the basics and, among other things, it explains scopes. The text is available online at Hansotten's Pascal web site but, I recommend you don't stop there. There is a lot more than what that introductory book covers.
I don't see any errors. :-[It is not the same situation as used by TS.
It is not the same situation as used by TS.
Where is this situation in the documentation?afaik it currently isn't described.
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.
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.)
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.
For the record, in the following code:Again this argument is just fallacious. Your argument is formalized: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.
procedure foo(x: Integer); var x: Double; begin end;
[...]
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.
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.
Re-read my previous post as many times as necessary.
2. With doesn't create a temporary object
Provably wrong with the fpc code creating a tempnode
Do you really believe your logical fallacies of not knowing the difference between implication and equivalence get less wrong when I read them again?As I previously stated: Do the world a favor, stop posting your garbage.
Like all claims you made were provably wrong
But then
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?
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
Hi, good explanation, that can apply to this the same?
with TStringList.Create do begin Free; end;
It's in the node tree. Looking at the fpc source:
2. With doesn't create a temporary object
Provably wrong with the fpc code creating a tempnode
There is a fundamental difference between. "With creates the temp variable" and "The compilers implementation for with has code that creates a temp variable."But the temporary variable is one of the key features of with. It is missing in the documentation of with (it currently only mentions variable expressions), but the fact that if the expression is non variable, a local copy of the result of that expression is created is really important to the semantics of with. It has two major effects:
There is a fundamental difference between. "With creates the temp variable" and "The compilers implementation for with has code that creates a temp variable."But the temporary variable is one of the key features of with. It is missing in the documentation of with (it currently only mentions variable expressions), but the fact that if the expression is non variable, a local copy of the result of that expression is created is really important to the semantics of with. It has two major effects:
1. The expression in with will always be evaluated, even if it is never used:
Besides, you did not show the complete code of the compiler. You showed code that creates a node for that temp var, but what about any code that later removes it (or the effects of it) again? So that looking at the compiler as a whole at the end of generating code for "with" there may not ("not always") be a temp var?Well then the question becomes what is a temporary object? Some memory object that's in the assembly? Does a register count? This discussion gets quite philosophical. So why not look at the context of my posts and what I actually described when saying this.
Feels like cheating? Because any optimizer business is a general business and not related to to "with" in particular? Well, its in line of saying the general "operating on the result" is not general when it happens within a "with" block. Or is it not?
program Project1; uses Classes, SysUtils; type TRecAB = record A: integer; B: integer; end; { TMyObj } TMyObj = class private TRecAB: TRecAB; public property rec: TRecAB read TRecAB write TRecAB; end; var Obj: TMyObj; begin Obj := TMyObj.Create; with Obj.rec do begin A := 10; B := 20; end; with Obj.rec do begin A := 15; end; writeln(Obj.rec.A); writeln(Obj.rec.B); readln; end.
A is 15 and B is 20 at the end. So it works fine for me...
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.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) :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.
program Project1; const HighInt64 = int64(int64(-1) shr 1); // Typed const type TTest = record V: int64; end; var X: TTest; function Test: TTest; begin Result := X; end; var i: qword; begin with Test do begin V := HighInt64; //No Error WriteLn(X.V, ' ', {With Test.}V); end; Readln; end.
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.)
The syntax is a little crazy. I'd do this instead
Type
Point_type = record
X, y: integer;
End;
Var
Point: point_type;
Function test(a,b:integer):integer;
Begin
Test := a+b;
End;
Begin
With point do
Begin
x := test(100,5);
y := test(5,5);
End;
End.
You have to code things in a way to improve readabilty so if you
have to go back a week, or a month later you won't be staring at
headlights like a deer.
Delphi nowadays forbids changing fields of a record that is a return value of a function to matter if with is used or not. Older Delphi versions did not, just like older FPC versions or TP did not. FPC nowadays forbids it directly for the function result, but not yet if the function result is captured in a with-statement. But that is only because that is simply not implemented in FPC, because it requires explicit code to forbid this and doesn't stem from the language itself.I just want to make sure I am interpreting the above corretly.
I think calling function with "with" whose result I can operate on is quite useful feature.Writable constants are useful too. Now, we have a language that allows assigning to a function result outside the function, it's useful, therefore... no problem!.
Delphi nowadays forbids changing fields of a record that is a return value of a function to matter if with is used or not. Older Delphi versions did not, just like older FPC versions or TP did not. FPC nowadays forbids it directly for the function result, but not yet if the function result is captured in a with-statement. But that is only because that is simply not implemented in FPC, because it requires explicit code to forbid this and doesn't stem from the language itself.I just want to make sure I am interpreting the above corretly.
Does the above mean that FPC will "eventually" forbid "changing fields of a record that is a return value of a function to matter if with is used or not." ?
A "yes" answer would definitely be encouraging.
I have no intention of re-igniting debates here, but I made a simple test, both with record and object. Both seem to work correctly.
This will stop working in the future, because the value returned by the functions (in your case GetRange and GetRangeObj) will only be temporary and won't propagate back to the original memory. So in that case one needs to explicitly capture the returned value in a variable and then use with. Users using this accidentally or wondering why it doesn't work the way they expect outweigh useful cases like this.
Have you ever heard the term "Bricking" / "Brick" ?You mean as in https://en.wikipedia.org/wiki/Brick_(electronics) (https://en.wikipedia.org/wiki/Brick_(electronics)) ?
Jamie
Speaking of readability: please use [code=pascal][/code] to improve readabililty and to avoid the forum software interpreting the code.
The answer is indeed yes. When is a different question however. 😅It's good to know assigning a result to a function outside the function itself will eventually be disallowed.
Some people aren't happy unless they can break something. With changes comes unintended behaviors and years to fix.Have you ever heard the term "Bricking" / "Brick" ?You mean as in https://en.wikipedia.org/wiki/Brick_(electronics) (https://en.wikipedia.org/wiki/Brick_(electronics)) ?
Jamie
If that's so, we need to make sure to never update to their trunk fantasies.
They are not even able to correctly multiply 2 currency values togehter correctly ...
That does not mean they get changed in the original source, they don't.Semantically, that code you posted shows that the values returned by the function are being changed. That's what that code means and that is not only wrong, it is non-sensical not to mention mathematically appalling.
The blind leading the blind. The destroyer of clean and easy syntax and bloat generator.+1
The blind leading the blind. The destroyer of clean and easy syntax and bloat generator.It's more like "the blind ignorants are whining about the future loss of their defective toy".... awwww... poor things!
Have a good day, I've had enough of this non-sense.
Jamie
Does the above mean that FPC will "eventually" forbid "changing fields of a record that is a return value of a function to matter if with is used or not." ?
The answer is indeed yes. When is a different question however. 😅
Of course, if such method calls are allowed, then the original issue remainsI just want to make sure I understand the pair of code snippets above correctly. In the first case, SetX invokes some code that changes the value of a field, obviously that is perfectly fine since no function result is being modified.
MyObject.PropertyWithGetterForSomeTPoint().SetX(42);
has exactly the same potential of confusion as
MyObject.PropertyWithGetterForSomeTPoint().X := 42;
Of course, if such method calls are allowed, then the original issue remainsI just want to make sure I understand the pair of code snippets above correctly. In the first case, SetX invokes some code that changes the value of a field, obviously that is perfectly fine since no function result is being modified.
MyObject.PropertyWithGetterForSomeTPoint().SetX(42);
has exactly the same potential of confusion as
MyObject.PropertyWithGetterForSomeTPoint().X := 42;
If the second piece of code is really/fully equivalent then "X" is not part of a function's result and, if it isn't then it's fine.
Did I interpret the code you showed correctly ?
neo luddism.+++ You're quite in an accurate sarcasm vein lately ...
Test.V := 1; //Error: Argument cannot be assigned to
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?
For example changing V changes the original X.
I know I can return the pointer, but is there any other way?
If the second piece of code is really/fully equivalent then "X" is not part of a function's result and, if it isn't then it's fine.
Did I interpret the code you showed correctly ?
So there is absolutely nothing that not allowing to set the field of a function result (with or without with) would prevent that is not otherwise already possible.
Somehow, the only replies I got where entirely offtopic to that question. :(My reply was more than anything an attempt to understand the behavior of the code you posted.
I merely was curious, because I do not see how this could easily be extended to cover *all* possible cases. And how it would affect method calls that could still do exactly the behaviour that is said to be of such misleading nature.
All I wanted to know is, if there was any comment on that.
No judgment if the planned change is good or not, or anything else. Merely: is it known to be incomplete, or are there ways (that I can not see) to make it complete?
I think it would be interesting to extend the concept of constness to methods, e.g. in C++ you can have the following:
This will stop working in the future, because the value returned by the functions (in your case GetRange and GetRangeObj) will only be temporary and won't propagate back to the original memory. So in that case one needs to explicitly capture the returned value in a variable and then use with. Users using this accidentally or wondering why it doesn't work the way they expect outweigh useful cases like this.
Will this also stop working in the future?
with TfrmVIES.Create(nil) do try ShowModal; finally Release; end;
Speaking of readability: please use [code=pascal][/code] to improve readabililty and to avoid the forum software interpreting the code.
The forum software is a compiler that will run code in a post?
PascalDragon, I confess I have not followed this thread closely because of the unpleasantness exhibited. But I do use TestOne below and would like you to assure me it is future safe.
program Project1; {$mode objfpc} type TaRec = record TheInt : integer; TheString : string; end; function Test() : TaRec; begin result.TheInt := 42; result.TheString := 'FortyTwo'; end; var aRec : TaRec; begin aRec := Test(); // Test One WriteLn('Test One TheInt ', aRec.TheInt); writeln('Test One TheString ', aRec.TheString); with Test() do begin // Test Two WriteLn('Test Two TheInt ', TheInt); writeln('Test Two TheString ', TheString); end; end.
yeah well, I have a rather large app that I was able to get fpc to compile that uses lots of code like this.
with GetNodeByIndex(1{one for now}) do begin NormalizeValues; if X = -1 then X := Adefault; //Constant for now but changes. if Y = -1 then Y := ADefault; //Place Null nodes to a common place. if Z = -1 then Z := ADefault; ProcessNode; // more code after this. end;
That function GetNodeByIndex returns a Record, in Delphi mode to get advanced records and as you can see, I have procedures, and I do change the values within.
That does not mean they get changed in the original source, they don't.
Does the above mean that FPC will "eventually" forbid "changing fields of a record that is a return value of a function to matter if with is used or not." ?
The answer is indeed yes. When is a different question however. 😅
Out of interest:
Is that "forbid direct assignment" or "forbid changing fields of ..."? Or where (and maybe how) will that line be drawn.
There it's assignments to fields and properties that are forbidden if the record (or object) is accessed using a with-statement directly capturing a function result.
QuoteThere it's assignments to fields and properties that are forbidden if the record (or object) is accessed using a with-statement directly capturing a function result.
Does this mean calling methods will be allowed?