20

I'm pretty new to C# so bear with me.

One of the first things I noticed about C# is that many of the classes are static method heavy. For example...

Why is it:

Array.ForEach(arr, proc)

instead of:

arr.ForEach(proc)

And why is it:

Array.Sort(arr)

instead of:

arr.Sort()

Feel free to point me to some FAQ on the net. If a detailed answer is in some book somewhere, I'd welcome a pointer to that as well. I'm looking for the definitive answer on this, but your speculation is welcome.

dharmatech
  • 7,399
  • 7
  • 32
  • 65

6 Answers6

11

Because those are utility classes. The class construction is just a way to group them together, considering there are no free functions in C#.

vcsjones
  • 128,004
  • 28
  • 283
  • 274
K-ballo
  • 76,488
  • 19
  • 144
  • 164
  • 1
    I wouldn't call `Array` a utility class. It's the abstract base class which all arrays derive...which seems like a good place to make these instance methods. I think this is a good question. – Daniel Oct 24 '11 at 04:21
  • @Daniel Maybe Array isn't a utility class per se, but the static methods it offers sure look like utility methods that were grouped in it. – Christian Oct 24 '11 at 05:55
  • disagree they clearly are taking a reference to their own object so they really should be methods, they probably still could be changed to be extension methods, but this may have too low cost/benefit – jk. Oct 24 '11 at 08:09
8

Assuming this answer is correct, instance methods require additional space in a "method table." Making array methods static may have been an early space-saving decision.

This, along with avoiding the this pointer check that Amitd references, could provide significant performance gains for something as ubiquitous as arrays.

Community
  • 1
  • 1
Daniel
  • 46,089
  • 10
  • 89
  • 172
  • The question/answer you linked to is what I was looking for. Thanks! I discovered `List` a few minutes ago and that class works in a way that I was expecting. The answer there gets into why Array and List are designed differently. – dharmatech Oct 24 '11 at 04:46
  • In fact, if one of the admins wants to mark this as a duplicate of the question you linked to, that would be OK with me. – dharmatech Oct 24 '11 at 05:05
6

Also see this rule from FXCOP

CA1822: Mark members as static

Rule Description

Members that do not access instance data or call instance methods can be marked as static (Shared in Visual Basic). After you mark the methods as static, the compiler will emit nonvirtual call sites to these members. Emitting nonvirtual call sites will prevent a check at runtime for each call that makes sure that the current object pointer is non-null. This can achieve a measurable performance gain for performance-sensitive code. In some cases, the failure to access the current object instance represents a correctness issue.

Amitd
  • 4,691
  • 8
  • 51
  • 82
2

Perceived functionality.

"Utility" functions are unlike much of the functionality OO is meant to target.

Think about the case with collections, I/O, math and just about all utility.

With OO you generally model your domain. None of those things really fit in your domain--it's not like you are coding and go "Oh, we need to order a new hashtable, ours is getting full". Utility stuff often just doesn't fit.

We get pretty close, but it's still not very OO to pass around collections (where is your business logic? where do you put the methods that manipulate your collection and that other little piece or two of data you are always passing around with it?)

Same with numbers and math. It's kind of tough to have Integer.sqrt() and Long.sqrt() and Float.sqrt()--it just doesn't make sense, nor does "new Math().sqrt()". There are a lot of areas it just doesn't model well. If you are looking for mathematical modeling then OO may not be your best bet. (I made a pretty complete "Complex" and "Matrix" class in Java and made them fairly OO, but making them really taught me some of the limits of OO and Java--I ended up "Using" the classes from Groovy mostly)

I've never seen anything anywhere NEAR as good as OO for modeling your business logic, being able to demonstrate the connections between code and managing your relationship between data and code though.

So we fall back on a different model when it makes more sense to do so.

Bill K
  • 60,031
  • 14
  • 96
  • 147
1

The classic motivations against static:

  1. Hard to test
  2. Not thread-safe
  3. Increases code size in memory

1) C# has several tools available that make testing static methods relatively easy. A comparison of C# mocking tools, some of which support static mocking: https://stackoverflow.com/questions/64242/rhino-mocks-typemock-moq-or-nmock-which-one-do-you-use-and-why

2) There are well-known, performant ways to do static object creation/logic without losing thread safety in C#. For example implementing the Singleton pattern with a static class in C# (you can jump to the fifth method if the inadequate options bore you): http://www.yoda.arachsys.com/csharp/singleton.html

3) As @K-ballo mentions, every method contributes to code size in memory in C#, rather than instance methods getting special treatment.

That said, the 2 specific examples you pointed out are just a problem of legacy code support for the static Array class before generics and some other code sugar was introduced back in C# 1.0 days, as @Inerdia said. I tried to answer assuming you had more code you were referring to, possibly including outside libraries.

Community
  • 1
  • 1
Chris Moschini
  • 33,398
  • 18
  • 147
  • 176
  • 2
    Why would I test framework methods? Are you answering the question or just talking about to define static methods or not in your code? – manojlds Oct 24 '11 at 02:10
  • 1
    The question asked why so many statics in C#, not why so many in the framework specifically. The 2 examples happened to be very old, well-tested framework methods, but I assumed the question is about C# libraries and code in general. I will also point out that there are newer framework methods with less testing that can be worth writing your own test for when your code just won't work as expected - not all that Microsoft makes is bug-free. – Chris Moschini Oct 24 '11 at 14:34
0

The Array class isn't generic and can't be made fully generic because this would break backwards compatibility. There's some sort of magic going on where arrays implement IList<T>, but that's only for single-dimension arrays with a lower bound of 0 – "list-ish" arrays.

I'm guessing the static methods are the only way to add generic methods that work over any shape of array regardless of whether it qualifies for the above-mentioned compiler magic.

millimoose
  • 36,982
  • 8
  • 75
  • 128
  • 1
    You've always been able to treat any array type (`string[]`, `int[]`, etc) as an instance of `Array`, so I don't think the _lack of generics_ argument holds. – Daniel Oct 24 '11 at 04:22
  • @Daniel: My point is, arrays don't have *any* instance methods where the signature features the type of the element. `List` and such do – this makes me think the "utility functions" explanation doesn't hold water. So it seems that arrays are "special" somehow. And since the "specialness" is the lack of instance methods with a type parameter of the receiver in the signature - *generic* methods, my conclusion is that arrays, in the general case, just aren't generic. – millimoose Oct 24 '11 at 11:01