Sign in Join

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

Mailing lists / fpc-devel / 2006-09

Language extension: absolute for classes

29 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

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

Micha Nelissen

Hi,

I want to bring up the following scenario: (need fixed font)

B --> G
| |
A --> F

All are classes, and usually A 'owns' F. So A has a field 'Field' of type F. Now, whenever A creates F, B overrides this (in virtual method or class type) to create a G.

The problem now is that every time B wants to access G, it has to typecast Field to G.

I want to propose something like:

type
  B = class(A)
  protected
    Field: G absolute Field;
    ...
  end;

Whenever the implementation of methods of B (or descendants of B) accesses Field, the compiler will use type G automatically, so that no typecast is necessary.

The compiler option -Criot might be used to check whether the type is actually the suggested type, in extension to the current behaviour where class typecasts are converted to 'as' under usage of this switch.

I realize that this is only a 'saving-typing' language extension, but it does save significant amounts of typing and would make the code more readable (IMHO).

It would be useful in the LCL: TLCLComponent.FWidgetSetClass which is a metaclasstype, and TWinControl (see wincontrol.inc:2053 for current typecast example), TEdit etc. want to use a descendant metaclasstype. It would also be useful in lNet: TLConnection has a FIterator which is a TLSocket, but descendants can choose to create descendants of TLSocket instead.

Opinions ?

Micha

Reply by email

Marco van de Voort
to Micha Nelissen
I realize that this is only a 'saving-typing' language extension, but it does save significant amounts of typing and would make the code more readable (IMHO).

You can achieve the same with generics ? Specialize a class with <T>=G ?

Reply by email

Christian Iversen
to Marco van de Voort
Marco van de Voort wrote 5 lines
> I realize that this is only a 'saving-typing' language extension, but it > does save significant amounts of typing and would make the code more > readable (IMHO). You can achieve the same with generics ? Specialize a class with <T>=G ?

Something similar can also be done with interfaces (but in this case, generics is probably a cleaner way to do it)

Regards, Christian Iversen

Reply by email

Micha Nelissen
to Marco van de Voort: You can achieve the same with generics ? Specialize a class with <T>=G ?
Marco van de Voort wrote 5 lines
> I realize that this is only a 'saving-typing' language extension, but it > does save significant amounts of typing and would make the code more > readable (IMHO). You can achieve the same with generics ? Specialize a class with <T>=G ?

No, because A needs an F, so A has already specialized it. Or I don't understand what you're proposing.

Micha

Reply by email

Michalis Kamburelis
to Micha Nelissen: I want to bring up the following scenario: (need fixed font) B --> G | | A --> F
Micah Milissent wrote 15 lines
Hi, I want to bring up the following scenario: (need fixed font) B --> G | | A --> F All are classes, and usually A 'owns' F. So A has a field 'Field' of type F. Now, whenever A creates F, B overrides this (in virtual method or class type) to create a G. The problem now is that every time B wants to access G, it has to typecast Field to G.

You don't need new language construction for this ?

All you want is just to cover in class B identifier "Field" of class A. So you should make "Field" a dummy function in class A (that just returns a field value), and then you can redefine function name in descendant classes. See the example below. Within the scope of class B the "Field" function will return class G.

---------
{$mode objfpc}
type
  TF = class
  end;
  TG = class(TF)
  end;
  TA = class
  private
    FField: TF;
  protected
    function Field: TF;
  end;
function TA.Field: TF;
begin
  Result := FField;
end;
type
  TB = class(TA)
  protected
    function Field: TG;
  end;
function TB.Field: TG;
begin
  Result := (inherited Field) as TG;
end;
begin
end.
---------

Michalis

Reply by email

Micha Nelissen
to Michalis Kamburelis
Michalis Kamburelis wrote 5 lines
All you want is just to cover in class B identifier "Field" of class A. So you should make "Field" a dummy function in class A (that just returns a field value), and then you can redefine function name in descendant classes. See the example below. Within the scope of class B the "Field" function will return class G.

This is a smart hack, at best. It's abuse of function syntax IMHO (as if they were fields). Second, you cannot assign to a function.

If the functions were inline, it could be as optimal, I agree; then you have essentially localized the typecast to one place.

I just want to tell the compiler what I can guarantee, but what it cannot automatically infer.

Thank you for the suggestion,

Micha

Reply by email

Michael Van Canneyt
to Micha Nelissen
Micha Nelissen wrote 17 lines
Michalis Kamburelis wrote: > All you want is just to cover in class B identifier "Field" of class A. > So you should make "Field" a dummy function in class A (that just > returns a field value), and then you can redefine function name in > descendant classes. See the example below. Within the scope of class B > the "Field" function will return class G. This is a smart hack, at best. It's abuse of function syntax IMHO (as if they were fields). Second, you cannot assign to a function. If the functions were inline, it could be as optimal, I agree; then you have essentially localized the typecast to one place. I just want to tell the compiler what I can guarantee, but what it cannot automatically infer. Thank you for the suggestion,

I don't think your solution is any cleaner than what he suggests. It's also a 'smart hack', after all. Just like in the old DOS days, when one would declare an array of bytes with 'absolute' at the location of the VGA or Hercules text screen card...

Just an opinion, of course...

Michael.

Reply by email

Micha Nelissen
to Michael Van Canneyt
Michael Van Canneyt wrote
I don't think your solution is any cleaner than what he suggests. It's also a 'smart hack', after all. Just like in the old DOS days,

Why?

when one would declare an array of bytes with 'absolute' at the location of the VGA or Hercules text screen card...

Hmm? You knew that at that location in memory (0xB800 was it ? :)) text is to be written in a certain format, so you tell the compiler that it is like that. Why is this a hack ?

Micha

Reply by email

Daniël Mantione
to Michael Van Canneyt: I don't think your solution is any cleaner than what he suggests. It's also a 'smart…

Op Sun, 1 Oct 2006, schreef Michael Van Canneyt:

Show quoted text 28 lines
On Sun, 1 Oct 2006, Micha Nelissen wrote: > Michalis Kamburelis wrote: > > All you want is just to cover in class B identifier "Field" of class A. > > So you should make "Field" a dummy function in class A (that just > > returns a field value), and then you can redefine function name in > > descendant classes. See the example below. Within the scope of class B > > the "Field" function will return class G. > > This is a smart hack, at best. It's abuse of function syntax IMHO (as if > they were fields). Second, you cannot assign to a function. > > If the functions were inline, it could be as optimal, I agree; then you > have essentially localized the typecast to one place. > > I just want to tell the compiler what I can guarantee, but what it > cannot automatically infer. > > Thank you for the suggestion, I don't think your solution is any cleaner than what he suggests. It's also a 'smart hack', after all. Just like in the old DOS days, when one would declare an array of bytes with 'absolute' at the location of the VGA or Hercules text screen card... Just an opinion, of course...

Well... You can do absolute in procedures:

var b:byte;
    c:char absolute b;

Now, you can consider this bad programming, but it is just a lowlevel trick. It is the addition of low level functions that was the key in making Pascal suitable for real world use.

Now, if absolute is allowed in procedures, is there a good reason to forbid it in classes? I.e. what is fundamentally bad about...

type   t=class
         b:byte;
         c:char absolute b;
       end;

?

The use of specialization is interresting:

type   t=class
         a:Tabractclass;
         b:Tspecialized_class absolute a;
       end;

Using b, instead of a, provides in certain operations like calling inherited methods, provides extra information to the compiler. It'll be interresting to think wether it is theoretically possible to do extra optimizations using this information.

Daniël

Reply by email

Michael Van Canneyt
to Micha Nelissen: Why? Hmm? You knew that at that location in memory (0xB800 was it ? :)) text is to be…
Micha Nelissen wrote 10 lines
Michael Van Canneyt wrote: > I don't think your solution is any cleaner than what he suggests. > It's also a 'smart hack', after all. Just like in the old DOS days, Why? > when one would declare an array of bytes with 'absolute' at the > location of the VGA or Hercules text screen card... Hmm? You knew that at that location in memory (0xB800 was it ? :))

Yep. and 0xB000 for Hercules... :-)

text is to be written in a certain format, so you tell the compiler that it is like that. Why is this a hack ?

Because you do a typecast just as if you would override a property using a read specifier and do the typecast there. Just the typecast is disguised as an 'absolute'...

But don't get me wrong, I'm not opposing this.

Michael.

Reply by email

Michael Van Canneyt
to Daniël Mantione: Op Sun, 1 Oct 2006, schreef Michael Van Canneyt: Well... You can do absolute in…
Daniël Mantione wrote 63 lines
Op Sun, 1 Oct 2006, schreef Michael Van Canneyt: > > > On Sun, 1 Oct 2006, Micha Nelissen wrote: > > > Michalis Kamburelis wrote: > > > All you want is just to cover in class B identifier "Field" of class A. > > > So you should make "Field" a dummy function in class A (that just > > > returns a field value), and then you can redefine function name in > > > descendant classes. See the example below. Within the scope of class B > > > the "Field" function will return class G. > > > > This is a smart hack, at best. It's abuse of function syntax IMHO (as if > > they were fields). Second, you cannot assign to a function. > > > > If the functions were inline, it could be as optimal, I agree; then you > > have essentially localized the typecast to one place. > > > > I just want to tell the compiler what I can guarantee, but what it > > cannot automatically infer. > > > > Thank you for the suggestion, > > I don't think your solution is any cleaner than what he suggests. > It's also a 'smart hack', after all. Just like in the old DOS days, > when one would declare an array of bytes with 'absolute' at the > location of the VGA or Hercules text screen card... > > Just an opinion, of course... Well... You can do absolute in procedures: var b:byte; c:char absolute b; Now, you can consider this bad programming, but it is just a lowlevel trick. It is the addition of low level functions that was the key in making Pascal suitable for real world use. Now, if absolute is allowed in procedures, is there a good reason to forbid it in classes? I.e. what is fundamentally bad about... type t=class b:byte; c:char absolute b; end; ? The use of specialization is interresting: type t=class a:Tabractclass; b:Tspecialized_class absolute a; end; Using b, instead of a, provides in certain operations like calling inherited methods, provides extra information to the compiler. It'll be interresting to think wether it is theoretically possible to do extra optimizations using this information.

For clarity:
I am not opposing it, but I do consider it a dirty trick in both cases...

Michael.

Reply by email

Marco van de Voort
to Michael Van Canneyt
Show quoted text 5 lines
On Sun, 1 Oct 2006, Dani?l Mantione wrote: For clarity: I am not opposing it, but I do consider it a dirty trick in both cases...

Hmm, I don't think neli's one is that dirty, more exotic syntactic sugar. Yes it happens with the composition pattern, but is it really worth inventing new syntax for?

Reply by email

Micha Nelissen
to Michael Van Canneyt: Yep. and 0xB000 for Hercules... :-) Because you do a typecast just as if you would…
Michael Van Canneyt wrote 6 lines
> is to be written in a certain format, so you tell the compiler that it > is like that. Why is this a hack ? Because you do a typecast just as if you would override a property using a read specifier and do the typecast there. Just the typecast is disguised as an 'absolute'...

In this case I'm doing a typecast because the compiler is too 'stupid', so the motivation for the typecast is different than in the general case.

I have been thinking of another way, but it's more involved, but also 'more correct'. The class A would specify for the 'Field: F' that it has an overrideable type, maybe keyword 'virtual' or so. The compiler will store the type in the RTTI of the class. Then, B can override the type, and the compiler will rewrite the needed type (G) into the RTTI. Then at runtime, whenever an assignment to A.Field is done, the compiler will generate code that retrieves from the RTTI the 'needed' type, and will check the type of the rightside expression to that needed type, like 'as' operator does.

Micha

Reply by email

Michael Van Canneyt
to Marco van de Voort: Hmm, I don't think neli's one is that dirty, more exotic syntactic sugar. Yes it happens…
Marco van de Voort wrote 9 lines
> On Sun, 1 Oct 2006, Dani?l Mantione wrote: > > For clarity: > I am not opposing it, but I do consider it a dirty trick in both cases... Hmm, I don't think neli's one is that dirty, more exotic syntactic sugar. Yes it happens with the composition pattern, but is it really worth inventing new syntax for?

What new syntax are you referring to ? You mean the 'absolute' ? I don't think so...

Michael.

Reply by email

Marco van de Voort
to Michael Van Canneyt
Show quoted text 14 lines
On Sun, 1 Oct 2006, Marco van de Voort wrote: > > On Sun, 1 Oct 2006, Dani?l Mantione wrote: > > > > > For clarity: > > I am not opposing it, but I do consider it a dirty trick in both cases... > > Hmm, I don't think neli's one is that dirty, more exotic syntactic sugar. > Yes it happens with the composition pattern, but is it really worth > inventing new syntax for? What new syntax are you referring to ? You mean the 'absolute' ? I don't think so...

Depends on implementation. Do you really implement absolute as with same memoryspace here too, or only allow type upgrading (which is the major reason for such feature)?

Reply by email

Micha Nelissen
to Marco van de Voort
Marco van de Voort wrote 6 lines
> What new syntax are you referring to ? You mean the 'absolute' ? > I don't think so... Depends on implementation. Do you really implement absolute as with same memoryspace here too, or only allow type upgrading (which is the major reason for such feature)?

Changing type to something which is not a descendant (and thus incompatible) seems useless and always dangerous to me, so should be forbidden if possible.

Micha

Reply by email

Marco van de Voort
to Micha Nelissen
Show quoted text 11 lines
Marco van de Voort wrote: >> What new syntax are you referring to ? You mean the 'absolute' ? >> I don't think so... > > Depends on implementation. Do you really implement absolute as with same > memoryspace here too, or only allow type upgrading (which is the major > reason for such feature)? Changing type to something which is not a descendant (and thus incompatible) seems useless and always dangerous to me, so should be forbidden if possible.

I also considered it that way. But maybe the "absolute" keyword is then a bit badly chosen, since it implies memory overlaying, no questions asked.

Reply by email

Micha Nelissen
to Marco van de Voort
Marco van de Voort wrote 6 lines
> Changing type to something which is not a descendant (and thus > incompatible) seems useless and always dangerous to me, so should be > forbidden if possible. I also considered it that way. But maybe the "absolute" keyword is then a bit badly chosen, since it implies memory overlaying, no questions asked.

Yes, agree, but the way of use is so similar. Maybe the other usages should get this checking as well ;-).

Maybe 'override' instead, but that one is so closely tied to functions, and implies something 'virtual' as well.

Micha

Reply by email

Michael Van Canneyt
to Micha Nelissen: In this case I'm doing a typecast because the compiler is too 'stupid', so the motivation…
Micha Nelissen wrote 20 lines
Michael Van Canneyt wrote: >> is to be written in a certain format, so you tell the compiler that it >> is like that. Why is this a hack ? > > Because you do a typecast just as if you would override a property using a > read specifier and do the typecast there. Just the typecast is disguised > as an 'absolute'... In this case I'm doing a typecast because the compiler is too 'stupid', so the motivation for the typecast is different than in the general case. I have been thinking of another way, but it's more involved, but also 'more correct'. The class A would specify for the 'Field: F' that it has an overrideable type, maybe keyword 'virtual' or so. The compiler will store the type in the RTTI of the class. Then, B can override the type, and the compiler will rewrite the needed type (G) into the RTTI. Then at runtime, whenever an assignment to A.Field is done, the compiler will generate code that retrieves from the RTTI the 'needed' type, and will check the type of the rightside expression to that needed type, like 'as' operator does.

I'm more in favour of this approach, actually.
But I would do it at the property level, not at the field level. And only for classes.

Michael.

Reply by email

Michael Van Canneyt
to Micha Nelissen: Yes, agree, but the way of use is so similar. Maybe the other usages should get this…
Micha Nelissen wrote 13 lines
Marco van de Voort wrote: >> Changing type to something which is not a descendant (and thus >> incompatible) seems useless and always dangerous to me, so should be >> forbidden if possible. > > I also considered it that way. But maybe the "absolute" keyword is then a > bit badly chosen, since it implies memory overlaying, no questions asked. Yes, agree, but the way of use is so similar. Maybe the other usages should get this checking as well ;-). Maybe 'override' instead, but that one is so closely tied to functions, and implies something 'virtual' as well.

If you do it for fields of class type only, then I think this is OK. Declare the field as virtual, and require it to be 'overridden' in the descendent class.

Michael.

Reply by email

Micha Nelissen
to Michael Van Canneyt
Michael Van Canneyt wrote
If you do it for fields of class type only, then I think this is OK. Declare the field as virtual, and require it to be 'overridden' in the descendent class.

Why is there a need to declare fields virtual ?

Micha

Reply by email

Micha Nelissen
to peter green
peter green wrote 5 lines
> Changing type to something which is not a descendant (and thus > incompatible) seems useless and always dangerous to me, so should be > forbidden if possible. useless yes, dangerous if not carefull yes but its the number one way for bypassing "protected" ;)

"protected" as in language (type) protection ?

Micha

Reply by email

Daniël Mantione
to Michael Van Canneyt: Because you want to override it. It's a flag for the compiler that this is allowed.…

Op Sun, 1 Oct 2006, schreef Michael Van Canneyt:

Show quoted text 14 lines
On Sun, 1 Oct 2006, Micha Nelissen wrote: > Michael Van Canneyt wrote: > > If you do it for fields of class type only, then I think this is OK. > > Declare the field as virtual, and require it to be 'overridden' in the > > descendent class. > > Why is there a need to declare fields virtual ? Because you want to override it. It's a flag for the compiler that this is allowed. Otherwise you could override just about any field in a descendent class, which is not what you want, I think ?

Actually I don't see the need. A descendent class can already be used in any situation where the parent is used, so there is no need to explicitely specify this.

Daniël

Reply by email

Michael Van Canneyt
to Micha Nelissen: Why is there a need to declare fields virtual ? Micha
Micha Nelissen wrote 6 lines
Michael Van Canneyt wrote: > If you do it for fields of class type only, then I think this is OK. > Declare the field as virtual, and require it to be 'overridden' in the > descendent class. Why is there a need to declare fields virtual ?

Because you want to override it. It's a flag for the compiler that this is allowed. Otherwise you could override just about any field in a descendent class, which is not what you want, I think ?

You don't know what descendent classes can be created, after all.

Michael.

Reply by email

peter green
to Micha Nelissen: "protected" as in language (type) protection ? Micha
Show quoted text 18 lines
-----Original Message----- From: Behalf Of Micha Nelissen Sent: 01 October 2006 21:41 To: FPC developers' list Subject: Re: [fpc-devel] Language extension: absolute for classes peter green wrote: >> Changing type to something which is not a descendant (and thus >> incompatible) seems useless and always dangerous to me, so should be >> forbidden if possible. > useless yes, dangerous if not carefull yes but its the number one way for > bypassing "protected" ;) "protected" as in language (type) protection ?

protected as in the protected modifier for stuff in a class which is hugely overused in the vcl.

Reply by email

Michalis Kamburelis
to Micha Nelissen: This is a smart hack, at best. It's abuse of function syntax IMHO (as if they were…
Micha Nelissen wrote 16 lines
Michalis Kamburelis wrote: > All you want is just to cover in class B identifier "Field" of class A. > So you should make "Field" a dummy function in class A (that just > returns a field value), and then you can redefine function name in > descendant classes. See the example below. Within the scope of class B > the "Field" function will return class G. This is a smart hack, at best. It's abuse of function syntax IMHO (as if they were fields). Second, you cannot assign to a function. If the functions were inline, it could be as optimal, I agree; then you have essentially localized the typecast to one place. I just want to tell the compiler what I can guarantee, but what it cannot automatically infer.

It can be done for properties too. And I agree, this can be considered an "abuse" but not of the function syntax. It's an abuse of the rule that you can always hide identifiers of parent class in a subclass. Virtual methods are a typical clean solution to similar problems, but in this case you want to change the method/property interface so we're left with this unclean solution.

BTW That's why I agree with the cleaner approach of "overriding properties" later in this thread.

Example below shows the same trick working for properties. Here "Field" is a read/write property.

-----------
{$mode objfpc}
type
  TF = class
  end;
  TG = class(TF)
  end;
  TA = class
  private
    FField: TF;
  protected
    property Field: TF read FField write FField;
  end;
  TB = class(TA)
  private
    function GetField: TG;
    procedure SetField(Value: TG);
  protected
    property Field: TG read GetField write SetField;
  end;
function TB.GetField: TG;
begin
  Result := (inherited Field) as TG;
end;
procedure TB.SetField(Value: TG);
begin
  (inherited Field) := Value;
end;
begin
end.
-------

Michalis

Reply by email

Micha Nelissen
to peter green: protected as in the protected modifier for stuff in a class which is hugely overused in…
peter green wrote 6 lines
>> bypassing "protected" ;) > "protected" as in language (type) protection ? protected as in the protected modifier for stuff in a class which is hugely overused in the vcl. From memory, most fields in the VCL are private, not protected. I don't

think absolute will, or should, change visibility rules. I.e. you can't 'overlay' a private member of a parent class.

Micha

Reply by email

Bram Kuijvenhoven
to Micha Nelissen: Yes, agree, but the way of use is so similar. Maybe the other usages should get this…
Micha Nelissen wrote 12 lines
Marco van de Voort wrote: >> Changing type to something which is not a descendant (and thus >> incompatible) seems useless and always dangerous to me, so should be >> forbidden if possible. > I also considered it that way. But maybe the "absolute" keyword is then a > bit badly chosen, since it implies memory overlaying, no questions asked. Yes, agree, but the way of use is so similar. Maybe the other usages should get this checking as well ;-). Maybe 'override' instead, but that one is so closely tied to functions, and implies something 'virtual' as well.

Another suggestion: 'specialize'.

Regardless of the syntaxis, I'd like to have this feature very much as well. In my major FPC project it could save a lot of typecasts.

To be more specific: I have two similar class hierarchies, where each class in the second has a field refer to its 'conjugate' class in the first hierarchy. Like

type
  TA = class end;
  TB = class(TA) end;
  TAConjugate = class Conjugate:TA; end;
  TBConjugate = class(TAConjugate) end;

I'd like to be able to write instead one of

  TBConjugate = class(TAConjugate) Conjugate:TB; end;
  TBConjugate = class(TAConjugate) Conjugate:TB; override; end;
  TBConjugate = class(TAConjugate) Conjugate:TB; specialize; end;
  ... (other syntaxis) ...

One small request: if time and resources are conflicting, please finish generic support before going into this ;) Generics are needed much harder (for type safety/reducing type casts).

Regards,

Bram

Reply by email