Parameter of type X must support interface Y - class

I have a setup like so :
IBuilder = interface(IInvokable)
end;
IBuilder<T: IBuilder; TOut : TWinControl> = interface(IInvokable)
end;
TBuilder<T: IBuilder; TOut : TWinControl> = class(TInterfacedObject, IBuilder, IBuilder<T, TOut>)
end;
TBuilder = class(TBuilder<TBuilder, TWinControl>)
end;
This kind of structure allows me to build a sugar syntax like so :
TBuilder<T : IBuilder; TOut : TWinControl> = class(TInterfacedObject, IBuilder, IBuilder<T, TOut>)
function Output : TOut;
function Name(aName : string) : T;
function Left(aLeft : Integer) : T;
function Top(aTop : Integer) : T;
end;
// ... later
TBuilder.Create().Left(10).Top(5).Name('ABC'); // Nice one liner
The problem is that I get a compilation error, saying that
E2514 The type parameter TBuilder must support interface 'IBuilder'.
This is probably due to the typed constraint T: IBuilder present on the interface, even though TBuilder does support IBuilder (trough it's ancestor).
Can anyone please direct me on how to get around this?
Though, I cannot use TBuilder = class(TBuilder<IBuilder, TObject>)

This can't be done. You're essentially trying to do this :
IBar = interface(IInterface) end;
TFoo<T : IBar> = class(TObject, IBar) end;
TBar = TFoo<TBar>;
Which generates error
E2086 Type 'TBar' is not yet completely defined
Without the interface dependence you can write this as
TBar = class(TFoo<TBar>) end;
making it a true descendent and not just an alias. This could normally resolve the type, but the interface dependence is forcing the compiler to ask the question : Does TBar support IBar?
If you think about it, this works out as :
TBar = TFoo<TBar> {TBar support IBar?}
|
TBar = TFoo<TBar>... {ok, TBar support IBar?}
|
TBar = TFoo<TBar> {ok, TBar support IBar?}
|
{...turtles all the way down}
You're asking the compiler to solve an infinite recursion problem. It cannot do this.

You can fix this by changing the return type of your methods, and excluding the recursive type parameter.
interface
type
//IBuilder = interface(IInvokable)
//end; //I don't think you need this
IBuilder<TOut : TWinControl> = interface(IInvokable)
function Output : TOut;
function Name(const aName : string) : IBuilder<TOut>;
function Left(aLeft : Integer) : IBuilder<TOut>;
function Top(aTop : Integer) : IBuilder<TOut>;
end;
TFactory<TOut: TWinControl> = record
class function New: IBuilder<TOut>; static;
end;
implementation
type
//Put the actual class in the implementation
TBuilder<TOut : TWinControl> = class(TInterfacedObject, IBuilder<TOut>)
//see interface
end;
You normally use this like so:
var
MyButton: IBuilder<TButton>;
begin
MyButton:= TFactory<TButton>.New.Left(10).Top(5).Name('ABC');
If you're using interface then you should never work with the class, always interact with the interface exclusively. By moving the class definition in the implementation you enforce this. To compensate you add a factory method in the interface.
In this case it has to be a record, because you cannot (yet) have generic stand-alone methods.
class function TFactory<TOut>.New: IBuilder<TOut>;
begin
Result:= TBuilder<TOut>.Create;
end;

Related

Implementation through interface delegation not pass to descendant

Consider this interfaces and its implementations.
unit utest;
interface
{$MODE OBJFPC}
type
IIntfA = interface
procedure writeA();
end;
IIntfB = interface(IIntfA)
procedure writeB();
end;
TADelegateClass = class(TInterfacedObject, IIntfA)
public
procedure writeA();
end;
TAClass = class(TInterfacedObject, IIntfA)
private
delegateA : IIntfA;
public
constructor create(const AInst : IIntfA);
destructor destroy(); override;
property A : IIntfA read delegateA implements IIntfA;
end;
TBClass = class(TAClass, IIntfB)
public
procedure writeB();
end;
implementation
procedure TADelegateClass.writeA();
begin
writeln('Implement IIntfA through delegation');
end;
constructor TAClass.create(const AInst : IIntfA);
begin
delegateA := AInst;
end;
destructor TAClass.destroy();
begin
inherited destroy();
delegateA := nil;
end;
procedure TBClass.writeB();
begin
writeln('Implement IIntfB');
end;
end.
Following program will not compile.
program test;
{$MODE OBJFPC}
uses
utest;
var b : IIntfB;
begin
b := TBClass.create(TADelegateClass.create());
b.writeA();
b.writeB();
end.
Free Pascal (version 3.0.4) complains
Error: No matching implementation for interface method "writeA;" found.
at line where TBClass is declared.
Of course, I can compile it successfully by implementing writeA either in TAClass or TBClass and call writeA method of TADelegateClass from there.
TAClass is concrete implementation of IIntfA interface through interface delegation but why TBClass, which is descendant of TAClass, is not considered a concrete implementation of IIntfA interface?
TAClass is concrete implementation of IIntfA interface through
interface delegation but why TBClass, which is descendant of TAClass,
is not considered a concrete implementation of IIntfA interface?
Short answer: it's not IIntfA that is the problem, it is IIntfB that is incomplete.
Long answer: Interface inheritance is C++ vtable inheritance, which is sometimes not intuitive.
In the example:
IIntfB = interface(IIntfA)
procedure writeB();
end;
could actually be written as
IIntfB = interface
procedure writeA();
procedure writeB();
end;
When implementing multiple interfaces, common parts are not reused. The compiler sets up individual tables from the implementing methods, such as:
TADelegateClass:
QueryInterface(IIntfA) = Self.vtable_IIntfA
vtable_IIntfA.writeA <- Self.writeA
TAClass:
QueryInterface(IIntfA) = delegateA.vtable_IIntfA
TBClass:
QueryInterface(IIntfA) = inherited delegateA.vtable_IIntfA
QueryInterface(IIntfB) = vtable_IIntfB
vtable_IIntfB.writeA <- (this is missing!)
vtable_IIntfB.writeB <- Self.writeB
TBClass does indeed not have an implementation of IIntfB.writeA.
This can be verified by manually assigning a method to the specific interface and observe the error disappearing:
TBClass = class(TAClass, IIntfB)
public
procedure IIntfB.writeA = writeB;
// dummy method, shows IIntfB.writeA is missing
Sadly, I don't know of any way to tell the compiler to access a mapping from another interface. FWIW, Delphi has the same bug/shortcoming.

What is the best way for implementing something similar to an interface with Ada 95?

I want to implement something similar to an interface using Ada 95 (so the typical OO interfaces are not available). I've done it by using generics and a set of "pointer to method" within a record. The code is below.
EDIT: I know that it can be done by passing subprograms as formal parameters to the generic package, but I would like to avoid passing too many parameters to it.
I think that there must be a much better way for implementing what I want, so I would like if I'm right and, if so, I would like to see an example of code.
The "interface" is declared in a generic package called Drivers. There, there is a record which is meant to contain a variable of a generic type that represents the driver and a record which contains its operations:
drivers.ads
generic
type T is private;
type Error is private;
NOT_IMPLEMENTED_CODE : Error;
package Drivers is
type Driver is private;
-- Need to declare these types because I compile with Ada 95.
type ToStringPtr is access function(self : in T) return String;
type ReadLinePtr is access procedure(self : in T; buffer : out String; err : out Error);
type DriverOps is
record
to_string_op : ToStringPtr := null;
read_line_op : ReadLinePtr := null;
end record;
function create_driver(underlying : T; ops : DriverOps) return Driver;
function to_string(self : in Driver) return String;
procedure read_line(self : in Driver; buffer : out String; err : out Error);
private
type Driver is
record
underlying : T;
ops : DriverOps;
end record;
end Drivers;
drivers.adb
package body Drivers is
function create_driver(underlying : T; ops : DriverOps) return Driver is
begin
return (underlying, ops);
end create_driver;
function to_string(self : in Driver) return String is
begin
if self.ops.to_string_op /= null then
return self.ops.to_string_op(self.underlying);
else
return "";
end if;
end to_string;
procedure read_line(self : in Driver; buffer : out String; err : out Error) is
begin
if self.ops.read_line_op /= null then
self.ops.read_line_op(self.underlying, buffer, err);
else
err := NOT_IMPLEMENTED_CODE;
end if;
end read_line;
end Drivers;
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Fixed;
with Drivers;
procedure main is
type Error is (SUCCESS, NOT_IMPLEMENTED, UNKNOWN);
type MyInt is new Integer;
function to_string(self : in MyInt) return String is
begin
return Integer'Image( Integer(self) ); --'
end to_string;
procedure read_line(self : in MyInt; buffer : out String; err : out Error) is
begin
Ada.Strings.Fixed.Move(
Target => buffer,
Source => "Lets suppose we have read this from a device" & ASCII.LF,
Pad => ASCII.NUL);
err := SUCCESS;
end read_line;
package IntDrivers is new Drivers(MyInt, Error, NOT_IMPLEMENTED);
use IntDrivers;
underlying : MyInt := 25;
int_driver_ops : DriverOps := (
to_string_op => to_string'access, --'
read_line_op => read_line'access --'
);
my_driver : Driver := create_driver(underlying, int_driver_ops);
buffer : String(1..256) := (others => Character'Val(0)); --'
err : Error := SUCCESS;
begin
Put_Line(to_string(my_driver));
read_line(my_driver, buffer, err);
Put(buffer);
Put_Line(Error'Image(err)); --'
end main;
The only one I known of is described below, and may not be canonical. This is not strictly interface inheritance, but it can put you in the right direction.
It requires to use a discriminant tagged record.
The trick is to define 2 tagged types. One is your classic class definition, the other is used as "interface" inheritance.
You can then manipulate an object that gives access to the interface contract and the class contract using discriminants. Declaring both in the same package should give you full visibility over private parts, to be confirmed.
In short :
type InterfaceX is abstract ....; -- abstract class and services
type ClassA is tagged ...; -- or is new ....
type Trick (component : ClassA) is new InterfaceX ...; -- this type gives you access to classA and interfaceX primitives
Trick object realizes your InterfaceX contract.
You will have to define instantiaton/accessors to either ClassA object or the Trick object. I think types should also be limited.
I always hear people call this "Rosen trick", guess it is named after J.-P. Rosen.
Maybe you will find some more precise answers here http://www.adaic.org/resources/add_content/standards/95rat/rat95html/rat95-p2-4.html#6
An interface is an abstract tagged null record in Ada 95:
package Abstract_Driver is
type Instance is abstract tagged null record;
subtype Class is Instance'Class; --' (defect syntax highlighter)
function Image (Item : in Instance) return String is abstract;
procedure Read_Line (Item : in out Instance;
Buffer : out String) is abstract;
end Abstract_Driver;
with Abstract_Driver;
package Text_IO_Driver is
subtype Parent is Abstract_Driver.Instance;
type Instance is new Parent with private;
subtype Class is Instance'Class; --' (defect syntax highlighter)
function Image (Item : in Instance) return String;
Buffer_Too_Small : exception;
procedure Read_Line (Item : in out Instance;
Buffer : out String);
private
type Instance is new Parent with null record;
end Text_IO_Driver;
with Ada.Text_IO;
package body Text_IO_Driver is
function Image (Item : in Instance) return String is
begin
return "Ada.Text_IO.Standard_Input";
end Image;
procedure Read_Line (Item : in out Instance;
Buffer : out String) is
Last : Natural;
begin
Buffer := (Buffer'Range => ' '); --' (defect syntax highlighter)
Ada.Text_IO.Get_Line (Item => Buffer,
Last => Last);
if Last = Buffer'Last then --' (defect syntax highlighter)
raise Buffer_Too_Small;
end if;
end Read_Line;
end Text_IO_Driver;

ShowModal for an associated form

I have a component with bellow properties:
property Form: TForm read FForm write SetForm
property BtnOK: TButton read FBtnOK write SetBtnOK
and a procedure behind like this:
procedure Execute_FormShowModal;
I would like to open the associated form (eg. FormUser) when the Execute_FormShowModal is executed.
I would like to mention that, the associated form is already defined and exist, but is not created.
Is there any possibility to do this?
procedure TMyComp.Execute_FormShowModal;
var
frm: TForm;
begin
frm:= TForm(FForm.ClassName).Create(FParentForm); //Access Violation...
//... here I would like to play also this the elements from this form
//like: BtnOK.Enabled:= False;
frm.ShowModal;
frm.Free;
end;
You added in the comments that you are setting FForm to be equal to a valid existing form. If so, you may not need to create anything:
procedure TMyComp.Execute_FormShowModal;
var
frm: TFormUser;
begin
frm:= TFormUser(FForm);
frm.BtnOK.Enabled:=False;
frm.ShowModal;
//frm.Free;
end;
This assumes that this valid instance you are referring to is declared
type
TFormUser = class(TForm)
BtnOK : TButton;
// etc...
end;
If you trying to make a copy of the form you might use this:
procedure TMyComp.Execute_FormShowModal;
var
frm: TFormUser;
begin
frm:= TFormUser(TFormClass(FForm.ClassType).Create(FParentForm));
// which is no different than:
frm:= TFormUser.Create(FParentForm));
frm.BtnOK.Enabled:=False;
frm.ShowModal;
frm.Free;
end;
If you want to manipulate the controls on the form (i.e. BtnOK), then you need to know the class type of the Form (TFormUser in this case). So it is contradictory to be required to know the exact class type of the form and yet want to instanciate a form from a design-time established type.
Since you may be trying to instanciate the form without "knowing" its absolute type, your FForm property should be the class for the form.
Assuming you weren't publishing the "Form" property in your component, I would make these changes to your component:
TMyComp = class(TComponent)
FFormClass : TFormClass;
procedure SetFormClass(Value : TFormClass);
property FormClass: TFormClass read FFormClass write SetFormClass;
procedure Execute_FormShowModal;
end;
The initialization code you referred to might look like this:
begin
// .....
//MyComp.Form := FormUser1;
MyComp.FormClass := TFormUser;
// .....
end;
And then "Execute_FormShowModal" becomes:
procedure TMyComp.Execute_FormShowModal;
var
frm: TForm;
begin
// Check that FFormClass is not nil and perform some alternate
// action.
// if FFormClass = nil then ......
//
frm:= FFormClass.Create(FParentForm);
frm.ShowModal;
frm.Free;
end;
Of course, you may also want to add some code to check if FFormClass is nil and preform some alternate behavior if so, like raise an exception or showing some message or even instanciating a default form.
If you were publishing the Form property then it won't be able to handle the case where your FForm field value is nil because you don't know or have a specific class type to instanciate the Form. That is:
frm:= TFormClass(FForm.ClassType).Create(FParentForm);
will simply display a blank, empty form.
If you want to publish this property, you could try making it a string type that carries the name of the form class you want to instanciate and then use RTTI to find the class:
uses RTTI;
TMyComp = class(TComponent)
FFormClassName : string;
procedure SetFormClassName(const Value : string);
property FormClassName: string read FFormClassName write SetFormClassName;
procedure Execute_FormShowModal;
end;
procedure TMyComp.Execute_FormShowModal;
var
frmCls : TFormClass;
frm: TForm;
RTTI : TRTTIContext;
RTTIType : TRTTIType;
begin
frmCls := nil;
for RTTIType in RTTI.GetTypes do
begin
if (RTTIType.Name = FFormClassName) and (RTTIType.TypeKind = tkClass) then
begin
if RTTIType.Handle.TypeData.ClassType.InheritsFrom(TForm) then
begin
frmClass := TFormClass(RTTIType.Handle.TypeData.ClassType);
break;
end;
end;
end;
// Check that frmCls is not nil and perform some alternate
// action.
// if frmCls = nil then ......
//
frm:= frmCls.Create(FParentForm);
frm.ShowModal;
frm.Free;
end;
Is there any possibility to do this?
Yes
Try something like this
uses uFForm; // Add the unit name that defined the associated form to your (TMyComp) unit uses clause
procedure TMyComp.Execute_FormShowModal;
begin
with TFForm.Create(Self) do //TFForm is the child form
begin
//... here I would like to play also this the elements from this form
BtnOK.Enabled:= False;
Show;
end;
end;
First problem is that you are trying to typecast the ClassName to a class type that you're trying to instantiate. Instead you want to work with the metaclass that can be obtained by the ClassType method from an object instance. The next issue is that with such metaclass you need to typecast to a metaclass, not to a class, so instead of typecasting to TForm class cast to its metaclass TFormClass.
To the next part of your question, if you can generally access a specific class members of an object that is declared as a common class ancestor, no, that is not possible. As a workaround you must determine the object class type and access it by typecasting to that class, or use RTTI which is more difficult.
Try something like this:
procedure TMyComp.Execute_FormShowModal;
var
frm: TForm;
begin
frm := TFormClass(FForm.ClassType).Create(FParentForm);
{ to acess the class specific members you will have to typecast to a
specific class (or use RTTI, which is even more difficult) }
if frm is TMyForm then
TMyForm(frm).BtnOK.Enabled := False;
frm.ShowModal;
frm.Free;
end;

How to copy data from one class into another class

how to copy data from one class into a second class using operator overloading with DELPHI ?
my dummy app goes like this :
type
TClass_A = class
a: String;
end;
TClass_B = class(TClass_A)
b: String;
end;
implementation
procedure TForm1.Button1Click(Sender: TObject);
var
a: TClass_A;
b: TClass_B;
begin
a := TClass_A.Create;
b := TClass_B.create;
b := a; // <<-- What code should be here? Can I overload := operator?
end;
The assignment operator cannot be overloaded in Delphi.
You will need to introduce a method to perform the copying. An example of how this might be done is TPersistent.Assign. It would be perfectly reasonable for you to derive from TPersistent and override the virtual Assign method to implement the desired functionality.
Here is a small example of how to do this with new style RTTI (D2010 and higher).
Please note that this is a very basic example which only copies fields (not properties) and works best with basic classes (do not use this with TComponent), the fields in the destination object must be the same type. FYI, there are better examples out there :)
uses
Rtti,...
function CopyObject(const FromObj, ToObj: TObject): Boolean;
var
Ctx : TRTTIContext;
FromObjType : TRttiType;
ToObjType : TRttiType;
FromField : TRttiField;
ToField : TRttiField;
begin
Result := False;
FromObjType := Ctx.GetType(FromObj.ClassInfo);
ToObjType := Ctx.GetType(ToObj.ClassInfo);
for FromField in FromObjType.GetFields do
begin
ToField := ToObjType.GetField(FromField.Name);
if Assigned(ToField) then
begin
if ToField.FieldType = FromField.FieldType then
ToField.SetValue(ToObj, FromField.GetValue(FromObj));
Result := True;
end;
end;
end;

Error When Editing Member Variable in Class

I'm trying to use a class in my program.
TStack = Class
Public
constructor Create; Overload;
Procedure Add(Frm:TForm);
Procedure Remove();
Procedure Do_Close;
Private
List : Array[1..Max_Forms] of Rec;
Count : Byte;
End;
Constructor:
constructor TStack.Create;
begin
Self.Count := 0;
end;
Procedure TStack.Add(Frm:TForm);
begin
Inc(Self.Count);
List[Count].Form := #Frm;
List[Count].Width := Frm.Width;
List[Count].Height := Frm.Height;
List[Count].left := Frm.Left;
List[Count].Top := Frm.Top;
end;
I can't change value of Count variable! It cause Run-Time error : Access violation....Write of address 000001E4
What's the problem?!
FOR MORE INFORMATION:
I'm trying to store a pointer to each form in a structure like this :
Rec = Record
Form : ^TForm;
Maximized : Boolean;
Width,
Height,
left,
Top : Integer;
End;
And then
Procedure TStack.Do_Close;
var
i : integer;
MyForm : TForm;
begin
i := .....some code here.......;
MyForm := #List[i].Form;
ShowMessage('I will close '+MyForm.Caption);
MyForm.Close;
end;
AND call constructor like this to initialize 'Count':
Stack.Create;
As described in comments you are attempting to create the object like this:
var
Stack: TStack;
....
Stack.Create;
This is a classic mistake, and one that we've all made. You are calling a method on an uninitialized instance variable.
In order to instantiate a class you need to write this:
Stack := TStack.Create;
On top of that I have the following comments:
Use zero-based indexing for arrays. That's the convention everywhere in Delphi apart from anachronistic strings. And even that is changing in newer versions.
Don't use static arrays for a stack unless you have a good reason for doing so. You'll just run the risk of running out of space. Or allocating more memory than you need. Use a dynamic array.
Rather than a dynamic array, you could use TList<T>.
Even so, one wonders why you are making your own stack class when there is the perfectly good TStack<T>.
You store the address of a local variable in your stack. In TStack.Add you add #Frm into the container. As soon as TStack.Add returns, #Frm is meaningless. That's because Frm is a local variable whose life ends when the function that owns it returns. I think you want to take a copy of Frm.
Picking up item 5 in more detail, your record is declared like this:
Rec = Record
Form : ^TForm;
Maximized : Boolean;
Width,
Height,
left,
Top : Integer;
End;
It is a mistake to use ^TForm. That is a pointer to a variable holding a pointer to an object. That's two levels of indirection, one too many. You must declare the Form field to be of type TForm. I suggest you revise the way Delphi object reference variables work. Delphi classes are what is known as reference types. A variable of type TMyClass where TMyClass is class(...) is already a pointer. The language automatically de-references the pointer when you use the . operator to access members.