Class Methods vs Instance Methods

C# implements BigInteger.Parse as a static class method, and there is obvious reason for it: you can call a static class methods in a variable’s declaration:

  BigInteger N = BigInteger.Parse(stringToParse);

Delphi/Pascal does not support the above syntax, so the equivalent code is

var
  N: BigInteger;
begin
  N:= BigInteger.Parse(stringToParse);

But now it looks like implementing BigInteger.Parse as a static class method is nothing but additional typing; using an instance method looks better:

var
  N: BigInteger;
begin
  N.Parse(stringToParse);

So, what is the right “Delphi way” of implementing BigInteger.Parse – as a static class method or as an instance method?

Advertisements

9 thoughts on “Class Methods vs Instance Methods

  1. Since BigInteger is a record, your N variable is already allocated/constructed, so N.Parse() sounds just fine to me. For a class, it may have been unsafe (since N would be filled with a garbage pointer from the stack), but for a record/object, my guess is that an instance method is the “Delphi way”, since the instance is already existing on the stack.

    • There is no safety problems with TForge implementation, the method can be implemented both ways – as a static class method or as an instance method. Just a matter of choice.

  2. Which do you prefer:

    foo(BigInteger.Parse(stringToParse));
    

    or

    var
      tmp: BigInteger;
    ....
      tmp.Parse(stringToParse);
      foo(tmp);
    

    And how about:

    List[i] := BigInteger.Parse(stringToParse);
    

    or

    var
      tmp: BigInteger;
    ....
      tmp.Parse(stringToParse);
      List[i] := tmp;
    

    The latter is needed to avoid falling into the well known trap of

    List[i].Parse(stringToParse);
    

    which simply modifies a transient copy.

    • How about TryParse? it can be implemented as an instance method:

          function BigInteger.TryParse(const S: string): Boolean;
      

      or as a static class method:

          class function BigInteger.TryParse(const S: string; var N: BigInteger): Boolean; static;
      

      The arguments in favor of a static class method implementation do not apply here.

      • But now you’ve got inconsistency because you use static class functions sometimes, and instance methods other times.

        What’s more you have given up immutability which I regard as desirable for a numeric value type.

        What benefit does the instance method bring?

  3. Since Delphi has a long history of global procedures, I would say that the Static method is what fits in a readable and understandable progression. You can think of a static method as a global procedure or function that lives in a nicer namespace, and doesn’t pollute your code as much as if you just wrote StrToBigInteger() like it was 1975. Remember to optimize for consistency and readability as much as for usefulness. Developer brains should be trained to follow certain patterns. These patterns have been thought out. Because you are returning a record, which is a value type, I believe you should do what you would do in C# or java and use static method.

  4. I’d go with the static method

    I do so also when using enumeratives: I declare the corresponding record helper and then implement a static TMyEnum.Parse(whatever)

  5. Just look at the mess that is Boolean.ToString (via class helpers),

    Boolean.ToString() is mixed with Boolean.ToString(). One follows the BoolToStr pattern, but does exactly the wrong thing all of the time..

    program Project1;

    {$APPTYPE CONSOLE}

    uses
    System.SysUtils;

    Var
    B : Boolean;

    Begin
    B := False;
    Writeln(B.ToString(True)); // Always prints “-1” regardless of B’s value
    Writeln(B.ToString(TUseBoolStrs.True)); // prints “false”
    Readln;
    End.

    Basically, either way, make sure what you do makes sense in all usage patterns, don’t be a Boolean.ToString.

    In this case, both approaches produce the expected result cases – you can do both and people can use either without confusion. Proper use of Inline; will solve code overhead problems and allow for code reuse.

  6. There are various reasons to use static methods. David Heffernan already mentioned a few: syntax and immutability. Sure, you could have an instance method returning a new instance, but that would violate the principle of least astonishment, since people expect instance methods to modify the instance. And I agree with him that BigIntegers should preferrably be immutable.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s