Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2009-11

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

26 messages · 12 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Alexander Klenin
Hans-Peter Diettrich wrote 15 lines
Martin schrieb: > All fine and good. But it doesn't help, unless you convince the fpc > developers. Right :-( > Eventually the new Version of FPC will be used, and eventually all code > has to be able to be compiled with it.... I have several suggestions: - apply the new rules only in $mode Delphi - use an (global) switch to treat Inc/Dec as macros or operators - introduce new Incr/Decr macros, to reduce required editing of legacy code

IMHO:

1) The change was correct in the sense that all properies should be treated equally, regardless of their implementation. If that means (temporarily) loss of features, than so be it.

2) However, there is an obvious room for improvement here: not only Inc/Dec, but any procedure accepting var parameter should be able to accept writeable property of the same type. (especially common example is Include/Exclude for set properties)

For each property argument, the compiler should create temporary variable, set it by reading the property before the function call, and set property to the new value
after the call.

Inc(MyObj.MyIntProperty);
=>
var
  temp: Integer;
begin
  temp := MyObj.MyIntProperty;
  Inc(temp);
  MyObj.MyIntProperty := temp;
end;

Of course, if the compiler determines that the property is an alias for a field, it is free to pass the field directly -- but this is only an optimization.

Alexander S. Klenin

Reply by email

Paul Ishenin
to Alexander Klenin
Alexander Klenin wrote 10 lines
Inc(MyObj.MyIntProperty); => var temp: Integer; begin temp := MyObj.MyIntProperty; Inc(temp); MyObj.MyIntProperty := temp; end;

Property does not need to have a reader.

Best regards,
Paul Ishenin.

Reply by email

Martin
to Alexander Klenin: IMHO: 1) The change was correct in the sense that all properies should be treated…
Alexander Klenin wrote 28 lines
IMHO: 1) The change was correct in the sense that all properies should be treated equally, regardless of their implementation. If that means (temporarily) loss of features, than so be it. 2) However, there is an obvious room for improvement here: not only Inc/Dec, but any procedure accepting var parameter should be able to accept writeable property of the same type. (especially common example is Include/Exclude for set properties) For each property argument, the compiler should create temporary variable, set it by reading the property before the function call, and set property to the new value after the call. Inc(MyObj.MyIntProperty); => var temp: Integer; begin temp := MyObj.MyIntProperty; Inc(temp); MyObj.MyIntProperty := temp; end; Of course, if the compiler determines that the property is an alias for a field, it is free to pass the field directly -- but this is only an optimization

I had the same ideas once too.

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

Martin

Reply by email

Alexander Klenin
to Martin: I had the same ideas once too. The answer was that properties are meant to change the…
Martin wrote 5 lines
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. 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.

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.

Alexander S. Klenin

Reply by email

Mattias Gaertner
to Alexander Klenin: IMHO: 1) The change was correct in the sense that all properies should be treated…
[...] 2) However, there is an obvious room for improvement here: not only Inc/Dec, but any procedure accepting var parameter should be able to accept writeable property of the same type.

Var parameters must fit exactly for typecasts and pointers.

procedure DoIt(var i: integer);
begin
  DoSome(@i);
end;

This is not possible with a Setter function.

Show quoted text 20 lines
(especially common example is Include/Exclude for set properties) For each property argument, the compiler should create temporary variable, set it by reading the property before the function call, and set property to the new value after the call. Inc(MyObj.MyIntProperty); => var temp: Integer; begin temp := MyObj.MyIntProperty; Inc(temp); MyObj.MyIntProperty := temp; end; Of course, if the compiler determines that the property is an alias for a field, it is free to pass the field directly -- but this is only an optimization.

I guess this would be possible for compiler functions like inc.

Mattias

Reply by email

Marc Weustink
to Alexander Klenin: IMHO: 1) The change was correct in the sense that all properies should be treated…
Alexander Klenin wrote 14 lines
For each property argument, the compiler should create temporary variable, set it by reading the property before the function call, and set property to the new value after the call. Inc(MyObj.MyIntProperty); => var temp: Integer; begin temp := MyObj.MyIntProperty; Inc(temp); MyObj.MyIntProperty := temp; end;

At that time I proposed this too and there was a valid reason not to generate such code.

Marc

Reply by email

Graeme Geldenhuys
to Marc Weustink

2009/11/7 Marc Weustink :

At that time I proposed this too and there was a valid reason not to generate such code.

And that valid reason would be? I agree with Alexander and Mattias, why can't the compiler generate such code behind the scenes?

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/

Reply by email

Vincent Snijders
to Graeme Geldenhuys
Graeme Geldenhuys wrote 9 lines
2009/11/7 Marc Weustink : > At that time I proposed this too and there was a valid reason not to > generate such code. And that valid reason would be? I agree with Alexander and Mattias, why can't the compiler generate such code behind the scenes?

It is better to have this discussion on the fpc-pascal or fpc-devel mailing list. It is useless here, because Lazarus (and its developers) can not change this.

Vincent

Reply by email

Hans-Peter Diettrich
to Alexander Klenin: IMHO: 1) The change was correct in the sense that all properies should be treated…
Show quoted text 10 lines
IMHO: 1) The change was correct in the sense that all properies should be treated equally, regardless of their implementation. If that means (temporarily) loss of features, than so be it. 2) However, there is an obvious room for improvement here: not only Inc/Dec, but any procedure accepting var parameter should be able to accept writeable property of the same type. (especially common example is Include/Exclude for set properties)

ACK, all compiler magics deserve an update.

But that done, I still can see no change but code bloat :-(

All other cases, where var arguments are involved, cannot work with property references. If this was not handled properly in the past, i.e. when the field address was used for the reference, then this flaw could have been fixed with no impact on existing code.

DoDi

Reply by email

Hans-Peter Diettrich
to Paul Ishenin: Property does not need to have a reader. Paul Ishenin.
Show quoted text 12 lines
Alexander Klenin wrote: > Inc(MyObj.MyIntProperty); > => > var > temp: Integer; > begin > temp := MyObj.MyIntProperty; > Inc(temp); > MyObj.MyIntProperty := temp; > end; > Property does not need to have a reader.

A compiler magic can check for both read and write access to a property.

The above code can be reduced to what now has to be written in explicit source code:

   MyObj.MyIntproperty := MyObj.MyIntproperty + delta;

In this case the compiler would have issued a warning, when the property was read-only or write-only. Nothing changed by the new property handling.

DoDi

Reply by email

Hans-Peter Diettrich
to Martin: I had the same ideas once too. The answer was that properties are meant to change the…
Show quoted text 19 lines
> Inc(MyObj.MyIntProperty); > => > var > temp: Integer; > begin > temp := MyObj.MyIntProperty; > Inc(temp); > MyObj.MyIntProperty := temp; > end; > > Of course, if the compiler determines that the property is an alias > for a field, > it is free to pass the field directly -- but this is only an optimization I had the same ideas once too. 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).

This *also* will happen in the above code, when the temporary variable is loaded or stored.

When the compiler erroneously bypassed getters and setters in the past, this error could have been fixed in that place, without any further impact on existing (compiler and application) code.

DoDi

Reply by email

Hans-Peter Diettrich
to Alexander Klenin: I thought about that too. There are few counter-arguments here: Strictly speaking,…
Show quoted text 36 lines
> 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?

Show quoted text 6 lines
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.

Show quoted text 11 lines
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

Reply by email

Hans-Peter Diettrich
to Graeme Geldenhuys: 2009/11/7 Marc Weustink : And that valid reason would be? I agree with Alexander and…
Show quoted text 6 lines
> At that time I proposed this too and there was a valid reason not to > generate such code. And that valid reason would be? I agree with Alexander and Mattias, why can't the compiler generate such code behind the scenes?

IMO "such" code (with temporary variables) is not
the implementation of Inc() is changed into kind of a macro (with arguments), the compiler can expand Inc(x,y) into x:=x+y, and then all existing optimizations become applicable to that code. According to my experience with the C preprocessor I do *not* vote for macros with arguments, in general, but in the case of compiler magics a little bit more work would result in much more comfort to the users.

DoDi

Reply by email

Martin
to Alexander Klenin: I thought about that too. There are few counter-arguments here: Strictly speaking,…
Alexander Klenin wrote 15 lines
On Sat, Nov 7, 2009 at 14:15, Martin wrote: > 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

As I said it is not my argument, you better take it to the fpc list.

The one thing I may not have repeated clear enough: "expected to change"

Of course the setter is expected to change (at least a member variable).
So if your functions/procedure does
  MyProc(var SomeValueFromProertyasTempVar: integer);
 begin
    SomeValueFromProertyasTemp := 1;
    Foo();
 end

and Foo reads the property in question, then Foo sees the old value, even so it is expected to have changed already.

Reply by email

Alexander Klenin
to Hans-Peter Diettrich: Where would you place such temporary variables, in your sample code? Into an invisible…
Hans-Peter Diettrich wrote 5 lines
Alexander Klenin schrieb: > 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?

Eh... on the stack, as usual. I am not sure what do you mean by "invisible layer".

Show quoted text 9 lines
[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() :-]

Yes, passing property as var parameter. if implemented, would be a FPC-only extension.

Alexander S. Klenin

Reply by email

Marc Weustink
to Vincent Snijders: It is better to have this discussion on the fpc-pascal or fpc-devel mailing list. It is…
Vincent Snijders wrote 14 lines
Graeme Geldenhuys schreef: > 2009/11/7 Marc Weustink : >> At that time I proposed this too and there was a valid reason not to >> generate such code. > > > And that valid reason would be? I agree with Alexander and Mattias, > why can't the compiler generate such code behind the scenes? > > It is better to have this discussion on the fpc-pascal or fpc-devel mailing list. It is useless here, because Lazarus (and its developers) can not change this.

Also do a search on the fpc-devel list archive before continuing, iirc it was discussed there.
(if not then it was on core and I'll repost the reasons).

Marc

Reply by email

Marco van de Voort
to Alexander Klenin: IMHO: 1) The change was correct in the sense that all properies should be treated…
Alexander Klenin wrote 9 lines
1) The change was correct in the sense that all properies should be treated begin temp := MyObj.MyIntProperty; Inc(temp); MyObj.MyIntProperty := temp; end; Of course, if the compiler determines that the property is an alias for a field, it is free to pass the field directly -- but this is only an optimization.

This is not orthogonal. VAR parameters are generally updated instantaniously. By delaying the update over a temp variable you break another aspect of the VAR parameter.

IMHO such kludges only lead to more kludges.

Reply by email

Michael Van Canneyt
to Marco van de Voort
Marco van de Voort wrote 14 lines
On Sat, Nov 07, 2009 at 01:44:39PM +1000, Alexander Klenin wrote: > 1) The change was correct in the sense that all properies should be treated > begin > temp := MyObj.MyIntProperty; > Inc(temp); > MyObj.MyIntProperty := temp; > end; > > Of course, if the compiler determines that the property is an alias for a field, > it is free to pass the field directly -- but this is only an optimization. This is not orthogonal. VAR parameters are generally updated instantaniously. By delaying the update over a temp variable you break another aspect of the VAR parameter.

Not to mention the various reference counted objects: strings, interfaces, open arrays. Unexpected results abound...

Maybe we should put this question in the FAQ.

Michael.

Reply by email

Alexander Klenin
to Michael Van Canneyt
Michael Van Canneyt wrote 7 lines
On Sat, 7 Nov 2009, Marco van de Voort wrote: > This is not orthogonal. VAR parameters are generally updated > instantaniously. By delaying the update over a temp variable you break > another aspect of the VAR parameter. Not to mention the various reference counted objects: strings, interfaces, open arrays. Unexpected results abound...

What kind of unexpected results?

Alexander S. Klenin

Reply by email

Howard Page-Clark
to Alexander Klenin
> On Sat, 7 Nov 2009, Marco van de Voort wrote: >> This is not orthogonal. VAR parameters are generally updated >> instantaniously. By delaying the update over a temp variable you break >> another aspect of the VAR parameter.

I don't understand 'not orthogonal' in this sentence. What meaning does orthogonal have apart from 'being at right angles to' ?

Howard

Reply by email

Hans-Peter Diettrich
to Alexander Klenin: Eh... on the stack, as usual. I am not sure what do you mean by "invisible layer". Yes,…
Show quoted text 6 lines
>> 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? Eh... on the stack, as usual. I am not sure what do you mean by "invisible layer".

The var parameter already resides on the stack, when the procedure is invoked. Given that a var parameter is represented by a memory address, what should that address point to?

Show quoted text 11 lines
> [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() > :-] Yes, passing property as var parameter. if implemented, would be a FPC-only extension.

I'm pretty sure that such a feature will never come. It would be easier to implement macros with arguments, or generics, that allow for similar comfort in a more transparent way.

DoDi

Reply by email

Mehmet Erol Sanliturk
to Howard Page-Clark: On Sun, 8 Nov 2009 08:13:28 +1000 I don't understand 'not orthogonal' in this sentence.…
Howard Page-Clark wrote 15 lines
On Sun, 8 Nov 2009 08:13:28 +1000 Alexander Klenin wrote: >> On Sat, 7 Nov 2009, Marco van de Voort wrote: >>> This is not orthogonal. VAR parameters are generally updated >>> instantaniously. By delaying the update over a temp variable you break >>> another aspect of the VAR parameter. I don't understand 'not orthogonal' in this sentence. What meaning does orthogonal have apart from 'being at right angles to' ? Howard --

Any one of two orthogonal entities cannot be represented by using other one .

In a programming language it means an orthogonal sentence can not be expressed by using other sentences .

As a corollary < not orthogonal > means , it can be expressed by using other sentences .

Thank you very much .

Mehmet Erol Sanliturk

Reply by email

Marco van de Voort
to Howard Page-Clark: On Sun, 8 Nov 2009 08:13:28 +1000 I don't understand 'not orthogonal' in this sentence.…
Howard Page-Clark wrote 7 lines
> > On Sat, 7 Nov 2009, Marco van de Voort wrote: > >> This is not orthogonal. VAR parameters are generally updated > >> instantaniously. By delaying the update over a temp variable you break > >> another aspect of the VAR parameter. I don't understand 'not orthogonal' in this sentence. What meaning does orthogonal have apart from 'being at right angles to' ?

I'm not entirely sure where the phrase comes from (see also Mehmet), but I guess it has something to do with the axises in a Carthesian coordinate system, and from there dimensions (point,length,area,volume etc). A translation along one axis doesn't change the other in classic geometry.

Assume it came to indicate absence of side-effects from there.

Reply by email

Mehmet Erol Sanliturk
to Marco van de Voort
Marco van de Voort wrote 18 lines
On Sun, Nov 08, 2009 at 12:17:35AM +0000, Howard Page-Clark wrote: >>> On Sat, 7 Nov 2009, Marco van de Voort wrote: >>>> This is not orthogonal. VAR parameters are generally updated >>>> instantaniously. By delaying the update over a temp variable you break >>>> another aspect of the VAR parameter. > I don't understand 'not orthogonal' in this sentence. What meaning does > orthogonal have apart from 'being at right angles to' ? I'm not entirely sure where the phrase comes from (see also Mehmet), but I guess it has something to do with the axises in a Carthesian coordinate system, and from there dimensions (point,length,area,volume etc). A translation along one axis doesn't change the other in classic geometry. Assume it came to indicate absence of side-effects from there. --

If you search

orthogonality in programming language design

in www.yahoo.com , you may find many references , such as

http://en.wikipedia.org/wiki/Programming_language_design http://en.wikipedia.org/wiki/Orthogonality_(programming)

Design Criteria for a Language :
http://www.ist.rit.edu/~jdb/plc/wk1.pdf

Orthogonality in Language Design - Why and how to fake it : http://prog.vub.ac.be/~wdmeuter/PostJava/Herrmann.pdf

Compactness and Orthogonality :
http://catb.org/esr/writings/taoup/html/ch04s02.html

On orthogonality in programming languages :
http://portal.acm.org/citation.cfm?id=954246&dl=ACM&coll=portal&CFID=934114&CFTOKEN=43879943

The Art of Unix Programming :
( To design for compactness and orthogonality ... ) http://www.linuxtopia.org/online_books/programming_books/art_of_unix_programming/ch04s02_4.html

among many others .

Abundance of references show that orthogonality is a widely considered concept in programming language design .

As an example , the following statements are not orthogonal to each other :

( 1 ) if - go to
( 2 ) for
( 3 ) repeat
( 4 ) while
( 5 ) case

because any one of them may be expressed by the others , but

( 1 ) go to
( 2 ) := ( assignment )

are orthogonal because it is not possible to express any one of them by the other .

Thank you very much .

Mehmet Erol Sanliturk

Reply by email

Howard Page-Clark
to Mehmet Erol Sanliturk
Show quoted text 67 lines
Marco van de Voort wrote: > On Sun, Nov 08, 2009 at 12:17:35AM +0000, Howard Page-Clark wrote: >>>> On Sat, 7 Nov 2009, Marco van de Voort wrote: >>>>> This is not orthogonal. VAR parameters are generally updated >>>>> instantaniously. By delaying the update over a temp variable you break >>>>> another aspect of the VAR parameter. >> I don't understand 'not orthogonal' in this sentence. What meaning does >> orthogonal have apart from 'being at right angles to' ? > > I'm not entirely sure where the phrase comes from (see also Mehmet), but I > guess it has something to do with the axises in a Carthesian coordinate > system, and from there dimensions (point,length,area,volume etc). > A translation along one axis doesn't change the other in classic geometry. > > Assume it came to indicate absence of side-effects from there. If you search orthogonality in programming language design in www.yahoo.com , you may find many references , such as http://en.wikipedia.org/wiki/Programming_language_design http://en.wikipedia.org/wiki/Orthogonality_(programming) Design Criteria for a Language : http://www.ist.rit.edu/~jdb/plc/wk1.pdf Orthogonality in Language Design - Why and how to fake it : http://prog.vub.ac.be/~wdmeuter/PostJava/Herrmann.pdf Compactness and Orthogonality : http://catb.org/esr/writings/taoup/html/ch04s02.html On orthogonality in programming languages : http://portal.acm.org/citation.cfm?id=954246&dl=ACM&coll=portal&CFID=934114&CFTOKEN=43879943 The Art of Unix Programming : ( To design for compactness and orthogonality ... ) http://www.linuxtopia.org/online_books/programming_books/art_of_unix_programming/ch04s02_4.html among many others . Abundance of references show that orthogonality is a widely considered concept in programming language design . As an example , the following statements are not orthogonal to each other : ( 1 ) if - go to ( 2 ) for ( 3 ) repeat ( 4 ) while ( 5 ) case because any one of them may be expressed by the others , but ( 1 ) go to ( 2 ) := ( assignment ) are orthogonal because it is not possible to express any one of them by the other .

Thanks guys for your explanations.

Reply by email