[fpc-pascal] Question about interfaces and patch

ml ml at brainwashers.org
Thu Mar 24 19:58:02 CET 2005


On Thu, 2005-03-24 at 15:01 +0100, Michael Van Canneyt wrote:
> 
> On Thu, 24 Mar 2005, ml wrote:
> 
> > On Thu, 2005-03-24 at 09:06 +0100, Michael Van Canneyt wrote:
> >>
> >> On Thu, 24 Mar 2005 ml at brainwashers.org wrote:
> >>
> >>> Quoting Michael Van Canneyt <michael.vancanneyt at wisa.be>:
> >>>
> >>>>
> >>>>
> >>>> On Wed, 23 Mar 2005 ml at brainwashers.org wrote:
> >>>>
> >>>>> Quoting Marco van de Voort <marcov at stack.nl>:
> >>>>>
> >>>>>>> On Tue, 22 Mar 2005, ml wrote:
> >>>>>>>> // than one interface
> >>>>>>>>  a := (object as IA); // correct
> >>>>>>>>  b := (object as IB); // returns pointer to the first interface
> >>>>> vmt=IA
> >>>>>>>>  c := (object as IC); // returns pointer to the first interface
> >>>>> vmt=IA
> >>>>>>>> // there's no way to do again it's like direct call to exception
> >>>>>>>>  obj := a; // returns pointer(obj) + 12 ???
> >>>>>>>
> >>>>>>> This is nonsense. You cannot assign an interface to a class.
> >>>>>>> A class IMPLEMENTS an interface, it is not an interface.
> >>>>>
> >>>>> Ok, its nonsense. I said it already works with my patch, but I guess you
> >>>>> know it better. So my example down there doesn't work (with patch). You
> >>>>> should know.
> >>>>> I (; can't ;) transfer from one interface to other back to object and to
> >>>>> 3rd interface. I just imagine my results.
> >>>>
> >>>> Tell me, what is
> >>>>
> >>>>    obj := a;
> >>>>
> >>>> supposed to DO ? A class has a set of methods. Some of these methods form
> >>>> the VMT of an interface. What your code does, is say
> >>>> "don't use your VMT methods, use these instead' ?
> >>>
> >>> Yes, exactly. I even provided test example at the bottom of my previous message,
> >>> where I transfered from class to IA, back to class and then to ID. And called
> >>> ID.D; And it just works (this is also nice start for blind properties
> >>> implementation, which now also became possible, since original vmt is now visible)
> >>>
> >>> But, It should be used as
> >>>
> >>> if (TObject(a).InheritedFrom(TSomeClass)) then begin
> >>>  obj := TSomeClass(a); // note that here obj is declared as TSomeClass
> >>>  // now safely use as this vmt
> >>> end;
> >>>
> >>> if SupportsInterface(TObject(a), IB) then begin
> >>>  ibvar := a;  // declared ibvar: IB
> >>>  // now safely use as this vmt
> >>> end;
> >>>
> >>> in perfect world "is" would return InheritedFrom or SupportsInterface result and
> >>> not actual class check, if true then all needed operations are satisfied.
> >>
> >> I can understand that 'is' should be able to check interfaces; this is a
> >> useful patch.
> >>
> >> I also understand what your code should do.
> >>
> >> BUT I see some flaws in your design.
> >>
> >>   IA = Interface
> >>     procedure InitF;
> >>   end;
> >>
> >>
> >>   TA = class(TObject,IA)
> >>     F : TList;
> >>     Procedure InitF;
> >>     Procedure B;
> >>   end;
> >>
> >>   Procedure TA.InitF;
> >>
> >>   begin
> >>     F:=Tlist.Create;
> >>   end;
> >>
> >>   Procedure TA.B;
> >>
> >>   begin
> >>     F.Add(SomePointer);
> >>   end;
> >>
> >>
> >> Var
> >>    A : TA;
> >>    C : IA;
> >>
> >> begin
> >
> > Completely wrong type of thinking here, and I can't answer you what you
> > asked, so I provided answer why I can't answer and how it should be used
> >
> >>    A:=TA.Create;
> >>    C:=SomeIA;    // Get an IA interface from somewhere.
> >
> > Why would someone create one object just to override its variable with
> > some other value? To create memory leaks?
> 
> Hey, the
> 
>      A:=C;
> 
> was supposed to be the equivalent of YOUR code :
> 
>    // there's no way to do again it's like direct call to exception
>    obj := a; // returns pointer(obj) + 12 ???
> 

:) and that was taken from my first example where I showed problems, I
made at least 3 new examples after that (examples how it could be and
not showing where the problems are).

> 
> ?
> 
> [...]
> 
> > Here we go again. Your main problem is that you don't understand (or you
> > lack imagination) what interface is in his complete feature set. Main
> > feature of interfaces is to have ability to predict combinations of
> > commands that interfaces support, as I already specified... having
> > monolithic interface structure makes no sense (you just get mirror copy
> > of classes), it's a waste of time, paper and space. And before you
> > answer how it is not possible, or how you don't have time to implement
> > it.
> 
> I was not going to answer any of this, I'm trying to understand what you
> want to accomplish, and why this could be useful for other people.
> 
> > I'm game. I'm prepared to make all the necessary changes and
> > patches. All that I would ask for is a few pointers (if that could be
> > done on line on some irc or msn channel, that would be perfect, it's
> > hard to talk in one e-mail a day) how and where so that I don't need to
> > dissect complete compiler code (you probably understand that I'm not as
> > familiar with its code as you are, that would be only few questions like
> > "where does it...", "how does it...", "what would be the preffered
> > implementation of ...").
> >
> > Here is a simple example how it should be used
> >
> > type
> >  IReportable = interface
> >    function Report: string;
> >    // let's say that this should write report and
> >    // return status description as string
> >  end;
> >
> >  ILogged = interface
> >    procedure Log(aStr: string);
> >  end;
> >
> > And now some completely different place in your software, main feature
> > of interfaces is that you can predict possible features, and not even
> > start to implement them at that moment
> >
> > procedure MyXYZPart.DoReport(aRep: IReportable);
> > begin
> >  if (aRep <> nil) then begin
> >    if (aRep is ILogged) then
> >      (aRep as ILogged).Log(aRep.Report)
> >    else
> >      aRep.Report
> > end;
> 
> I see what you want, but if you would do
> 
> procedure MyXYZPart.DoReport(aRep: TInterfacedObject);
> 
> begin
>    if (aRep <> nil) and arep is IReportable then begin
>      if (aRep is ILogged) then
>        (aRep as ILogged).Log(aRep.Report)
>      else
>        aRep.Report
> end;
> 
> you would have the same effect ?
> 

Yeah, exactly like this. And now the bug of this effect. With this you
get a whole bunch of calling procedures and functions and all are
accepting TInterfacedObject parameter. You don't know what actual
parameter is. With passing interfaces as parameters code is much
cleaner. And all functions are defined as restrictive what kind of
interface is accepted.

> Necessarily, there is always SOME instance implementing any interface...
> 
> >
> > Meaning, that if I derived some class as (and call DoReport with it as
> > parameter)
> > type
> >  TSomeClass = interface(TInterfacedObject, IReportable, ILogged)
> >
> > this class will have to contain all the logging facility needed, and
> > that's conditioned with interfaces (otherwise it won't be compiled).
> >
> >  TSomeClass2 = interface(TInterfacedObject, IReportable)
> >
> > this class will automatically skip logging, because logging interface is
> > not supported by class
> >
> > What is difference here? I could pass a simple interfaced object as
> > parameter and predict possibility of logging. If object or interface
> > support that option then all the facility needed is supported and
> > logging is done.
> >
> > This is how and why interfaces should be used, for predicting features.
> > And with interfaces as they are this is just impossible.
> 
> But with a slight change in your code, I think it is, see above ?
> 

I see, and I named you reason why. Mostly readability of your code.

> If I understand you correct, you want to query the instance 'behind'
> some interface to see if it inmplements another interface, without
> having to access the actual instance ?
> 

Yes.

> This still does not explain why you would need to do
> 
>    AClassInstance := AnInterface;
> 

The only reason why, is mostly internal (where vmt problems were
discussed). If "is" and "as" would be solved as I suggested, this isn't
necessary anymore. Meaning I can test if original object (and not
interface) implements some other interface and then act as that
interface, then this is not necessary anymore. 
 
Having ability to do

  if (aRep is ILogged) then
    (aRep as ILogged).Log(aRep.Report);

would make clean code, where possible calling parameter is obvious

Second reason why could be treated as internal too.

For now you have to specify properties as

type
  IA = interface
    function GetSome: integer;
    procedure SetSome(aValue: integer);
    property Some: integer read GetSome write SetSome;
  end;

this is needed because interface has no clue of original vmt. while
blind properties definition would be

type
  IA = interface
    property Some: integer read object write object;
  end;

and the implementation of property is left to class, not conditioned
with function and procedure

Follow the vmt problems. That is needed for defining blind properties.
Blind property has to be redirected to original vmt of class.


ml

> Which seems to me against all pascal rules of strict typing ?
> 
> Michael.
> 
> _______________________________________________
> fpc-pascal maillist  -  fpc-pascal at lists.freepascal.org
> http://lists.freepascal.org/mailman/listinfo/fpc-pascal





More information about the fpc-pascal mailing list