views:

238

answers:

4

What is the difference between these two pieces of code

type
  IInterface1 = interface
    procedure Proc1;
  end;

  IInterface2 = interface
    procedure Proc2;
  end;

  TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
  protected
    procedure Proc1;
    procedure Proc2;
  end;

And the following :

type
  IInterface1 = interface
    procedure Proc1;
  end;

  IInterface2 = interface(Interface1)
    procedure Proc2;
  end;

  TMyClass = class(TInterfacedObject,  IInterface2)
  protected
    procedure Proc1;
    procedure Proc2;
  end;

If they are one and the same, are there any advantages, or readability issues with either.

I guess the second means you cannot write a class that implements IInterface2 without implementing IInterface1, whilst with the first you can.

+1  A: 

Assuming you meant

...
IInterface2 = interface(Interface1)
...

I interpret it the same as you, the second form requires a class implementing Interface2 to implement Interface1 as well, while the first form does not.

Joe Skora
+1  A: 

I guess the second means you cannot write a class that implements IInterface2 without implementing IInterface1, whilst with the first you can.

That would be the technical difference.

Which one is better depends very much on what the interfaces actually are. Does it ever make sense for an IInterface2 to exist without it also being an IInterface1?

If IInterface1 is "displayable" and IInterface2 is "storable," then the first option probably makes more sense. If IInterface1 is "vehicle" and IInterface2 is "truck," then the second option probably makes much more sense.

Glomek
+3  A: 

First off, I'm assuming that the second example's declaration for IInterface2 is a typo and should be

IInterface2 = interface(Interface1)

because inheriting from itself is nonsensical (even if the compiler accepted it).

And "inheriting" is the key word there for answering your question. In example 1 the two interfaces are completely independent and you can implement one, the other, or both without problems. In example 2, you are correct that you can't implement interface2 without also implementing interface1, but the reason why that's so is because it makes interface1 a part of interface2.

The difference, then, is primarily structural and organizational, not just readability.

Dave Sherohman
yes...typo sorry!
Steve
+6  A: 

The two snippets of code have very different effects, and are in almost no way equivalent, if we are talking about Delphi for Win32 (Delphi for .NET has different rules).

  1. A class that implements its interface must implement all the members of that interface's ancestors, but it does not implicitly implement the ancestors. Thus, attempts to assign instances of type TMyClass to locations of type IInterface1 will fail for the second case.
  2. Related to the previous point, if IInterface1 and IInterface2 both had GUIDs, dynamic casts (using Supports or 'as') of interface references with a target type of IInterface1 would fail on instances of TMyClass in the second case.
  3. The interface IInterface2 has an extra method in the second case, which it does not in the first.
  4. Values of type IInterface2 in the second case are assignable to locations of type IInterface1; this is not true for the first case.

See for yourself in this example:

    type
      A_I1 = interface
      end;

      A_I2 = interface(A_I1)
      end;

      A_Class = class(TInterfacedObject, A_I2)
      end;

    procedure TestA;
    var
      a: A_Class;
      x: A_I1;
    begin
      a := A_Class.Create;
      x := a; // fails!
    end;

    type
      B_I1 = interface
      end;

      B_I2 = interface
      end;

      B_Class = class(TInterfacedObject, B_I1, B_I2)
      end;

    procedure TestB;
    var
      a: B_Class;
      x: B_I1;
    begin
      a := B_Class.Create;
      x := a; // succeeds!
    end;

    begin
      TestA;
      TestB;
    end.
Barry Kelly