More interface woes (Acessing original object methods through an interface)

Having come to the Delphi world via VB, I presumed that the following would be possible:

procedure bar( fooi: IFoo);
var
  foot : TFoo;
begin
  foot := TFoo(fooi);
  MessageBox(0,pchar(foot.str),'',1);
end;

var
  foot : TFoo;
begin
  foot := TFoo.create;
  foot.str := ('hallo');
  bar(foot);
end.

i.e. That after storing a TFoo in an IFoo that I could cast IFoo back to type TFoo. Have I done something stupid? How can I perform such a cast?
davelaneAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Wim ten BrinkSelf-employed developerCommented:
Yep. Something stupid... But hey, we've all done stupid things in the past... ;-)

And no, a class type is not compatible with an interface. Even worse, you could have a class like this:

type TBar = class(TInterfacedObject, IFoo);

Now, the class would be TBar so what do you think would happen if you assign a TBar to a TFoo? These could be incompatible types...

An interface is nothing more than a definition of methods and where they can be found inside an object. Since multiple components can support the same interface, you're never sure that the interface is pointing to the right class. Which is why it's near-impossible to typecast an interface back to a class.

Can it be done? Sure, but the complexity is a bit much. Besides, it's a bit risky if the interface isn't a Delphi interface but created in some other application. If it is a Delphi interface then the interface is pointing to a class that is inherited from TObject. And TObject can tell you the exact class of the object. However, to get to the TObject from an interface??? I don't know exactly how to do that.
0
davelaneAuthor Commented:
Well when I meant stupid, I meant obvious :-( In VB this is possible (because even classes have hidden interfaces). And anyway my point is that this is a reasonable thing to want to do. Imagine a unit where I define 2 objects

  I1 = interface
    function DoSomething: integer;
  end;

  T1 = class(TIntefacedObject, I1)
  private
    InternalData: string;
    function DoSomethingInternal: integer;
  public
    function DoSomething: integer;
  end;

  T2 = class(TInterfacedObject)
  public
    function DoSomethingToAT1(T1Object: I1): integer;
  end;

In function DoSomethingToAT1 I want to be able to access the private functions and data on the object but I cant do this because they are not defined on the interface.
0
Wim ten BrinkSelf-employed developerCommented:
Unfortunately, what you are trying is just not allowed. You use an interface to make the object more abstract and once it's more abstract you can't undo it anymore. If your interface doesn't provide access to any private methods, you just don't have any access to them. Now, with this definition:

  T2 = class(TInterfacedObject)
  public
    function DoSomethingToAT1(T1Object: T1): integer;
  end;

Notice I use T1 instead of I1. This way you will get access to the private methods. Unfortunately this doesn't allow you to send the object over through it's interface.
0
Starting with Angular 5

Learn the essential features and functions of the popular JavaScript framework for building mobile, desktop and web applications.

j42Commented:
Hi davelane,

IM(H)O your should rethink about your design. If function DoSomethingToAT1(T1Object: I1) needs acess to private members of T1 then they are connected in some way. So decoupling (and as far as I understand that is what interfaces are for) is not neccessary and not possible. You could pass a T1 object to it - as Workshop_Alex said.
0
davelaneAuthor Commented:
Thanks for the replies guys,
like I said I came from VB, where this is allowed and oft used. Have been using Delphi for 2 years now, but have only now started using Interfaces under Delphi. Like I said I (still) don't think it is an unreasonable thing to want to do. Decoupling is one of the things that interfaces facilitate, but to say they are only for decoupled object is wrong IMHO. And anyway in my case the objects are not couipled. Take this example:
2 objects with interfaces IDatabaseTable and IRow. IDatabaseTable is basically a collection of IRows. Now say I have a function IDatabaseTable.Append(IRow). It is clear that this append function will want to do things to IRow that are not on the public interface. What would be good design in this case? A hidden interface with the necessary functions: IRowInternal?
0
j42Commented:
Well... I have never been into VB and database programming.

> public interface
I guess in  Delphi there is nothing like a 'hidden' or private interface.

> IDatabaseTable is basically a collection of IRows
I do not like that (maybe because interfaces are slightly different in VB). I would say:
TDatabaseTable (an implementation of IDatabaseTable) is a collection of TRow s which implement IRow.

What if there is something like IDatabaseTable.Append(IRow) and you 'cast' the IRow to a TRow. I can implement another class
with an IRow interface but completely different internals. Thus Append(IRow) will crash if I pass my object to it.
As far as I understand your problem you need a certain behaviour of your rows, so why not put it in the interface? Or something like
TRow = class(TWhatEver, IRow, IForInternalManipulation);

> but to say they are only for decoupled object is wrong
I am not a native english speaker so please do not take me to literal ;-)
0
davelaneAuthor Commented:
> TDatabaseTable (an implementation of IDatabaseTable) is a collection of TRow s which implement IRow.
You say don't take me too literally, but that is obviously what I meant. :-)

> I guess in  Delphi there is nothing like a 'hidden' or private interface.
Well by hidden I meant, not to include it in the .pas file that defines the public interfaces and / or not to include it in the tlb if and when it exists. TRow = class(TWhatEver, IRow, IForInternalManipulation); is exactly what I meant.

> What if there is something like IDatabaseTable.Append(IRow) and you 'cast' the IRow to a TRow. I can
> implement another class with an IRow interface but completely different internals. Thus Append(IRow)
> will crash if I pass my object to it.
Right, I will have to think about it though. The main reason for using interfaces in this case is to provide some kind of memory management.
0
j42Commented:
> in this case is to provide some kind of memory management.
Ok, another try (beside the whole communication stuff):

IRowWrapper = interface
  function GetRow: TRow;
end;

procedure IDatabaseTable.Append(ARow: IRowWrapper);
var
  row: TRow;
begin
  row := ARow.GetRow;
  row.AccesSomeVeryPrivateAndInSomeWayHiddenDataOfRow;
  ...
end;

This way you have reference counting, access to internals and no ugly casts.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
davelaneAuthor Commented:
Yeah, I've already done something similar (couldn't do exactly what you said due to a problem with circular references).

IRow = interface
  function GetClassPointer: Pointer;
end;

function TRow.GetClassPointer: Pointer;
begin
  result := Self;
end;

procedure IDatabaseTable.Append(ARow: IRow);
var
  row: TRow;
begin
  row := TRow(ARow.GetClassPointer);
  row.AccesSomeVeryPrivateAndInSomeWayHiddenDataOfRow;
  ...
end;

It ain't pretty but it works. Thanks for the help.
0
j42Commented:
I'm glad to be helpful!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.