Sign in Join

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

Mailing lists / lazarus / 2013-02

"global" operator overloading

27 messages · 9 people · –

Reply by email Subscribe to this list Your subscription

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

xrfang

Hi There,

Days ago I posted a message about compiling error related to operator overloading. I found the reason now, but don't know how to fix that. ?The code is:

=========

uses Classes, treap;
type
? TSLCounter = specialize TTreap<TStringList, Integer>;
operator <(sl1, sl2: TStringList): Boolean;

=========

The compiler complains about "<" is not defined for string list. ?If I put the operator overloading into treap.pas, there is no problem.

Is there anyway to avoid this dilemma? ?Because I don't want treap.pas to "reversely" rely on a specialized class.

Thanks,
Shannon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130226/8f84e680/attachment.html>

Reply by email

leledumbo
to xrfang
Is there anyway to avoid this dilemma? Because I don't want treap.pas to

"reversely" rely on a specialized class.

No, it's not a dilemma, but rather a requirement. Before generics specialization, all required operations for given type must be known. This is because the symbol table when the generics is parsed must be reconstructed when it gets specialized. Think about declaring usual classes with the generic parameter replaced with actual type. If at that time, the operation < is not yet defined, the code won't compile anyway.

View this message in context: http://free-pascal-lazarus.989080.n3.nabble.com/Lazarus-global-operator-overloading-tp4029446p4029447.html Sent from the Free Pascal - Lazarus mailing list .

Reply by email

xrfang
to leledumbo

No, it's not a dilemma, but rather a requirement. Before generics specialization, all required operations for given type must be known. This is because the symbol table when the generics is parsed must be reconstructed when it gets specialized. Think about declaring usual classes with the generic parameter replaced with actual type. If at that time, the operation < is not yet defined, the code won't compile anyway.

It is a pity. I think if fpc supports class operators, maybe this problem could be solved by using class helpers (my purpose is that users of ttreap class does not have to modify treap.pas) ? Is that possible in future FPC?

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130226/ab9fe682/attachment.html>

Reply by email

Sven Barth
to xrfang
"xrfang" wrote
> > No, it's not a dilemma, but rather a requirement. Before generics > specialization, all required operations for given type must be known.

This

> is because the symbol table when the generics is parsed must be > reconstructed when it gets specialized. Think about declaring usual

classes

> with the generic parameter replaced with actual type. If at that time,

the

> operation < is not yet defined, the code won't compile anyway. It is a pity. I think if fpc supports class operators, maybe this problem

could be solved by using class helpers (my purpose is that users of ttreap class does not have to modify treap.pas) ? Is that possible in future FPC?

Helpers have the same problem. For now there is only one solution (as I already wrote): require that the type with which you specialize is a record. Then a class operator in that record can be defined.

For the future I already have the following longterm plans:
- add class operator support to class and object
- allow to specify additional units after "specialize" that will be used when specializing (they will be added first, so that the original code is not unnecessarily modified)

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130226/66a956c3/attachment.html>

Reply by email

Xiangrong Fang
to Sven Barth

Hi Sven,

Could you please give a simple example that shows what you said: require that the type with which you specialize is a record. Then a class operator in that record can be defined.

Thanks

2013/2/26 Sven Barth

Show quoted text 39 lines
Am 26.02.2013 08:59 schrieb "xrfang" : >> >> No, it's not a dilemma, but rather a requirement. Before generics >> specialization, all required operations for given type must be known. This >> is because the symbol table when the generics is parsed must be >> reconstructed when it gets specialized. Think about declaring usual classes >> with the generic parameter replaced with actual type. If at that time, the >> operation < is not yet defined, the code won't compile anyway. > > > It is a pity. I think if fpc supports class operators, maybe this problem could be solved by using class helpers (my purpose is that users of ttreap class does not have to modify treap.pas) ? Is that possible in future FPC? Helpers have the same problem. For now there is only one solution (as I already wrote): require that the type with which you specialize is a record. Then a class operator in that record can be defined. For the future I already have the following longterm plans: - add class operator support to class and object - allow to specify additional units after "specialize" that will be used when specializing (they will be added first, so that the original code is not unnecessarily modified) Regards, Sven -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130226/990a9e9d/attachment-0001.html>

Reply by email

Michael Schnell
to Sven Barth: This classes the could be solved by using class helpers (my purpose is that users of…
Sven Barth wrote 12 lines
Helpers have the same problem. For now there is only one solution (as I already wrote): require that the type with which you specialize is a record. Then a class operator in that record can be defined. For the future I already have the following longterm plans: - add class operator support to class and object - allow to specify additional units after "specialize" that will be used when specializing (they will be added first, so that the original code is not unnecessarily modified)

Here a "funny" question come up:

Why do we (still) have records at all ?

We do have classes that allow for static and/or virtual methods (of course no methods at all are possible, too. )

So why are record that now can have more than none methods. The only difference I see is that records can reside in other places than on the heap. But (if necessary) a certain type of class seems more straight forward to me (of course with "record" as a synonym for compatibility) .

AFAIK even old style Turbo-Pascal "Objects" are still in place.... That could be a certain type of class as well.

-Michael

Reply by email

Sven Barth
to Xiangrong Fang: Could you please give a simple example that shows what you said: require that the type…
Xiangrong Fang wrote 5 lines
Hi Sven, Could you please give a simple example that shows what you said: require that the type with which you specialize is a record. Then a class operator in that record can be defined.

Let's suppose you have the following generic declaration:

=== example begin ===

type
   generic TTreap<T1, T2> = class
     // let's assume T1 requires "<"
   end;

=== example end ===

If you use a record to specialize TTreap's T1 parameter then you can do it the following way:

=== example begin ===

type
   TMyRecord = record
     // note: in mode objfpc the modeswitch advancedrecords is needed
     class operator < (aLeft, aRight: TMyRecord): Boolean;
   end;
// implementation:
class operator TMyRecord.<(aLeft, aRight: TMyRecord): Boolean;
begin
   // compare aLeft and aRight
end;
// somewhere else
TTreapTMyRecordLongInt = specialize TTreap<TMyRecord, LongInt>;

=== example end ===

Now the generic will specialize without problem. If you want to specialize other types that don't support class operators then you need to wrap them inside a record, e.g.:

=== example begin ===

type
   TRecTStringList = record
     MyStringList: TStringList;
     class operator < (aLeft, aRight: TRecTStringList): Boolean;
   end;

=== example end ===

You can also use visibility modifiers like private or strict private to hide the MyStringList field and make it accessible only through properties. To simplyfy usage you can also define assignment operators. E.g.:

=== example begin ===

type
   // maybe it will also work with a TStringList if you use TStrings
instead...
   TRecTStringList = record
   private
     fStringList: TStringList;
   public
     class operator := (aRight: TStringList): TRecTStringList;
     class operator := (aRight: TRecStringList): TStringList;
   end;
class operator TRecTStringList.:=(aRight: TStringList): TRecTStringList;
begin
   Result.fStringList := aRight;
end;
class operator TRecTStringList.:=(aRight: TRecStringList): TStringList;
begin
   Result := aRight.fStringList;
end;
// somewhere else:
var
   sl: TStringList;
   rec: TRecStringList;
begin
   // setup sl
   rec := sl;
   // use rec in the tree
   sl := rec;
end;

=== example end ===

It's not the nicest solution, but currently the only thing you can do.

Regards,
Sven

Reply by email

Sven Barth
to Michael Schnell: Here a "funny" question come up: Why do we (still) have records at all ? We do have…
Michael Schnell wrote 25 lines
On 02/26/2013 09:07 AM, Sven Barth wrote: > > Helpers have the same problem. For now there is only one solution (as > I already wrote): require that the type with which you specialize is a > record. Then a class operator in that record can be defined. > > For the future I already have the following longterm plans: > - add class operator support to class and object > - allow to specify additional units after "specialize" that will be > used when specializing (they will be added first, so that the original > code is not unnecessarily modified) > > Here a "funny" question come up: Why do we (still) have records at all ? We do have classes that allow for static and/or virtual methods (of course no methods at all are possible, too. ) So why are record that now can have more than none methods. The only difference I see is that records can reside in other places than on the heap. But (if necessary) a certain type of class seems more straight forward to me (of course with "record" as a synonym for compatibility) .

The critical difference between records and classes besides the ability of records to reside on the stack is that they don't allow inheritance and they support variable parts. The "don't allow inheritance" is important, because otherwise you'll have a certain overhead like virtual method resolution.

AFAIK even old style Turbo-Pascal "Objects" are still in place.... That could be a certain type of class as well.

Yes, objects still exist as well and I still don't really understand why Borland didn't revive them instead of adding methods to records...

Nevertheless objects are between records and classes: they can also be located on the stack (and be initialized as a constant) like records, yet they support (if you need it) inheritance and virtual methods. They can't implement interfaces though and there is no base object type (similar to TObject). Also they don't support RTTI (though I might change this with the extended RTTI).

All three types, records, objects and classes have their purposes and uses and one can select the one that is most fitting in a given situation.

Regards,
Sven

Reply by email

Xiangrong Fang
to Sven Barth: Let's suppose you have the following generic declaration: === example begin === type…

Hi Sven,

My code below:

===============================================
program project1;
{$mode objfpc}{$H+}
{$MODESWITCH advancedrecords}
uses Classes;
type
  TMyStringList = record
    StringList: TStringList;
    class operator <(s1, s2: TMyStringList): Boolean;
  end;
class operator TMyStringList.<(s1, s2: TMyStringList): Boolean;
begin
  Result := s1.StringList.Count < s2.StringList.Count;
end;
begin
end.
===============================================

generated these errors:

project1.lpr(9,20) Error: It is not possible to overload this operator.
Related overloadable operators (if any) are:
project1.lpr(9,21) Error: It is not possible to overload this operator.
Related overloadable operators (if any) are:
project1.lpr(9,53) Error: Impossible operator overload
project1.lpr(12,31) Error: method identifier expected
project1.lpr(1,1) Fatal: Compilation aborted

I am using Lazarus 1.0.6/FPC2.6.0-6 on Linux Mint 14/x86_64.

Sincerely,
Shannon

2013/2/26 Sven Barth

Show quoted text 110 lines
On 26.02.2013 09:36, Xiangrong Fang wrote: > Hi Sven, > > Could you please give a simple example that shows what you said: require > that the type with which you specialize is a record. Then a class > operator in that record can be defined. > Let's suppose you have the following generic declaration: === example begin === type generic TTreap<T1, T2> = class // let's assume T1 requires "<" end; === example end === If you use a record to specialize TTreap's T1 parameter then you can do it the following way: === example begin === type TMyRecord = record // note: in mode objfpc the modeswitch advancedrecords is needed class operator < (aLeft, aRight: TMyRecord): Boolean; end; // implementation: class operator TMyRecord.<(aLeft, aRight: TMyRecord): Boolean; begin // compare aLeft and aRight end; // somewhere else TTreapTMyRecordLongInt = specialize TTreap<TMyRecord, LongInt>; === example end === Now the generic will specialize without problem. If you want to specialize other types that don't support class operators then you need to wrap them inside a record, e.g.: === example begin === type TRecTStringList = record MyStringList: TStringList; class operator < (aLeft, aRight: TRecTStringList): Boolean; end; === example end === You can also use visibility modifiers like private or strict private to hide the MyStringList field and make it accessible only through properties. To simplyfy usage you can also define assignment operators. E.g.: === example begin === type // maybe it will also work with a TStringList if you use TStrings instead... TRecTStringList = record private fStringList: TStringList; public class operator := (aRight: TStringList): TRecTStringList; class operator := (aRight: TRecStringList): TStringList; end; class operator TRecTStringList.:=(aRight: TStringList): TRecTStringList; begin Result.fStringList := aRight; end; class operator TRecTStringList.:=(aRight: TRecStringList): TStringList; begin Result := aRight.fStringList; end; // somewhere else: var sl: TStringList; rec: TRecStringList; begin // setup sl rec := sl; // use rec in the tree sl := rec; end; === example end === It's not the nicest solution, but currently the only thing you can do. Regards, Sven -- ______________________________**_________________ Lazarus mailing list .**freepascal.org http://lists.lazarus.**freepascal.org/mailman/**listinfo/lazarus<http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130226/a43d7c3b/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang
Xiangrong Fang wrote 36 lines
Hi Sven, My code below: =============================================== program project1; {$mode objfpc}{$H+} {$MODESWITCH advancedrecords} uses Classes; type TMyStringList = record StringList: TStringList; class operator <(s1, s2: TMyStringList): Boolean; end; class operator TMyStringList.<(s1, s2: TMyStringList): Boolean; begin Result := s1.StringList.Count < s2.StringList.Count; end; begin end. =============================================== generated these errors: project1.lpr(9,20) Error: It is not possible to overload this operator. Related overloadable operators (if any) are: project1.lpr(9,21) Error: It is not possible to overload this operator. Related overloadable operators (if any) are: project1.lpr(9,53) Error: Impossible operator overload project1.lpr(12,31) Error: method identifier expected project1.lpr(1,1) Fatal: Compilation aborted I am using Lazarus 1.0.6/FPC2.6.0-6 on Linux Mint 14/x86_64.

Hmm... 2.6.0 seems to indeed have problems there. I did not test 2.6.2 (I don't have it installed yet), but 2.7.1 works without problems.

Regards,
Sven

Reply by email

Sven Barth
to Xiangrong Fang: My code below: =============================================== program project1; {$mode…
Xiangrong Fang wrote 36 lines
Hi Sven, My code below: =============================================== program project1; {$mode objfpc}{$H+} {$MODESWITCH advancedrecords} uses Classes; type TMyStringList = record StringList: TStringList; class operator <(s1, s2: TMyStringList): Boolean; end; class operator TMyStringList.<(s1, s2: TMyStringList): Boolean; begin Result := s1.StringList.Count < s2.StringList.Count; end; begin end. =============================================== generated these errors: project1.lpr(9,20) Error: It is not possible to overload this operator. Related overloadable operators (if any) are: project1.lpr(9,21) Error: It is not possible to overload this operator. Related overloadable operators (if any) are: project1.lpr(9,53) Error: Impossible operator overload project1.lpr(12,31) Error: method identifier expected project1.lpr(1,1) Fatal: Compilation aborted I am using Lazarus 1.0.6/FPC2.6.0-6 on Linux Mint 14/x86_64.

In addition to my previous mail: It will work in 2.6.0 if you compile in mode delphi (no $H+ and $modeswitch needed there) and you need to rename the operator from "<" to "LessThan" (this is the Delphi operator name).

Regards,
Sven

Reply by email

Xiangrong Fang
to Sven Barth: Hmm... 2.6.0 seems to indeed have problems there. I did not test 2.6.2 (I don't have it…

Then, I wish to see 2.8 released :-D

thanks.

2013/2/26 Sven Barth

Show quoted text 54 lines
On 26.02.2013 15:30, Xiangrong Fang wrote: > Hi Sven, > > My code below: > > ==============================**================= > program project1; > {$mode objfpc}{$H+} > {$MODESWITCH advancedrecords} > > uses Classes; > type > TMyStringList = record > StringList: TStringList; > class operator <(s1, s2: TMyStringList): Boolean; > end; > > class operator TMyStringList.<(s1, s2: TMyStringList): Boolean; > begin > Result := s1.StringList.Count < s2.StringList.Count; > end; > > begin > end. > ==============================**================= > > generated these errors: > > project1.lpr(9,20) Error: It is not possible to overload this operator. > Related overloadable operators (if any) are: > project1.lpr(9,21) Error: It is not possible to overload this operator. > Related overloadable operators (if any) are: > project1.lpr(9,53) Error: Impossible operator overload > project1.lpr(12,31) Error: method identifier expected > project1.lpr(1,1) Fatal: Compilation aborted > > I am using Lazarus 1.0.6/FPC2.6.0-6 on Linux Mint 14/x86_64. > Hmm... 2.6.0 seems to indeed have problems there. I did not test 2.6.2 (I don't have it installed yet), but 2.7.1 works without problems. Regards, Sven -- ______________________________**_________________ Lazarus mailing list .**freepascal.org http://lists.lazarus.**freepascal.org/mailman/**listinfo/lazarus<http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130226/97d80c72/attachment.html>

Reply by email

ListMember
to Sven Barth: The critical difference between records and classes besides the ability of records to…
All three types, records, objects and classes have their purposes and uses and one can select the one that is most fitting in a given situation.

Is it possible to forward declare records the way we can with classes?

I mean, with classes, I can do this:

TSecondClass = class;
TFirstClass = Class(TObject)
private
   FSecondClass: TSecondClass;
public
end;
TSecondClass =  Class(TObject)
private
   FFirstClass: TFirstClass;
public
end;

but, I don't seem to be able to do the same with records --I am referring to the new/modern records.

I can see why it isn't immediately available, but it would be so much nicer if fpc handled the pointer stuff in the background.

Reply by email

Sven Barth
to ListMember
ListMember wrote 28 lines
> All three types, records, objects and classes have their purposes and > uses and one can select the one that is most fitting in a given > situation. Is it possible to forward declare records the way we can with classes? I mean, with classes, I can do this: TSecondClass = class; TFirstClass = Class(TObject) private FSecondClass: TSecondClass; public end; TSecondClass = Class(TObject) private FFirstClass: TFirstClass; public end; but, I don't seem to be able to do the same with records --I am referring to the new/modern records. I can see why it isn't immediately available, but it would be so much nicer if fpc handled the pointer stuff in the background.

It would be no use anyway. You CAN NOT have the record used as a field inside itself, so you'd need to define a pointer type anyway. And this is something where we won't do things behind the programmers back. If you need a pointer then you declare one.

Regards,
Sven

Reply by email

ListMember
to Sven Barth
Sven Barth wrote 34 lines
On 26.02.2013 16:15, ListMember wrote: > >> All three types, records, objects and classes have their purposes and >> uses and one can select the one that is most fitting in a given >> situation. > > Is it possible to forward declare records the way we can with classes? > > I mean, with classes, I can do this: > > TSecondClass = class; > > TFirstClass = Class(TObject) > private > FSecondClass: TSecondClass; > public > end; > > TSecondClass = Class(TObject) > private > FFirstClass: TFirstClass; > public > end; > > but, I don't seem to be able to do the same with records --I am > referring to the new/modern records. > > I can see why it isn't immediately available, but it would be so much > nicer if fpc handled the pointer stuff in the background. It would be no use anyway. You CAN NOT have the record used as a field inside itself, so you'd need to define a pointer type anyway. And this is something where we won't do things behind the programmers back. If you need a pointer then you declare one.

Well.. yes and no.

Here is my use-case:

I am working (on and off) on string classes. I have basically 3 string types: TByteString, TWordString, TCardinalString string each representing a different char/codepage width/bytesize.

And, I'd like to have the user-facing interface to be somethig like this:

TByteString = record
{...}
public
   property AsWordString: TWordString read GetWordString write
SetWordString;
   property AsCardinalString: TCardinalString read GetCardinalString
write SetCardinalString;
end;
TWordString = record
{...}
public
   property AsByteString: TByteString read GetByteString write
SetByteString;
   property AsCardinalString: TCardinalString read GetCardinalString
write SetCardinalString;
end;
TCardinalString = record
{...}
public
   property AsByteString: TByteString read GetByteString write
SetByteString;
   property AsWordString: TWordString read GetWordString write
SetWordString;
end;

Having these properties would be very useful; but if I have to use pointers, then I believe it would force almost all the rest of the calling code to be based on pointers --defeating the purpose of simplicity for the user.

Reply by email

Lukasz Sokol
to ListMember
ListMember wrote
On 2013-02-26 17:18, Sven Barth wrote:

[...]

Show quoted text 33 lines
> It would be no use anyway. You CAN NOT have the record used as a field inside itself, so you'd need to define a pointer type anyway. And this is something where we won't do things behind the programmers back. If you need a pointer then you declare one. Well.. yes and no. Here is my use-case: I am working (on and off) on string classes. I have basically 3 string types: TByteString, TWordString, TCardinalString string each representing a different char/codepage width/bytesize. And, I'd like to have the user-facing interface to be somethig like this: TByteString = record {...} public property AsWordString: TWordString read GetWordString write SetWordString; property AsCardinalString: TCardinalString read GetCardinalString write SetCardinalString; end; TWordString = record {...} public property AsByteString: TByteString read GetByteString write SetByteString; property AsCardinalString: TCardinalString read GetCardinalString write SetCardinalString; end; TCardinalString = record {...} public property AsByteString: TByteString read GetByteString write SetByteString; property AsWordString: TWordString read GetWordString write SetWordString; end; Having these properties would be very useful; but if I have to use pointers, then I believe it would force almost all the rest of the calling code to be based on pointers --defeating the purpose of simplicity for the user.
Would it not do to have classes here (s/record/class) and [Set|Get][Byte|Word|Cardinal]String be
class procedure; //'s
and/or
class function; //'s

instead ?

L.

Reply by email

ListMember
to Lukasz Sokol
Lukasz Sokol wrote 6 lines
Would it not do to have classes here (s/record/class) and [Set|Get][Byte|Word|Cardinal]String be class procedure; //'s and/or class function; //'s instead ?

User code needs to create and destroy classes.

With records, there's no need for any of that.

Reply by email

Jürgen Hestermann
to ListMember: Is it possible to forward declare records the way we can with classes? I mean, with…
ListMember wrote
Is it possible to forward declare records the way we can with classes?

Well, I know that you can do something like this:

      PTreeType    = ^TreeType;
      TreeType   = record
                             ...;
                             ...;
                             Dirs : PListType;
                             end; { of record }

You can see that "TreeType" is used in the first line although it is not (yet) defined. As long as you declare the type within the same "Type" section the compiler swallows it.

Reply by email

Sven Barth
to Jürgen Hestermann
J?rgen Hestermann wrote 19 lines
Am 2013-02-26 16:15, schrieb ListMember: > > Is it possible to forward declare records the way we can with classes? > Well, I know that you can do something like this: PTreeType = ^TreeType; TreeType = record ...; ...; Dirs : PListType; end; { of record } You can see that "TreeType" is used in the first line although it is not (yet) defined. As long as you declare the type within the same "Type" section the compiler swallows it.

He wants to have this supported:

=== example begin ===

type
   SomeType1 = record;
   SomeType2 = record;
   SomeType1 = record
     // ...
     property SomeProperty: SomeType2 read ... write ...
   end;
   SomeType2 = record
     // ...
     property SomeProperty: SomeType1 read ... write ...
   end;

=== example end ===

Just in case you aren't up to date with FPC's supported language, Jurgen, the following works in FPC out of Delphi compatibility since 2.6.0 (though it needs {$modeswitch advancedrecords} in non-Delphi modes):

=== example begin ===

type
   SomeType = record
     // ...
     property SomeProperty: SomeType read ... write ...
   end;

=== example end ===

What still doesn't work (and will never work [and doesn't work in Delphi either :P ]) is this:

=== example begin ===

type
   SomeType = record
     SomeField: SomeType;
   end;

=== example end ===

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Sven Barth
Show quoted text 19 lines
He wants to have this supported: === example begin === type SomeType1 = record; SomeType2 = record; SomeType1 = record // ... property SomeProperty: SomeType2 read ... write ... end; SomeType2 = record // ... property SomeProperty: SomeType1 read ... write ... end; === example end ===

In the meantime I understand why such a construct *is* useful, in detail with records. The *caller* provides the memory for the result, returned by an property getter, and is responsible for releasing it. Not so with pointers, for which memory may have to be allocated, but there is no obligation to release that memory (no owner)!

DoDi

Reply by email

Michael Schnell
to Sven Barth: The critical difference between records and classes besides the ability of records to…
Sven Barth wrote 6 lines
The critical difference between records and classes besides the ability of records to reside on the stack is that they don't allow inheritance and they support variable parts. The "don't allow inheritance" is important, because otherwise you'll have a certain overhead like virtual method resolution.

I see. But this does not force that a synonyme for record could be a certain type of class, so that "class" in a straight forward and thus more "future-compatible" way can be used for any combination of fields of multiple types. (of course keeping the "record" syntax for compatibility)

Show quoted text 6 lines
> AFAIK even old style Turbo-Pascal "Objects" are still in place.... That > could be a certain type of class as well. Yes, objects still exist as well and I still don't really understand why Borland didn't revive them instead of adding methods to records...

I suppose they already marked "Object" as obsolete and did not want to admit the bad decision. (Of course more sensible would have been to extend the count of "class" specifier keywords.)

Show quoted text 10 lines
Nevertheless objects are between records and classes: they can also be located on the stack (and be initialized as a constant) like records, yet they support (if you need it) inheritance and virtual methods. They can't implement interfaces though and there is no base object type (similar to TObject). Also they don't support RTTI (though I might change this with the extended RTTI). All three types, records, objects and classes have their purposes and uses and one can select the one that is most fitting in a given situation.

Yep. All in fact are sensible but the multiple syntax is rather queer (disregarding the history that led to it).

-Michael

Reply by email

Michael Schnell
to ListMember: User code needs to create and destroy classes. With records, there's no need for any of…
ListMember wrote 5 lines
User code needs to create and destroy classes. With records, there's no need for any of that.

This is because right now a class instance needs to reside on the heap. But this does not mean it does not make sense to define an additional class flavor (using a specifier maybe in a similar way as "helper") to define such a beast.

-Michael

Reply by email

Sven Barth
to Michael Schnell: Using a pointer to this type within a record does make a lot of sense for creating linked…
Michael Schnell wrote 5 lines
On 02/26/2013 04:18 PM, Sven Barth wrote: > You CAN NOT have the record used as a field inside itself, Using a pointer to this type within a record does make a lot of sense for creating linked lists. I do this all the time in "C".

This is not what is being talked about. It's about defining record types that use each other in their properties or functions without defining a pointer type.

Regards,
Sven

Reply by email

ListMember
to Sven Barth
Sven Barth wrote 9 lines
Am 27.02.2013 10:51, schrieb Michael Schnell: > On 02/26/2013 04:18 PM, Sven Barth wrote: >> You CAN NOT have the record used as a field inside itself, > > Using a pointer to this type within a record does make a lot of sense > for creating linked lists. I do this all the time in "C". This is not what is being talked about. It's about defining record types that use each other in their properties or functions without defining a pointer type.

Precisely.

Referring to your other post, you gave this example:

=== example begin ===

type
   SomeType1 = record;
   SomeType2 = record;
   SomeType1 = record
     // ...
     property SomeProperty: SomeType2 read ... write ...
   end;
   SomeType2 = record
     // ...
     property SomeProperty: SomeType1 read ... write ...
   end;

=== example end ===

While it does capture the idea, let me make it more detailed/clearer.

What I am proposing/suggesting is like this:

=== example begin ===

type
   SomeType1 = record;
   SomeType2 = record;
   SomeType1 = record
     // ...
     property SomeProperty: SomeType2 read *GetSomeType2* write
*SetSomeType2*;
   end;
   SomeType2 = record
     // ...
     property SomeProperty: SomeType1 read *GetSomeType1* write
*SetSomeType1*;
   end;

=== example end ===

You will notice that I have NOT used any fields that were forward declared.

I only (wish to) use the forward declared record types in methods/getters/setters/properties.

Correct me if I am wrong, but this way we can eliminate the possiblity of introducing infinite recursion (that would arise if we used forward declared record types as fields).

Is there still any logical flaw in this?

Reply by email

Sven Barth
to ListMember
"ListMember" wrote 22 lines
Referring to your other post, you gave this example: === example begin === type SomeType1 = record; SomeType2 = record; SomeType1 = record // ... property SomeProperty: SomeType2 read ... write ... end; SomeType2 = record // ... property SomeProperty: SomeType1 read ... write ... end; === example end === While it does capture the idea, let me make it more detailed/clearer.

To be honest: I left out the methods, because of lazyness :)

I only (wish to) use the forward declared record types in

methods/getters/setters/properties.

Correct me if I am wrong, but this way we can eliminate the possiblity of

introducing infinite recursion (that would arise if we used forward declared record types as fields).

Is there still any logical flaw in this?

After having slept about it a bit, I came to the conclusion that your proposal is at least a valid one considering that we already differentiate between record field or not for the type itself. As a forward declaration needs to be resolved in the same type section we don't need to bother about global variable or function declarations either. What could be a bit counterintuitive though is if there is a class, interface or object declaration inbetween and that one uses the record as well... Depending on when the sizes of the instances and parameters are calculated, we can either allow or need to forbid its usage...

You can create a feature request on the bugtracker. I don't know yet whether we'll definitely implement it or not, but this way it's up for discussion. And please state there again that you don't want to use it for fields.

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130227/415470af/attachment-0001.html>

Reply by email