[Lazarus] Passing properties as var paramatars (was: Delphi editor clone)

Hans-Peter Diettrich DrDiettrich1 at aol.com
Sat Nov 7 14:24:14 CET 2009


Alexander Klenin schrieb:

>> The answer was that properties are meant to change the value on the object
>> immediately. Also a property setter can raise an exception, or additional
>> actions can take place or the value can be substituted....
>> All this wouldn't happen with a temp variable (or at best deferred).
>> Therefore the behaviour would not be according to the rules of properties
> 
> I thought about that too. There are few counter-arguments here:
> 
> Strictly speaking, properties are not *meant* to change anything
> neither immediately nor
> in any other way. Assigning to a property with the setter is just a
> procedure call,
> and I do not think there exist any specification requiring the setter
> to change anything.
> 
> So it is important to understand that we are dealing here with "common
> sense" and "usual expectations",
> not with any formal requirement.
> 
> Now the question is, given the code:
> -----
> type T = class
>   ...
>   property P: Integer read GetP write SetP;
> end;
> 
> procedure MyInc2(var a: Integer); begin a := a + 1; a := a + 1; end;
> 
> var obj: T;
> begin
>   MyInc2(obj.P);
> end.
> -----
> 
> what is the *usual expectation* of the number of calls to GetP and SetP?
> Using temporary variables, there will be one call to each.

Where would you place such temporary variables, in your sample code? 
Into an invisible layer between the caller and MyInc2?

> It might be argued that some programmer might expect two calls to each,
> but I am really not sure if such programmer exists ;-)
> Moreover, if we assume the existence of such a hypothetical programmer,
> how could he implement MyInc2 to achieve the behaviour he expects?
> The answer is: he could not. It is impossible with or without the
> proposed extension.

I could follow your argumentation in an example like

   for i := 1 to obj.P do ...

where a C programmer would assume any number of calls to obj.GetP, while 
a Pascal programmer would be sure that obj.GetP is invoked only once, 
and the returned value is stored in a local variable.


> So we must conclude that the possible downside is relatively small.
> It must be weighted against the upside:
> 
> Components[ComponentIndex].Options :=
> Components[ComponentIndex].Options + [myOption];
> 
> vs
> 
> Include(Components[ComponentIndex].Options, myOption);
> 
> is, IMO, a very compelling argument.

Right :-)

But again, a C++ programmer would write a macro
   #define Inc2(x) {x += 2;}
and use it like
   Inc2(obj.P);
where a Pascal programmer would use the compiler magic
   Inc(obj.P,2);
because he cannot write macros, and the compiler should[1] do the job 
for him.

Unfortunately FPC did a lousy job in the past, using the field address 
(returned by @obj.P) to bypass the setter. Strange enough that FPC 
realized that a typed constant cannot be written to - it simply could 
have detected the same obstacle for a property. [I didn't realize these 
flaws until I did some testing just now]

[1] A quick comparison with Delphi 7 revealed:

Delphi notices that a property cannot be passed as a var parameter.

Delphi also denies Inc(obj.P), so that I have to adjust my opinion about 
the cleverness of Inc() :-(
[What does not influence my opinion about the *expected* behaviour of 
Inc() :-]

DoDi





More information about the Lazarus mailing list