Sign in Join

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

Mailing lists / fpc-devel / 2003-04

Method overloading

9 messages · 4 people ·

Reply by email Subscribe to this list Your subscription

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

Johann Glaser

Hi!

I've got another problem with the compiler. Stripped down the problem, it comes out that the compiler doesn't work correctly with overloaded methods.

For example: Serial transmission of data, a base class: CSerialInterface
which implements some methods for sending.

  Send(Buf:Pointer;Length:LongInt); virtual; abstract;
  Send(St:String);                  virtual;
  Send(Buf:CCharBuffer);            virtual;

(CCharBuffer is a class which is a "smart" char buffer)

Each serial interface type gets a descent class.
Type CRS232 = class(CSerialInterface) ... End;
Type CRS485 = class(CSerialInterface) ... End;
Type CRS422 = class(CSerialInterface) ... End;
(as examples). They only implement Send(Buf:Pointer;Length:LongInt);
And CSerialInterface implements the other Send methods which are only
wrappers for the above one (look at "virtual" and "virtual abstract"
declarations in CSerialInterface):
Procedure CSerialInterface.Send(St:String);
Begin
  Send(@St[1],Length(St));
End;
(and analogous for the CCharBuffer method).

CRS232 now has 3 Send methods:
Send(Buf:Pointer;Length:LongInt); { implemented there } Send(St:String); { inherited from CSerialInterface } Send(Buf:CCharBuffer); { inherited from CSerialInterface }

Let's now look at the main program:
Var RS232 : CRS232;
    Test  : CSerialInterface;
    St    : String;
Begin
  St := 'Hello World!';
  RS232 := CRS232.Create;
  RS232.Send(@St[1],Length(St)); { <-- works! }
  RS232.Send(St); { compiler complains [1] }
  Test := RS232;
  Test.Send(St); { ugly crash [2] }
End.

[1] the compiler complains
Error: Wrong amount of parameters specified
what means, that it it didn't find the Send(St:String) method. Despite it is inherited!!!

[2] here the compiler seems to have a problem with the VMT and the location each overloaded method gets in the VMT. First it calls CSerialInterface.Send(St:String) (which is called correct). This method then calls Send(Buf:Pointer;Length:LongInt).

Therefore the VMT was invented to find the "most actual" method. CSerialInterface.Send(St:String) gets the VMT of CRS232 (as hidden parameter) and so calls CRS232.Send(Buf:Pointer;Length:LongInt).

Paff! Crash! The compiler seems to use another one of the 3 Send methods from the VMT. Namely the Send(St:String). Which calls itself recursively. And with the wrong parameter and even the wrong parameter count.

I didn't try exactly the setup described here. Please have a look at the attached file. It contains a few units demonstrating the problem.

Please use "ulimit -s 256" before executing "./bar". This limits the stack and prevents a complete crash of your computer.

BTW: I'm using
Free Pascal Compiler version 1.0.6 [2002/08/10] for i386 in my Debian Linux (sid).

BTW: Strange: sometimes it has the problem as described and sometimes it even doesn't identify the Test.Send(St) correctly.

Please try using "fpc bar.pas" and "fpc -B bar.pas" several times. Then the problem occurs in different ways. Strange.

Bye
Hansi

Johann Glaser Vienna University of Technology Electrical Engineering ____ http://www.johann-glaser.at/ ____

Reply by email

Peter Vreman
to Johann Glaser
Show quoted text 33 lines
Hi! I've got another problem with the compiler. Stripped down the problem, it comes out that the compiler doesn't work correctly with overloaded methods. For example: Serial transmission of data, a base class: CSerialInterface which implements some methods for sending. Send(Buf:Pointer;Length:LongInt); virtual; abstract; Send(St:String); virtual; Send(Buf:CCharBuffer); virtual; (CCharBuffer is a class which is a "smart" char buffer) Each serial interface type gets a descent class. Type CRS232 = class(CSerialInterface) ... End; Type CRS485 = class(CSerialInterface) ... End; Type CRS422 = class(CSerialInterface) ... End; (as examples). They only implement Send(Buf:Pointer;Length:LongInt); And CSerialInterface implements the other Send methods which are only wrappers for the above one (look at "virtual" and "virtual abstract" declarations in CSerialInterface): Procedure CSerialInterface.Send(St:String); Begin Send(@St[1],Length(St)); End; (and analogous for the CCharBuffer method). CRS232 now has 3 Send methods: Send(Buf:Pointer;Length:LongInt); { implemented there } Send(St:String); { inherited from CSerialInterface } Send(Buf:CCharBuffer); { inherited from CSerialInterface }

Please try it with 1.1 compiler. Also for inherited overloading you need to specify the overload keyword explicitly.

Reply by email

Peter Vreman
to Peter Vreman
Show quoted text 36 lines
> Hi! > > I've got another problem with the compiler. Stripped down the problem, > it comes out that the compiler doesn't work correctly with overloaded > methods. > > For example: Serial transmission of data, a base class: > CSerialInterface > which implements some methods for sending. > Send(Buf:Pointer;Length:LongInt); virtual; abstract; > Send(St:String); virtual; > Send(Buf:CCharBuffer); virtual; > (CCharBuffer is a class which is a "smart" char buffer) > > Each serial interface type gets a descent class. > Type CRS232 = class(CSerialInterface) ... End; > Type CRS485 = class(CSerialInterface) ... End; > Type CRS422 = class(CSerialInterface) ... End; > (as examples). They only implement Send(Buf:Pointer;Length:LongInt); > > And CSerialInterface implements the other Send methods which are only > wrappers for the above one (look at "virtual" and "virtual abstract" > declarations in CSerialInterface): > Procedure CSerialInterface.Send(St:String); > Begin > Send(@St[1],Length(St)); > End; > (and analogous for the CCharBuffer method). > > CRS232 now has 3 Send methods: > Send(Buf:Pointer;Length:LongInt); { implemented there } > Send(St:String); { inherited from CSerialInterface } > Send(Buf:CCharBuffer); { inherited from CSerialInterface } Please try it with 1.1 compiler. Also for inherited overloading you need to specify the overload keyword explicitly.

I tried it myself under win32 and it works fine with 1.1:

C:\Down>pp11w -B bar
Hint: End of reading config file c:\pp\bin\fpc.cfg Free Pascal Compiler version 1.1 [2003/04/29] for i386 Copyright (c) 1993-2002 by Florian Klaempfl
Target OS: Win32 for i386
Compiling bar.pas
Compiling serialinterface.pas
Compiling rs485.pas
rs485.pas(16,49) Hint: Conversion between ordinals and pointers are not portable

Linking bar.exe
64 Lines compiled, 0.8 sec

C:\Down>pp11w bar
Hint: End of reading config file c:\pp\bin\fpc.cfg Free Pascal Compiler version 1.1 [2003/04/29] for i386 Copyright (c) 1993-2002 by Florian Klaempfl
Target OS: Win32 for i386
Compiling bar.pas
Linking bar.exe
19 Lines compiled, 0.8 sec

C:\Down>bar
CSerialInterface.Send(St:String = "S.Send"):LongInt; CRS485.Send(Buf:Pointer = 0006FE91;Length:LongInt = 6):LongInt; sending: "S.Send"
Kein BUG!

C:\Down>

Reply by email

Johann Glaser
to Peter Vreman: Please try it with 1.1 compiler. Also for inherited overloading you need to specify the…

Hi!

Please try it with 1.1 compiler. Also for inherited overloading you need to specify the overload keyword explicitly.

Is there a special "overload" keyword? Or did you mix it up with "override"?

Is the 1.1 compiler stable enough for a project?

Thanks
Hansi

Johann Glaser Vienna University of Technology Electrical Engineering ____ http://www.johann-glaser.at/ ____

Reply by email

Johann Glaser
to Peter Vreman: I tried it myself under win32 and it works fine with 1.1: C:\Down>pp11w -B bar Hint: End…

Hi!

I tried it myself under win32 and it works fine with 1.1:

Ok, I've tried with FPC 1.1 (current snapshot) under Linux and it works too:

(~/Kuernberg/Bar/src/bug)$ ppc386-1.0 -B bar
Free Pascal Compiler version 1.0.6 [2002/08/10] for i386 Copyright (c) 1993-2002 by Florian Klaempfl
Target OS: Linux for i386
Compiling bar.pas
Compiling serialinterface.pas
Assembling serialinterface
Compiling rs485.pas
Assembling rs485
Assembling bar
Linking bar
64 Lines compiled, 0.0 sec
(~/Kuernberg/Bar/src/bug)$ ./bar
CSerialInterface.Send(St:String = "S.Send"):LongInt; CSerialInterface.Send(St:String =
".Send@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@H@@@L@@@@@@@@"):LongInt; CSerialInterface.Send(St:String =
"Send@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"):LongInt; CSerialInterface.Send(St:String =
"end@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"):LongInt; CSerialInterface.Send(St:String =
"nd@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"):LongInt; CSerialInterface.Send(St:String =
"d@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"):LongInt; CSerialInterface.Send(St:String =
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"):LongInt; CSerialInterface.Send(St:String = ""):LongInt;
CSerialInterface.Send(St:String = ""):LongInt;
CSerialInterface.Send(St:String = ""):LongInt;
CSerialInterface.Send(St:String = ""):LongInt;
CSerialInterface.Send(St:String = ""):LongInt;
[ ... a lot more times ]
Speicherzugriffsfehler
(~/Kuernberg/Bar/src/bug)$ ppc386 -B bar
Free Pascal Compiler version 1.1 [2003/03/16] for i386 Copyright (c) 1993-2002 by Florian Klaempfl
Target OS: Linux for i386
Compiling bar.pas
Compiling serialinterface.pas
Compiling rs485.pas
Linking bar
64 Lines compiled, 0.1 sec
(~/Kuernberg/Bar/src/bug)$ ./bar
CSerialInterface.Send(St:String = "S.Send"):LongInt; CRS485.Send(Buf:Pointer = BFFFF765;Length:LongInt = 6):LongInt; sending: "S.Send"
Kein BUG!
(~/Kuernberg/Bar/src/bug)$

(the '@' above come from the editor 'joe' with which I've looked at a file generated with "./bar > a.txt" to get the whole output. The '@' is printed bold which means ^@ = #$00).

Bye
Hansi

Johann Glaser Vienna University of Technology Electrical Engineering ____ http://www.johann-glaser.at/ ____

Reply by email

Marco van de Voort
to Johann Glaser: Hi! Is there a special "overload" keyword? Or did you mix it up with "override"? Is the…
Show quoted text 5 lines
> Please try it with 1.1 compiler. Also for inherited overloading you need > to specify the overload keyword explicitly. Is there a special "overload" keyword? Or did you mix it up with "override"?

There is a overload too. It signals that you really want to overload a method, not just tried to inherit, but got the parameters wrong.

Is the 1.1 compiler stable enough for a project?

Usually yes, though there are times when large commits are done, when the ride is a bit rough.

In general,
- if you can build FPC yourself, you can use 1.1 (since you can always build another one).
- more often building eats a bit more bandwidth.
- _always_ keep the last version/build/snapshot that worked for you as back-up.
- Always try to start building 1.1 using the release compiler if there are problems with 1.1 CVS

If you have broadband, just build 1.1 from time to time, and if you don't have problems with that build, stick to it for a while etc, while keeping the old one as backup

Reply by email

Peter Vreman
to Johann Glaser: Hi! Is there a special "overload" keyword? Or did you mix it up with "override"? Is the…
Hi! > Please try it with 1.1 compiler. Also for inherited overloading you need > to specify the overload keyword explicitly.

The overload keyword was introduced in Delphi 5. We supported it already for delphi compatibility. Since Delphi also does inherited overloading we choose the best way to be both backwards compatible and delphi compatible. When the overload keyword is not used then overloading works only in the current scope. With the overload keyword the overloading will enable global/inherited overloading.

With overload you can also overload cross units:

unit a;
procedure test(s:string);
unit b;
procedure test(i:longint);overload;
program c;
uses b;
begin
  test('string');
end.

Reply by email

Jonas Maebe
to Peter Vreman
Peter Vreman wrote
With overload you can also overload cross units: unit a; procedure test(s:string);

Don't you have to add "overload" here as well?

Show quoted text 8 lines
unit b; procedure test(i:longint);overload; program c; uses b; begin test('string'); end.

Jonas

Reply by email

Peter Vreman
to Jonas Maebe
Show quoted text 9 lines
On dinsdag, apr 29, 2003, at 14:28 Europe/Brussels, Peter Vreman wrote: > With overload you can also overload cross units: > > unit a; > procedure test(s:string); Don't you have to add "overload" here as well?

It is not required, but if unit a used a unit d that also provided a procedure test then the procedure in unit d will not be available as overload

Show quoted text 9 lines
> unit b; > procedure test(i:longint);overload; > > program c; > uses b; > begin > test('string'); > end.

Reply by email