Allowing breaking changes to break is good

I remember a discussion with a coworker some time ago… He came and proudly told me he always used “.AsString”, “.AsInteger”, etc when dealing with TField’s descendant instead of using “.Value”. His rational was that, if the field type changes, using Value would would not compile while using AsString would.

Take the following code :

  FField.AsString := 'Hello World';
  FField.Value    := 'Hello World';

If FField is a TWideString field, both line means essentially the same. On the other hand, If FField is a TIntegerField, the 2nd line won’t compile.

While I need to admit my coworker was right, his approach was certainly better than mine at making sure a given line of code will keep compiling in the future, he was also wrong in believing this was a good thing.

In this particular example, even though FField.AsString would keep compiling if FField become a TIntegerField, it would just raise an exception at runtime trying to convert ‘Hello World’ to an Integer.

Personally, I tend to favor coding approach that will allow the compiler to catch problems at compile time. It’s one of the perks of working with a strongly typed language.

So, what do *I* do? I always use Field.Value for typed TField. When I’m working with untyped TField variable, then I never use Field.Value.

    FTypedField   : TWideStringField;
    FUntypedField : TField;
    sSomeVariable : String;
  FTypedField.Value       := sSomeVariable ; 
  FUntypedField.AsString  := sSomeVariable ;

In this situation, if FTypedField becomes a TIntegerField, the code won’t compile. But why use AsString with an TField?  In this case, the advantage lies on the right side of the operation : If sSomeVariable’s type is changed, that won’t compile anymore.

Leave a Reply

Your email address will not be published. Required fields are marked *