Question

In C#, for instance, there are static methods for telling if a string is null or empty, finding an element in an array, clearing an array, etc. However there's an instance method for replacing characters in a string, and both static and instance methods for copying elements between arrays.

Similarly, in Python there are functions for getting the length of a list, to filter a list, etc., but instance methods for finding the index of an element and for copying the list.

Contrarily, in JavaScript, pretty much any operation I need to do on a built in data type will be accessible via instance method or property.

So what is the rationale for making certain things static and others not?

EDIT: To be clear, I understand the purpose of static methods. My question is more towards why certain methods are written as static when they could have been written as instance methods. Like Find for arrays and Format for strings in C#, and filter and len in Python.

Was it helpful?

Solution

EDIT: the question has been refined so I'll refine my answer, but leave the previous one below so as to not make the comments irrelevant.

There can be several reasons to implement a method as a static method instead of an instance method, with different languages or frameworks possibly having different rationales:

  1. An object's public interface is a contract. If your Array type exposes a Sort method, every array from now on, regardless of type or version of the language needs to support it. If, however, an Array is just a representation of data in memory with a thin contract, and logic is moved to a class like Array.Sort, it gives you more flexibility to extend or modify your behavior while not breaking compatibility.

  2. See this quote from Bob Martin's Clean Code:

Objects expose behavior and hide data; Data structure expose data and have no significant behavior"

In this case, the List class is a class that exposes behavior - it hides its data (It's implemented as a resizable array, but that's an implementation detail), but exposes functionality. An int[], though, is a data structure. It's a sequentially allocated int block. It has a Length property because it's part of its data, but doesn't have much behavior - the behavior is offloaded to a class that operates on it.

  1. It might be a stylistic choice. Python isn't a purely OO language, and might not have the Java/C# "everything is an object" guarantee, so it chose to use language functions like len() that can be used regardless of whether its parameter is an object instance or not.

Previous Answer

The rationale behind static methods in C# is to have methods which are tied to a type but not to an instance. There can be several reasons for that:

  1. Methods that can operate on both an instance and null, like string.IsNullOrEmpty, naturally can't be instance methods - because there might not be an instance.
  2. Factory methods that create an instance, similarly, have no instance to be called from. For example, the someone deprecated static WebRequest.Create() method returns a new instance of a type derived from WebRequest.
  3. While it's easy to forget, .NET does have different handling for a native integral type (int i =5) and a boxed reference type around it (object boxed = 5). If you call a method on a value type (int i = 5; t.ToString();), you incur a cost of boxing it. That's why some operations aren't defined as a method on an object, but as a static method that accepts a value. That's why mathematical operations like Math.Abs aren't defined as methods on the boxed types, but as static functions that receive and return values.
  4. Sometimes static methods are used to "configure" a type, not one specific instance but the behavior of that type in the system. For instance, [ServicePointManager.SetTcpKeepAlive()][1] configures the behavior of all classes that use the shared HTTP(s) stack in .NET, so you can configure them all via these static methods.

OTHER TIPS

Static methods make a lot of sense

  • when the method is related to the type but does not require an existing instance; or
  • when the language supports namespacing only via classes.

C# only supports functions as members of classes, so helper functions should be written as static methods. The C# Math class is a prime example.

JavaScript doesn't have classes, but every non-local variable is associated with some object – in the browser, most APIs are accessible through the window object. However, there are methods that are accessible through a class-like object, e.g. Array.isArray(x).

Python is has an idiosyncratic design that's mostly object-oriented, but has some built-in functions like len() or iter(), largely for historical reasons. Under the hood, they invoke actual methods, e.g. iter(x) is usually x.__iter__(), with a fallback for objects that can be indexed like a list.

More interesting are methods that are static not because of quirks of the language, but because it makes sense. Constructor-like or factory-like methods are the classic example where we don't have an existing object that we could call a method on. Some functions also don't operate on exactly one object, e.g. String.IsNullOrEmpty(x) operates on zero or one objects. This doesn't work as a method, e.g. x.IsNullOrEmpty() would throw an exception if it's null! The Array.isArray(x) method in JS is another great example: we want to call isArray(x) on objects of any type, not just on arrays. Thus, an instance method doesn't work unless it's part of the prototype of every object.

Licensed under: CC-BY-SA with attribution
scroll top