Sign in Join

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

Mailing lists / fpc-devel / 2014-02

Class property and virtual getter

28 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

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

luiz americo pereira camara
TSimpleModel = class(TPersistent)
  protected
    class function GetResourceClient: IResourceClient; virtual;
    class property ResourceClient: IResourceClient read GetResourceClient;
  public
  end;

Trying to compile the above code i get the following error: Error: Illegal symbol for property access

Changing the GetResourceClient method from virtual to static works

Is this a bug or by design?

Luiz

Reply by email

Michael Van Canneyt
to luiz americo pereira camara
luiz americo pereira camara wrote 13 lines
TSimpleModel = class(TPersistent)   protected     class function GetResourceClient: IResourceClient; virtual;     class property ResourceClient: IResourceClient read GetResourceClient;   public   end; Trying to compile the above code i get the following error: Error: Illegal symbol for property access Changing the GetResourceClient method from virtual to static works Is this a bug or by design?

By design.

Michael.

Reply by email

Sven Barth
to luiz americo pereira camara: TSimpleModel = class(TPersistent) protected class function GetResourceClient:…
luiz americo pereira camara wrote 13 lines
TSimpleModel = class(TPersistent) protected class function GetResourceClient: IResourceClient; virtual; class property ResourceClient: IResourceClient read GetResourceClient; public end; Trying to compile the above code i get the following error: Error: Illegal symbol for property access Changing the GetResourceClient method from virtual to static works Is this a bug or by design?

As Michael said this is by design. If you want to use a non-static class procedure you must not use "class property", but only "property" (yes, that works).

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Sven Barth
Show quoted text 6 lines
> Changing the GetResourceClient method from virtual to static works > > Is this a bug or by design? As Michael said this is by design. If you want to use a non-static class procedure you must not use "class property", but only "property" (yes, that works).

So what's the special use of a *class* property? If it exists for Delphi compatibility only, why then is it handled differently from "property"?

DoDi

Reply by email

Michael Van Canneyt
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 11 lines
Sven Barth schrieb: >> Changing the GetResourceClient method from virtual to static works >> >> Is this a bug or by design? > As Michael said this is by design. If you want to use a non-static class > procedure you must not use "class property", but only "property" (yes, that > works). So what's the special use of a *class* property? If it exists for Delphi compatibility only, why then is it handled differently from "property"?

The reason is explained in the upcoming docs.

Namely: a static method cannot be overridden.
The class property is part of this particular class, and descendent classes should not be able to override it's behaviour.

Michael.

Reply by email

luiz americo pereira camara
to Sven Barth: As Michael said this is by design. If you want to use a non-static class procedure you…

2014-02-27 5:25 GMT-03:00 Sven Barth :

Show quoted text 9 lines
Am 27.02.2014 04:36, schrieb luiz americo pereira camara: Is this a bug or by design? > As Michael said this is by design. If you want to use a non-static class procedure you must not use "class property", but only "property" (yes, that works).

Thanks.

Removing class before property compiles. But if i try to access the property using TSimpleModel.ResourceClient gives the following error:

Error: Only class methods, class properties and class variables can be referred with class references

Technically there's some obstacle to allow such construct? Or is as today only to be delphi compatible?

Luiz

Reply by email

Hans-Peter Diettrich
to Michael Van Canneyt: The reason is explained in the upcoming docs. Namely: a static method cannot be…
Show quoted text 7 lines
> So what's the special use of a *class* property? If it exists for > Delphi compatibility only, why then is it handled differently from > "property"? The reason is explained in the upcoming docs. Namely: a static method cannot be overridden.

Sure, but virtual methods (including class methods) can be overridden.

The class property is part of this particular class, and descendent classes should not be able to override it's behaviour.

A static class method can call another virtual class method, so this protection looks very artifical to me.

BTW Delphi XE allows to call a virtual class method, but when called from a static class method it calls it like a static method, overrides are simply ignored. Calling the same method directly honors overrides.

Also "self" is no more known inside class methods in XE. In D7 it was the class type instead of the instance pointer. Thus a too restrictive compiler, geared towards compatibilitiy with *new* Delphi versions, may break existing code.

DoDi

Reply by email

Michael Van Canneyt
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 15 lines
Michael Van Canneyt schrieb: >> So what's the special use of a *class* property? If it exists for Delphi >> compatibility only, why then is it handled differently from "property"? > > The reason is explained in the upcoming docs. > > Namely: a static method cannot be overridden. Sure, but virtual methods (including class methods) can be overridden. > The class property is part of this particular class, and descendent classes > should not be able to override it's behaviour. A static class method can call another virtual class method,

No, it cannot. Try it.
It was explained to me using this exact example.

so this protection looks very artifical to me.

Nevertheless, this is the reason.

Michael.

Reply by email

Jonas Maebe
to luiz americo pereira camara: 2014-02-27 5:25 GMT-03:00 Sven Barth : Thanks. Removing class before property compiles.…
luiz americo pereira camara wrote 5 lines
Removing class before property compiles. But if i try to access the property using TSimpleModel.ResourceClient gives the following error: Error: Only class methods, class properties and class variables can be referred with class references

You have to declare an instance and then call its property. You don't have to instantiate the instance if the property maps to a class method.

Technically there's some obstacle to allow such construct?

Class properties should be accessible from within static class methods. Having them accessible depending on the getter/setter they use (static or not) would break orthogonality (the visibility/ usability must depend on the interface, not on the implementation of the interface).

Non-static class methods cannot be called from static class methods because you don't know the original class type that was used to call it (and hence this could have unexpected results).

Jonas

Reply by email

luiz americo pereira camara
to Jonas Maebe

2014-02-27 12:35 GMT-03:00 Jonas Maebe :

Show quoted text 7 lines
On 27 Feb 2014, at 12:40, luiz americo pereira camara wrote: Technically there's some obstacle to allow such construct? > Class properties should be accessible from within static class methods.

Got it.

Thanks

Luiz

Reply by email

Sven Barth
to Hans-Peter Diettrich: Sure, but virtual methods (including class methods) can be overridden. A static class…
Hans-Peter Diettrich wrote
Also "self" is no more known inside class methods in XE. In D7 it was the class type instead of the instance pointer. Thus a too restrictive compiler, geared towards compatibilitiy with *new* Delphi versions, may break existing code.

Source please. This compiles and runs without problems in XE:

=== source begin ===

type
   TTest = class
     class procedure Test;
   end;
class procedure TTest.Test;
begin
   Writeln(Self.ClassName);
end;
begin
   TTest.Test;
   Readln;
end.

=== source end ===

=== output begin ===

TTest

=== output end ===

It would be very strange if Embarcadero would have changed that.

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Michael Van Canneyt: No, it cannot. Try it. It was explained to me using this exact example. Nevertheless,…
Show quoted text 12 lines
>> The reason is explained in the upcoming docs. >> >> Namely: a static method cannot be overridden. > > Sure, but virtual methods (including class methods) can be overridden. > >> The class property is part of this particular class, and descendent >> classes should not be able to override it's behaviour. > > A static class method can call another virtual class method, No, it cannot. Try it. It was explained to me using this exact example.

Then I missed the "static;" directive in the posted example, added to the getter/setter methods. Delphi introduced that directive after D7, and I found no useful description for it yet. Now it looks to me as if we have to distinguish ordinary static (non-virtual) methods from explicit "static;" methods.

DoDi

Reply by email

Hans-Peter Diettrich
to Jonas Maebe: You have to declare an instance and then call its property. You don't have to instantiate…
Show quoted text 7 lines
> Error: Only class methods, class properties and class variables can be > referred with class references You have to declare an instance and then call its property. You don't have to instantiate the instance if the property maps to a class method. > Technically there's some obstacle to allow such construct?

As long as a method doesn't use Self, directly or implicitly, the absence of an object reference does not cause problems.

Class properties should be accessible from within static class methods. Having them accessible depending on the getter/setter they use (static or not) would break orthogonality (the visibility/usability must depend on the interface, not on the implementation of the interface).

This would mean that in legacy code the non-virtual methods have to be separated now, into non-virtual, static, class and static class methods, in order to keep the code compiling?

Non-static class methods cannot be called from static class methods because you don't know the original class type that was used to call it (and hence this could have unexpected results).

Does this mean that the new static class methods don't have an Self parameter?

DoDi

Reply by email

Hans-Peter Diettrich
to Sven Barth: Source please. This compiles and runs without problems in XE: === source begin === type…
Show quoted text 13 lines
Am 27.02.2014 15:35, schrieb Hans-Peter Diettrich: > Also "self" is no more known inside class methods in XE. In D7 it was > the class type instead of the instance pointer. Thus a too restrictive > compiler, geared towards compatibilitiy with *new* Delphi versions, > may break existing code. Source please. This compiles and runs without problems in XE: === source begin === type TTest = class class procedure Test; <--------- end;

When you add "static;", as required for class property getters/setters, the following won't compile:

class procedure TTest.Test; begin Writeln(Self.ClassName); end;

So the lack of "Self" seems to apply to "static;" methods, not to "class" methods. I'll ask in an EMBT group for a description of "static;", the OH seems to reflect the C++ meaning only, without mentioning the impact on OPL classes.

DoDi

Reply by email

Sven Barth
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 17 lines
Sven Barth schrieb: > Am 27.02.2014 15:35, schrieb Hans-Peter Diettrich: >> Also "self" is no more known inside class methods in XE. In D7 it was >> the class type instead of the instance pointer. Thus a too >> restrictive compiler, geared towards compatibilitiy with *new* Delphi >> versions, may break existing code. > Source please. This compiles and runs without problems in XE: > > === source begin === > > type > TTest = class > class procedure Test; <--------- > end; When you add "static;", as required for class property getters/setters, the following won't compile:

That's why I asked for source. The term "class methods" always implies "no static" while those with static are "static class methods".

Show quoted text 10 lines
> class procedure TTest.Test; > begin > Writeln(Self.ClassName); > end; So the lack of "Self" seems to apply to "static;" methods, not to "class" methods. I'll ask in an EMBT group for a description of "static;", the OH seems to reflect the C++ meaning only, without mentioning the impact on OPL classes.

A static class method is a method that is basically a normal global procedure/function that simply happens to be declared inside a class. They are even assignment compatible to normal procvars.

Regards,
Sven

Reply by email

Michael Schnell
to Hans-Peter Diettrich: When you add "static;", as required for class property getters/setters, the following…
Hans-Peter Diettrich wrote
So the lack of "Self" seems to apply to "static;" methods, not to "class" methods. I'll ask in an EMBT group for a description of "static;", the OH seems to reflect the C++ meaning only,

In ANSI C "static" with functions just means "unreachable from outside the current source file" (i.e. by the linker) (I always thought this is a silly name for that meaning.)

Is this different with C++ ?

-Michael

Reply by email

Sven Barth
to Michael Schnell
"Michael Schnell" wrote 5 lines
On 02/28/2014 02:18 AM, Hans-Peter Diettrich wrote: > > > So the lack of "Self" seems to apply to "static;" methods, not to

"class" methods. I'll ask in an EMBT group for a description of "static;", the OH seems to reflect the C++ meaning only,

In ANSI C "static" with functions just means "unreachable from outside

the current source file" (i.e. by the linker) (I always thought this is a silly name for that meaning.)

Is this different with C++ ?

In C++ classes you can have static methods that work like static class methods in FPC/Delphi (no "this", need to be called with TypeName::MethodName, can be used for function pointers).

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Michael Schnell: In ANSI C "static" with functions just means "unreachable from outside the current source…
Show quoted text 11 lines
On 02/28/2014 02:18 AM, Hans-Peter Diettrich wrote: > > So the lack of "Self" seems to apply to "static;" methods, not to > "class" methods. I'll ask in an EMBT group for a description of > "static;", the OH seems to reflect the C++ meaning only, In ANSI C "static" with functions just means "unreachable from outside the current source file" (i.e. by the linker) (I always thought this is a silly name for that meaning.) Is this different with C++ ?

Yes. Some C keywords have multiple different meanings in C++, depending on where they occur in source code.

DoDi

Reply by email

Michael Schnell
to Jonas Maebe: You have to declare an instance and then call its property. You don't have to instantiate…
Jonas Maebe wrote 11 lines
You have to declare an instance and then call its property. You don't have to instantiate the instance if the property maps to a class method. > Technically there's some obstacle to allow such construct? Class properties should be accessible from within static class methods. Having them accessible depending on the getter/setter they use (static or not) would break orthogonality (the visibility/usability must depend on the interface, not on the implementation of the interface).

I just came across the same issue and as well got the error "Only class methods, class properties and class variables can be referred with class references".

Hence I cant do "TmyClass.myProperty:=xyz;"
but I _can_ do "TmyClass.SetmyProperty(xyz);"
I in fact directly calling the "class" function that is denoted in the definition of the property.

Hence: I am allowed to use a class variable instead of a property, and I am allowed to call the setter class function, but I am not allowed to use the syntax candy provided by the property keyword.

In fact I don't see why this should make sense.

The error message suggest that it should be possible to define a "class property" similar to a class function. But this syntax seems to be illegal (says the appropriate error message).

-Michael

Reply by email

Michael Schnell
to Michael Schnell

I found out that I need to add "static" to the "get" class procedure to allow it's usage in a "class property".

Sorry for the noise :-[

If fact I don't understand what the additional "static" is necessary. I was of the op pinion that class procedures are static, anyway.

Can somebody clarify ?

Thanks,
-Michael

Reply by email

Ewald
to Michael Schnell
Michael Schnell wrote 8 lines
I found out that I need to add "static" to the "get" class procedure to allow it's usage in a "class property". Sorry for the noise :-[ If fact I don't understand what the additional "static" is necessary. I was of the op pinion that class procedures are static, anyway. Can somebody clarify ?

A `Class Procedure/Function XXX;` has a hidden parameter that points to the classtype. A `Class Procedure/Function XXX; static;` doesn't have this hidden parameter.

Ewald

Reply by email

Michael Schnell
to Ewald
Ewald wrote
A `Class Procedure/Function XXX;` has a hidden parameter that points to the classtype. A `Class Procedure/Function XXX; static;` doesn't have this hidden parameter.

I see.

The hidden parameter would be accessed as "Self" ?

Thanks for the explanation !

Now I came across a "class procedure xyz; virtual;" and was astonished that this does compile.

I suppose this means that the hidden parameter will point to the classtype of the child instead of the parent in a derived class.

correct ?

-Michael

Reply by email

Ewald
to Michael Schnell
Michael Schnell wrote 8 lines
On 05/26/2014 12:52 PM, Ewald wrote: > A `Class Procedure/Function XXX;` has a hidden parameter that points > to the classtype. A `Class Procedure/Function XXX; static;` doesn't > have this hidden parameter. > I see. The hidden parameter would be accessed as "Self" ?

Probably, I access it through `Classtype` (from TObject), as this gives me code that will still do the same thing if I remove the `Class` in front of the procedure/function.

Show quoted text 9 lines
Thanks for the explanation ! Now I came across a "class procedure xyz; virtual;" and was astonished that this does compile. I suppose this means that the hidden parameter will point to the classtype of the child instead of the parent in a derived class.

It does here (writes DoIt; on stdout):

===
Program Test;
{$mode objfpc}{$H+}
Type
    TTestClass = Class
    Public
        Class Procedure DoIt; virtual;
    End;
Class Procedure TTestClass.DoIt;
Begin
    WriteLn('DoIt;');
End;
Begin
    TTestClass.DoIt;
End.
===

Or am I missing something?

Ewald

Reply by email

Michael Schnell
to Ewald

I suppose this would work independently of virtual, as no "Self" is might be some work to do a test. It could e.g. use two siblings and detect if different classtype values are found in the two siblings.

-Michael

Reply by email

Sven Barth
to Michael Schnell
Michael Schnell wrote 5 lines
I suppose this would work independently of virtual, as no "Self" is involved at all. It might be some work to do a test. It could e.g. use two siblings and detect if different classtype values are found in the two siblings.

Here... happy now? ;)

=== code begin ===

program tclassvirtual;
{$mode objfpc}
type
   TBase = class
     class procedure Test; virtual;
   end;
   TSub1 = class(TBase)
     class procedure Test; override;
   end;
   TSub2 = class(TBase)
     class procedure Test; override;
   end;
   TBaseClass = class of TBase;
class procedure TBase.Test;
begin
   Writeln(Self.ClassName);
end;
class procedure TSub1.Test;
begin
   Writeln('TSub1');
   inherited;
end;
class procedure TSub2.Test;
begin
   Writeln('TSub2');
   inherited;
end;
var
   b: TBaseClass;
begin
   TBase.Test;
   TSub1.Test;
   TSub2.Test;
   b := TBase;
   b.Test;
   b := TSub1;
   b.Test;
   b := TSub2;
   b.Test;
end.

=== code end ===

=== output begin ===

TBase
TSub1
TSub1
TSub2
TSub2
TBase
TSub1
TSub1
TSub2
TSub2

=== output end ===

Regards,
Sven

Reply by email

Michael Schnell
to Sven Barth
Sven Barth wrote
Here... happy now? ;)

Very happy indeed :-) .

(Silly me did not remember the "ClassName" property. With same the test is as easy as you showed.)

Now thinking about why I had been confused is that obviously "self" of an instance _does_ determine the VMT of the class it is an instance of. That is why I erroneously assumed only an instance has a VMT. Now after learning that the VMT is provided already for the class itself seemingly as a static record, I wonder if the dynamic instance record has a just a pointer to the VMT of the class or if the classes VMT gets copied when creating an instance.

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 15 lines
On 05/26/2014 08:25 PM, Sven Barth wrote: > > Here... happy now? ;) Very happy indeed :-) . (Silly me did not remember the "ClassName" property. With same the test is as easy as you showed.) Now thinking about why I had been confused is that obviously "self" of an instance _does_ determine the VMT of the class it is an instance of. That is why I erroneously assumed only an instance has a VMT. Now after learning that the VMT is provided already for the class itself seemingly as a static record, I wonder if the dynamic instance record has a just a pointer to the VMT of the class or if the classes VMT gets copied when creating an instance.

AFAIK : Just a pointer to the correct VMT.

Michael.

Reply by email