Initialization Pattern?

Initialization Pattern?

type

  TIdentification = (Foo, Bar, Fubar, Snark, Plugh, Plover);

  TAssociation = (Ninja, Cowboy, Pirate);

  TIdAssoArray = array[TIdentification] of TAssociation;

var // or const

  IdentityToType : TIdAssoArray;

What is the best way of initializing IdentityToType so that it is robust against adding, removing or reordering the TIdentity members?

17 thoughts on “Initialization Pattern?


  1. Actually the most robust way is not having an array at all but a list with records/classes that contain TIdentification and TAssociation and a check procedure that is called from the initialization section.


    Not the best performance though.


  2. I’m currently doing a loop for t := low(TIdentification) to high(TIdentification) and a case statement, but it’s getting harder to maintain, as the number of ids and associations goes up.


  3. Declaring IdentityToType as const is only robust against adding/removing but not to reordering TIdentification. But for me that is usually good enough – you might put a comment there saying that if changing the order you must modify the const.


  4. Asbjørn Heid – The intent is to have it tightly coupled. 


    I wish it would have been possible to have a construct similar to


    const 


      IdentityToType = TIdAssoArray(


       (Foo: Ninja),


       (Bar: Pirate),


       (Fubar: Ninja),  


       (Snark: Pirate),


       (Plugh: Ninja),  


       (Plover: Cowboy) );


    which would complain on missing, duplicate or unknown elements.


  5. To check the pattern at runtime, use:


    function Check_TIdentification: Boolean;


    var


      tid: TIdentification;


    const


      tidName : array[TIdentification] of String = (


        ‘Foo’,


        ‘Bar’,


        ‘Fubar’,


        ‘Snark’,


        ‘Plugh’,


        ‘Plover’);


    begin


      for tid := Low(TIdentification) to High(TIdentification) do


      begin


        if (GetEnumName(TypeInfo(TIdentification),Ord(tid)) tidName[tid]) then


          Exit(False);


      end;


      Result := true;


    end;


    This will catch adding,removing and reordering.


  6. Leif Uneus And why does that require the enum name? 😉


    function Check_TIdentification: Boolean;


    const


      IdValues: array[TIdentification] of TIdentification = (


        Foo, Bar, Fubar, Snark, Plugh, Plover);


    var


      id: TIdentification;


    begin


      for id := Low(TIdentification) to High(TIdentification) do


        if id IdValues[id] then


          Exit(False);


      Result := true;


    end;


  7. Leif Uneus – No, no and no.  That’s introducing yet another order that needs to be maintained.  Here is what I do now.


    procedure InitIdentities;


    var


      t: TIdentification;


    begin


      for t := Low(IdentityToType) to (High(IdentityToType)


      do Case t of


       Foo,


       Fubar,  


       Plugh: IdentityToType[t] := Ninja;


       Bar, 


       Snark: IdentityToType[t] := Pirate;


       Plover: IdentityToType[t] := Cowboy;


       else raise EIdentificationConfigError.Create(‘Missing init for ‘ + GetEnumName(TypeInfo(TIdentification), Ord(t)));


      end;


    end; 


    Which will detect missing inits at first try – but – I’d rather have that check done at compile time, and have the Identity and Association relationships clearly defined in the source.  The above is a bit messy when you start running into larger numbers of Identities and Associations.


  8. Personally I hate wasting my time writing code to prevent stupid programmers from breaking anything.


    A comment stating that you have to reorder the const array when you change the order of the enum should suffice. And for any mistakes: commit history/blame is your friend.


  9. Sure, but imagine manually changing the order of 50+ submatrixes… That’s a rather error prone task.  


    I guess I just want constant array declarations to be smarter.


  10. Ok, here is another alternative:


    procedure InitAsso(var asso: TIdAssoArray);


    Type


      TIdAssoRec = record


        id : TIdentification;


        asso: TAssociation;


      end;


    const


      IdAssoRecArr : array[TIdentification] of TIdAssoRec =


       ((id:Foo;   asso:Ninja),


        (id:Bar;   asso:Ninja),


        (id:Fubar; asso:Cowboy),


        (id:Snark; asso:Pirate),


        (id:Plugh; asso:Pirate),


        (id:Plover;asso:Cowboy));


    var


      tid: TIdentification;


    begin


      for tid := Low(TIdentification) to High(TIdentification) do


      begin


        if (tid IdAssoRecArr[tid].id) then


          raise Hell;


        asso[tid] := IdAssoRecArr[tid].asso;


      end;


    end;


    Perhaps easier to maintain, but still ugly and still a runtime (mostly) check.


  11. Stefan Glienke Yes, it could have been done without strings. My mind was set on next step where perhaps the array would have to be stored and must handle reordering. I guess using enumerations here is a bit of an antipattern for large enumeration items.


  12. You could also do this:


    Type


      TIdAssoRec = record


      private


        id : TIdentification;


        asso: TAssociation;


        class function Init(i: TIdentification;a:TAssociation): TIdAssoRec; static;


      public


        class procedure InitAsso(var asso: TIdAssoArray); static;


      end;


    class function TIdAssoRec.Init(i: TIdentification; a: TAssociation): TIdAssoRec;


    begin


      Result.id := i;


      Result.asso := a;


    end;


    class procedure TIdAssoRec.InitAsso(var asso: TIdAssoArray);


    var


      IdAssoRecArr: TArray;


      tid: TIdentification;


    begin


      IdAssoRecArr :=


       [Init(Foo,    Ninja),


        Init(Bar,    Ninja),


        Init(Fubar,  Cowboy),


        Init(Snark,  Pirate),


        Init(Plugh,  Pirate),


        Init(Plover, Cowboy)];


      if (High(IdAssoRecArr) Ord(High(TIdentification))) then


        raise Hell;


      for tid := Low(TIdentification) to High(TIdentification) do


      begin


        if (tid IdAssoRecArr[Ord(tid)].id) then


          raise Hell;


        asso[tid] := IdAssoRecArr[Ord(tid)].asso;


      end;


    end;

Leave a Reply