Simple Generics: A way to reduce the number of explicit declarations for action, setter and getter types.

Simple Generics: A way to reduce the number of explicit declarations for action, setter and getter types.

 

type

  // procedure/function pointers

  TPtrProc = procedure;

  TPtrParamProc = procedure (const v: TA);

 

  TPtrFunc= function:TR;

  TPtrParamFunc = function(const v:TA):TR;

 

  // Anonymous procedure type templates

  TAnonProc = reference to procedure;

  TAnonParamProc = reference to procedure (const v:TA);

 

  TAnonFunc= reference to function:TR;

  TAnonParamFunc = reference to function (const v:TA):TR;

 

  // Object method variable type templates

  TObjectProc = procedure of object;

  TObjectParamProc = procedure (const v:TA) of object;

 

  TObjectFunc= function:TR of object;

  TObjectParamFunc = function (const v:TA):TR of object;

 

Allows you to declare like this

 

.. property OnChangeTime: TObjectParamProc;

.. property OnValidate: TAnonParamFunc;

 

You can of course be explicit with these as well…

type

  TOnTimeChange = TObjectParamProc;

  TOnValidate = TAnonParamFunc;

11 thoughts on “Simple Generics: A way to reduce the number of explicit declarations for action, setter and getter types.


  1. Be careful with your naming since some of them (like TProc and TFunc) are already defined in the RTL and may cause conflicts.


    Also you might want to add {$M+} to the delegate types (something I suggested to Barry long time ago to do with those in SysUtils and which never happened).


  2. Quite possibly, melice huang.  


    The point is not reusing THIS code, though – but showing how a few lines of Generics can reduce the need for declaring single purpose types. 


  3. That reduces the number of explicit declarations at the cost of making the size of each type reference larger, so in terms of number of characters to type (and read), I guess it’ll come out worse in many cases.


    Also it’s just me maybe, but I find those and repeated types everywhere awfully confusing.


    The expliciting you’re doing at the end is much cleaner IMHO… though it negates the whole point of having generics in the first place. Single purpose types have their use: they can clarify code!


    Your snippets hit squarely on the issue with generic types: they’re cumbersome to type, write and read (just like the horribly verbose anonymous method syntax for that matter)


  4. Those are absolutely valid objections, but between these;


    var


      ActionResult: TMyTypeActionResult;


      ActionResult: TObjectParamFunc;


    I prefer the latter, since I don’t have to visit the the other declaration to see how it is declared.


  5. I don’t prefer the later, because it lacks a very important information; what do those parameters means?


    f.i.a TXYEvent and a TCompareIntegerEvent would both show up as TObjectParamFunc


    While the first will obviously be passing x & y coordinates, the second would be asking you to perform a comparison between two integers, etc.


    TFunc on the other hand isn’t very expressive…


  6. But then you’re essentially moving the onus of meaningfulness from the type system solely to the variable/member names.


    TNotifyEvent states a notification intent, TProc states nothing and just looks cryptic 🙂


  7. Not solely, as you know how the type is declared, and once you start reusing it, that purpose becomes even clearer.


    TNotifyEvent is abused a lot and not exactly type safe.  How many Notification handlers do you have where you never accessed Sender? Of the times you did access sender – how many times did you type cast?


  8. Good points, it can be abused.


    But then a TUserChangedEvent is still preferable to a TProc, it’s more readable, easier to type and can be auto-completed anyway.


    When there are more than one params is when generic procedure types become completely cryptic, they look like the output from an automated disassembly, rather than a human-written bit of code.

Leave a Reply