Search code examples
classdelphitypesprivate

In Delphi, how do I make a type passable only between functions/methods of a class


I currently have the following code;

   interface

   {...}   

   type
      TMyRecord = record
        List : TShellList;
        Tree : TShellTree;
        Image : TImage;
      end;

      TSDIAppForm = class(TForm)
        { Published declarations }
      private
        function GetChildren(Sheet : TTabSheet) : TMyRecord;
      public
        { Public declarations }
      end;

As I understand it this means that TMyRecord is a global type visible to the whole program. The type only needs to be visible within the class, although objects of the type do need to be passed and returned as parameters to between "private" functions/procedures of the class. How can I do that? I can't declare the type under the "private" part of the class interface, and if I declare it in the implements then I don't believe it is visible to be used in the interface function prototypes. Also, I think implements/interface relate more to visibility within the unit than the class. Do I need to declare theGetChildren() function in some other way?


Solution

  • As noted in other answers, in versions of Delphi that support nested types you can simply declare the type within the required scope and visibility.

    For older versions of Delphi you can achieve a similar outcome by using an untyped var parameter to avoid having to reference the 'private type' in the interface section of your unit:

    TSDIAppForm = class(TForm)
      ..
      procedure GetChildren(Sheet : TTabSheet; var aRecord);
      ..
    end;
    

    For convenience and declarative type enforcement in the implementation of the method you can use an absolute declaration to create a local variable to act as placeholder for the untyped parameter:

    procedure TSDIAppForm.GetChildren(    Sheet : TTabSheet; 
                                      var aRecord);
    var
      result: TMyRecord absolute aRecord;
    begin
      result.List := ...;
      // etc
    end;
    

    In this case, since the function has no direct return value and uses the var param in a directly analagous way you might choose to use the name result, as illustrated. Or of course you can use any other name for the local variable you prefer.

    In use, you would simply call this method as normal with an appropriate variable in the var param:

    var
      myRec: TMyRecord;
    begin
      ..
      sdiForm.GetChildren(someSheet, myRec);
      ..
    end;
    

    In this way, you can keep a type which is an implementation detail truly confined to the implementation section of your unit.

    NOTE: This technique can also be useful in situations where typed var parameters might otherwise cause the compiler to complain about 'formal var parameter types not matching'.

    You should of course always consider carefully whether they are the right approach. Not least because whenever you use untyped parameters of course you take on a greater responsibility for ensuring type safety in your code. The potential for abuse should be obvious, but they sometimes offer advantages as well (as in this case, removing entirely a type from the interface section that is arguably most properly entirely confined to the implementation section).

    They can also be a useful tool to keep in mind if you create code that you might wish to make available to users of older versions of Delphi where private types etc are not available.