[fpc-pascal] Question about interfaces and patch

Michael Van Canneyt michael at freepascal.org
Thu Mar 24 21:21:02 CET 2005



On Thu, 24 Mar 2005, ml wrote:

[Cut]
> > >
> > > 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.

OK, now I see where you're going.

Your last sentence means: I want DoReport to accept only an 'IReportable'
But at the same time, your code is checking that behind 'IReportable'
there is also an 'ILogged'.

I find this a bit contradictory; If you pass an TInterfacedObject, then
you can check for as much classes or interfaces as you want.
The code remains the same. But this is not a principal question.

More important is: what happens if IReportable is an interface obtained
from Windows ? How can you tell whether an interface comes from a Pascal
class, or was obtained from a Windows OLE or ActiveX server ?
There may not be a a real class behind IReportable.
You can construct IReportable interfaces on the fly.
(OpenOffice does it, and I think some SOAP implementations as well)


> > 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

I think the properties are needed, to remain compatible with COM
interfaces, which only have methods, I think CORBA has this restriction
too; They don't have 'properties'.

After all the discussion, I see 2 real improvements:
- To be able to use 'Is' operator  on interfaces.
  (so without the need for 'Supports')
- Use 'as' on interfaces. (But this should be possible as in Delphi)

As for querying the class behind the interface: first you need to answer the
windows problem.

Michael.




More information about the fpc-pascal mailing list