Sign in Join

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

Mailing lists / fpc-pascal / 2013-10

WHY compiler should be public?

8 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

Xiangrong Fang

Hi,

First of all, I did some research and found this:

http://free-pascal-general.1045716.n5.nabble.com/Compiler-Warning-Constructor-should-be-public-td2825747.html

But that did not convince me. So here is my situation and question.

I have the following case:

TBase = class
public
  constructor Create;                         //VER-0
end;
TDerived = class(TBase)
private
  constructor Create(param1);                 //VER-1
public
  constructor Create; reintroduce;            //VER-0'
  constructor Create(param1, param2);         //VER-2
  constructor Create(param1, param2, param3); //VER-3
end;

My purpose is that while using TDerived, only VER-2 and VER-3 of the constructors should be used, VER-0 and VER-1 are used INTERNALLY by VER-2 and VER-3 and should NOT be used publicly.

As restricted by the "rule of OOP", you cannot make a method which is public in base class private in descendants, I plan to do the following:

1) reintroduce a Create (without param), which just throw an exception explaining that this MUST NOT be called directly. Meanwhile, use "inherited Create" internally in other versions of the constructors.

2) Make VER-1 private so that it cannot be called outside.

Now the compiler throw a warning that constructor should be public.

In the post I referred, Graeme explained that:

============================================================== Your code is flawed. Object Pascal is quite clear regarding visibility rules. TObject has a Public constructor. You can only raise the visibility from there, not reduce visibility.

Imagine how confusing it will be if you code was a library of some sorts and other developers had to use it. In a inherited class, you have public visibility to the constructor or some other method, and then suddenly in the descendant class the methods are hidden from the developer?? Not a good idea. ==============================================================

I don't understand this, because to me, the VER-1 constructor is introduced in TDerived, make it non-public does NOT reduce the visibility of VER-0 constructor, hence is not a violation of visibility rules, is it???

Thanks!
Xiangrong

Reply by email

Michael Van Canneyt
to Xiangrong Fang
Xiangrong Fang wrote 28 lines
Hi, First of all, I did some research and found this: http://free-pascal-general.1045716.n5.nabble.com/Compiler-Warning-Constructor-should-be-public-td2825747.html But that did not convince me. So here is my situation and question. I have the following case: TBase = class public   constructor Create;                         //VER-0 end; TDerived = class(TBase) private   constructor Create(param1);                 //VER-1  public   constructor Create; reintroduce;            //VER-0'   constructor Create(param1, param2);         //VER-2   constructor Create(param1, param2, param3); //VER-3 end; My purpose is that while using TDerived, only VER-2 and VER-3 of the constructors should be used, VER-0 and VER-1 are used INTERNALLY by VER-2 and VER-3 and should NOT be used publicly.

Why not simply make it a procedure that is called by ver-2 and ver-3.

If it cannot be called directly from external code, and will called only from inside a visible consructor, there is simply no reason to make this procedure a constructor. A simple procedure will do.

Michael.

Reply by email

Xiangrong Fang
to Michael Van Canneyt

2013/10/25 Michael Van Canneyt

Show quoted text 5 lines
Why not simply make it a procedure that is called by ver-2 and ver-3. If it cannot be called directly from external code, and will called only from inside a visible consructor, there is simply no reason to make this procedure a constructor. A simple procedure will do.

​Because I don't know how to make it non-constructor. See the following code:

  1 unit wtree;
  2 {$mode objfpc}{$H+}
  3 interface
  4 uses tree;
  5 type
  6   TQWordTree = specialize TTree<QWord>;
  7   TWTree = class(TQWordTree)
  8   private
  9     FModel: string;
 10   public
 11     property Model: string read FModel;
 12     constructor Create(AData: QWord; AParent: TWTree; AModel: string);
 13     constructor Create(HeadNode, TailNode: QWord);
 14   end;
 15 implementation
 16
 17 constructor TWTree.Create(AData: QWord; AParent: TWTree; AModel:
string);
 18 begin
 19   inherited Create(AData, AParent);
 20   FModel := AModel;
 21 end;
 22
 23 constructor TWTree.Create(HeadNode, TailNode: QWord);
 24 begin
 25   inherited Create(0, nil);
 26   Data := HeadNode;
 27   with TWTree do Create(TailNode, Create(HeadNode, Self, 'h'), 't');
 28   FModel := 'R';
 29 end;
 30
 31 end.

Please tell me how to deal with line 27, which called the should-be-private constructor.

BTW, this code uses TTree class, which is here:

https://github.com/xrfang/fpcollection/blob/master/src/units/tree.pas

Also, ​

​I don't understand why this does not work:

f := TFileStream.Create;

I know that TFileStream's Create require a file name parameter, but as TFileStream is inherited from TObject, which has a Create without parameter. This is why I feel that it is possible to HIDE a public constructor from ancestor.

Best Regards,
Xiangrong​

Reply by email

Xiangrong Fang
to Michael Van Canneyt: Why not simply make it a procedure that is called by ver-2 and ver-3. If it cannot be…

2013/10/25 Michael Van Canneyt

Show quoted text 5 lines
Why not simply make it a procedure that is called by ver-2 and ver-3. If it cannot be called directly from external code, and will called only from inside a visible consructor, there is simply no reason to make this procedure a constructor. A simple procedure will do.

​Because I don't know how to make it non-constructor. See the following code:

  1 unit wtree;
  2 {$mode objfpc}{$H+}
  3 interface
  4 uses tree;
  5 type
  6   TQWordTree = specialize TTree<QWord>;
  7   TWTree = class(TQWordTree)
  8   private
  9     FModel: string;
 10   public
 11     property Model: string read FModel;
 12     constructor Create(AData: QWord; AParent: TWTree; AModel: string);
 13     constructor Create(HeadNode, TailNode: QWord);
 14   end;
 15 implementation
 16
 17 constructor TWTree.Create(AData: QWord; AParent: TWTree; AModel:
string);
 18 begin
 19   inherited Create(AData, AParent);
 20   FModel := AModel;
 21 end;
 22
 23 constructor TWTree.Create(HeadNode, TailNode: QWord);
 24 begin
 25   inherited Create(0, nil);
 26   Data := HeadNode;
 27   with TWTree do Create(TailNode, Create(HeadNode, Self, 'h'), 't');
 28   FModel := 'R';
 29 end;
 30
 31 end.

Please tell me how to deal with line 27, which called the should-be-private constructor.

BTW, this code uses TTree class, which is here:

https://github.com/xrfang/fpcollection/blob/master/src/units/tree.pas

Also, ​

​I don't understand why this does not work:

f := TFileStream.Create;

I know that TFileStream's Create require a file name parameter, but as TFileStream is inherited from TObject, which has a Create without ​

Reply by email

Michael Van Canneyt
to Xiangrong Fang: 2013/10/25 Michael Van Canneyt ​Because I don't know how to make it non-constructor.…
Xiangrong Fang wrote 41 lines
2013/10/25 Michael Van Canneyt Why not simply make it a procedure that is called by ver-2 and ver-3. If it cannot be called directly from external code, and will called only from inside a visible consructor, there is simply no reason to make this procedure a constructor. A simple procedure will do. ​Because I don't know how to make it non-constructor. See the following code:   1 unit wtree;   2 {$mode objfpc}{$H+}   3 interface   4 uses tree;   5 type   6   TQWordTree = specialize TTree<QWord>;   7   TWTree = class(TQWordTree)   8   private   9     FModel: string;  10   public  11     property Model: string read FModel;  12     constructor Create(AData: QWord; AParent: TWTree; AModel: string);  13     constructor Create(HeadNode, TailNode: QWord);  14   end;  15 implementation  16  17 constructor TWTree.Create(AData: QWord; AParent: TWTree; AModel: string);  18 begin  19   inherited Create(AData, AParent);  20   FModel := AModel;  21 end;  22  23 constructor TWTree.Create(HeadNode, TailNode: QWord);  24 begin  25   inherited Create(0, nil);  26   Data := HeadNode;  27   with TWTree do Create(TailNode, Create(HeadNode, Self, 'h'), 't');  28   FModel := 'R';  29 end;  30  31 end. Please tell me how to deal with line 27, which called the should-be-private constructor.

Ah. The 'private' constructor is called FROM ANOTHER INSTANCE. You didn't say that.

That currently can't be done.

Michael.

Show quoted text 12 lines
BTW, this code uses TTree class, which is here: https://github.com/xrfang/fpcollection/blob/master/src/units/tree.pas Also, ​ ​I don't understand why this does not work: f := TFileStream.Create; I know that TFileStream's Create require a file name parameter, but as TFileStream is inherited from TObject, which has a Create without parameter.  This is why I feel that it is possible to HIDE a public constructor from ancestor.

I think this is a bug :)

Michael.

Reply by email

Sven Barth
to Michael Van Canneyt
"Michael Van Canneyt" wrote 6 lines
> Also, > I don't understand why this does not work: > > f := TFileStream.Create; > > I know that TFileStream's Create require a file name parameter, but as

TFileStream is inherited from TObject, which has a Create without parameter. This is why I feel that it is possible to HIDE a public

> constructor from ancestor. I think this is a bug :)

No, I don't think so. If you want users to use the original constructor as well you'd need to declare yours as "overload". If it would be possible to call TFileStream.Create without parameters then the instance would be in an inconsistent state, so only calling the constructor with arguments should be possible (which is the case for TFileStream.

So this is definitely by design.

Regards,
Sven

Reply by email

Sven Barth
to Xiangrong Fang: 2013/10/25 Michael Van Canneyt ​Because I don't know how to make it non-constructor.…
"Xiangrong Fang" wrote 7 lines
Also, I don't understand why this does not work: f := TFileStream.Create; I know that TFileStream's Create require a file name parameter, but as

TFileStream is inherited from TObject, which has a Create without parameter. This is why I feel that it is possible to HIDE a public constructor from ancestor.

Yes, it's possible to hide a public constructor (or any method for that matter), but it's not possible to decrease the visibility of a constructor (or any method for that.matter).

Regards,
Sven

Reply by email