Why C# is not allowing non-member functions like C++

25,124

Solution 1

See this blog posting:

http://blogs.msdn.com/ericlippert/archive/2009/06/22/why-doesn-t-c-implement-top-level-methods.aspx

(...)

I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen. All of them cost huge amounts of time, effort and money. Features are not cheap, and we try very hard to make sure that we are only shipping those features which give the best possible benefits to our users given our constrained time, effort and money budgets.

I understand that such a general answer probably does not address the specific question.

In this particular case, the clear user benefit was in the past not large enough to justify the complications to the language which would ensue. By stricting how different language entities nest inside each other we (1) restrict legal programs to be in a common, easily understood style, and (2) make it possible to define "identifier lookup" rules which are comprehensible, specifiable, implementable, testable and documentable.

By restricting method bodies to always be inside a struct or class, we make it easier to reason about the meaning of an unqualified identifier used in an invocation context; such a thing is always an invocable member of the current type (or a base type).

(...)

and this follow-up posting:

http://blogs.msdn.com/ericlippert/archive/2009/06/24/it-already-is-a-scripting-language.aspx

(...)

Like all design decisions, when we're faced with a number of competing, compelling, valuable and noncompossible ideas, we've got to find a workable compromise. We don't do that except by considering all the possibilites, which is what we're doing in this case.

(emphasis from original text)

Solution 2

C# doesn't allow it because Java didn't allow it.

I can think of several reasons why the designers of Java probably didn't allow it

  • Java was designed to be simple. They attempted to make a language without random shortcuts, so that you generally have just one simple way to do everything, even if other approaches would have been cleaner or more concise. They wanted to minimize the learning curve, and learning "a class may contain methods" is simpler than "a class may contain methods, and functions may exist outside classes".
  • Superficially, it looks less object-oriented. (Anything that isn't part of an object obviously can't be object-oriented? Can it? of course, C++ says yes, but C++ wasn't involved in this decision)

As I already said in comments, I think this is a good question, and there are plenty of cases where non-member functions would've been preferable. (this part is mostly a response to all the other answers saying "you don't need it")

In C++, where non-member functions are allowed, they are often preferred, for several reasons:

  • It aids encapsulation. The fewer methods have access to the private members of a class, the easier that class will be to refactor or maintain. Encapsulation is an important part of OOP.
  • Code can be reused much easier when it is not part of a class. For example, the C++ standard library defines std::find or std::sort` as non-member functions, so that they can be reused on any type of sequences, whether it is arrays, sets, linked lists or (for std::find, at least) streams. Code reuse is also an important part of OOP.
  • It gives us better decoupling. The find function doesn't need to know about the LinkedList class in order to be able to work on it. If it had been defined as a member function, it would be a member of the LinkedList class, basically merging the two concepts into one big blob.
  • Extensibility. If you accept that the interface of a class is not just "all its public members", but also "all non-member functions that operate on the class", then it becomes possible to extend the interface of a class without having to edit or even recompile the class itself.

The ability to have non-member functions may have originated with C (where you had no other choice), but in modern C++, it is a vital feature in its own right, not just for backward-comparibility purposes, but because of the simpler, cleaner and more reusable code it allows.

In fact, C# seems to have realized much the same things, much later. Why do you think extension methods were added? They are an attempt at achieving the above, while preserving the simple Java-like syntax. Lambdas are also interesting examples, as they too are essentially small functions defined freely, not as members of any particular class. So yes, the concept of non-member functions is useful, and C#'s designers have realized the same thing. They've just tried to sneak the concept in through the back door.

http://www.ddj.com/cpp/184401197 and http://www.gotw.ca/publications/mill02.htm are two articles written by C++ experts on the subject.

Solution 3

Non member functions are a good thing because they improve encapsulation and reduce coupling between types. Most modern programming languages such as Haskell and F# support free functions.

Solution 4

What's the benefit of not putting each method in a named class? Why would a non-member function "pollute" the class's interface? If you don't want it as part of the public API of a class, either don't make it public or don't put it in that class. You can always create a different class.

I can't remember ever wanting to write a method floating around with no appropriate scope - other than anonymous functions, of course (which aren't really the same).

In short, I can't see any benefit in non-member functions, but I can see benefits in terms of consistency, naming and documentation in putting all methods in an appropriately named class.

Solution 5

The CLS (common language specification) says that you shouldn't have non-member functions in a library that conforms to the CLS. It's like an extra set of restrictions in addition to the basic restrictions of the CLI (common language interface).

It is possible that a future version of C# will add the ability to write a using directive that allows the static members of a class to be accessed without the class name qualification:

using System.Linq.Enumerable; // Enumerable is a static class

...

IEnumerable<int> range = Range(1, 10); // finds Enumerable.Range

Then there will be no need to change the CLS and existing libraries.

These blog posts demonstrate a library for functional programming in C#, and they use a class name that is just one letter long, to try and cut down the noise caused by the requirement to qualify static method calls. Examples like that would be made a little nicer if using directives could target classes.

Share:
25,124
Navaneeth K N
Author by

Navaneeth K N

Nothing serious about me.

Updated on July 05, 2022

Comments

  • Navaneeth K N
    Navaneeth K N almost 2 years

    C# will not allow to write non-member functions and every method should be part of a class. I was thinking this as a restriction in all CLI languages. But I was wrong and I found that C++/CLI supports non-member functions. When it is compiled, compiler will make the method as member of some unnamed class.

    Here is what C++/CLI standard says,

    [Note: Non-member functions are treated by the CLI as members of some unnamed class; however, in C++/CLI source code, such functions cannot be qualified explicitly with that class name. end note]

    The encoding of non-member functions in metadata is unspecified. [Note: This does not cause interop problems because such functions cannot have public visibility. end note]

    So my question is why don't C# implement something like this? Or do you think there should not be non-member functions and every method should belong to some class?

    My opinion is to have non-member function support and it helps to avoid polluting class's interface.

    Any thoughts..?

  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    In a given context, it would often be nice to enable some unqualified functions. It's a tiny step closer to smooth embedded DSLs. Here's a great example of a library where the author uses a single-letter class name to cut out as much noise as possible. blogs.msdn.com/lucabol/archive/2008/04/08/…
  • josesuero
    josesuero almost 15 years
    it's pretty commonly accepted in C++ that when possible, non-member functions should be preferred. The logic is simple. The fewer methods have access to a class' privates, the better. The better encapsulated it is, and the easier it is to maintain. And of course, it allows a lot more code reuse across classes. (The standard library std::find, for example, is one single implementation that is reused for any iterator type. In C#, every container class have to define their own find function. Which is most OOP? Which offers the most code reusability? ;)
  • josesuero
    josesuero almost 15 years
    To most Java/C# programmers, this is a bit of a source of culture shock, but the logic behind it is pretty straightforward. See ddj.com/cpp/184401197 for example. However, I think you answer the question very well. C# doesn't allow it because to non-C++ programmers, it looks strange and scary and non-OOP. ;) It goes against a lot of what "conventional" OOP languages teach.
  • josesuero
    josesuero almost 15 years
    By the way, I think anonymous functions are pretty much the same. Conceptually, they are functions that aren't tied to any single class. They behave as non-member functions. But the CLR requires them to be implemented as members of an anonymous class. Extension methods are another concession to the fact that sometimes, we'd really like to be able to extend a class without actually adding members to it. In C++, you'd use non-members for the same reason.
  • Jon Skeet
    Jon Skeet almost 15 years
    @jalf: The argument of "the fewer methods have access to a class's privates, the better" doesn't work for me - because it just suggests you put the member in a different class, e.g. a static one.
  • Jon Skeet
    Jon Skeet almost 15 years
    Also, anonymous functions are very definitely tied to the class in which they're created - they have access to private variables within that class, which can very often be useful. Out of interest, are you arguing in favour of completely global variables which don't belong in any class too? If not, why not - what's the difference?
  • Jon Skeet
    Jon Skeet almost 15 years
    In terms of extension methods, I'd say that they certainly support the argument that there are ways of building on a class without deriving from it. However, that doesn't mean that such methods shouldn't be grouped together - and a class is a very convenient grouping construct, IMO. Better that than being at the namespace level. (One of my issues with extension methods is the way they're discovered - I wish there was something like "using static System.Linq.Enumerable;" to identify exactly where to get extension methods from.)
  • Jon Skeet
    Jon Skeet almost 15 years
    Class only infers object if it's an instance method. I don't see anything absurd about the concept of a class containing only static methods - it's a sufficiently useful pattern that it got proper syntax support in C# 2 :) Put it this way - I'd rather have classes "IOUtil", "StringUtil" etc than have all utility methods just at the namespace level.
  • Nemanja Trifunovic
    Nemanja Trifunovic almost 15 years
    It is absurd. Classes are supposed to be patterns for creating objects, not containers for methods.
  • Navaneeth K N
    Navaneeth K N almost 15 years
    Yeah. All my new projects are in C# and I really miss free function feature :(
  • Dmitry Tashkinov
    Dmitry Tashkinov almost 15 years
    I don't think putting static method into a class or into a namespace is a big deal either. But think about the very word "class". Class of what? I think the ansfer is of objects, not of something you can use in your program ;) .
  • josesuero
    josesuero almost 15 years
    @Jon: But why should I put it in a static class? What benefit does that give me over placing it outside all classes? It doesn't conceptually belong to that other static class. Anonymous classes are not members of the class in which they're created, however. They are implemented as a lot of trickery and the creation of a new anonymous class. As for global variables outside a class, no. A global variable can't meaningfully be considered part of a class's interface, the way a free function can. Why do you consider a static class a better grouping construct than a namespace though?
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    It's certainly a bit strange. Logically there is no difference between a static class and a namespace containing (hypothetical) non-member functions. It makes no more sense to insist that all utility methods should be contained in a static class than it would to insist that all small utility classes should be contained in a static class
  • josesuero
    josesuero almost 15 years
    Extension methods help quite a bit, but I agree, proper free functions would be a great addition
  • Nemanja Trifunovic
    Nemanja Trifunovic almost 15 years
    Forget C++. How about F# or VB.NET? They do support free functions just fine.
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    "Why do you consider a static class a better grouping construct than a namespace though?" Seconded! :) If non-member functions were allowed (and all else equal), a namespace would be better than a static class because it can be targeted by a using. Or equivalently we can ask: why shouldn't a 'using' directive be able to target a static class, allowing us to call its methods without qualification?
  • Navaneeth K N
    Navaneeth K N almost 15 years
    Great! Thanks for the explanation jalf
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    The major advantage of extension methods is that they integrate nicely with auto-completion or "intellisense" in a code editor. But your first sentence says it all! Java appeared to be the language of the future in 1999, so the CLS was tailor made to ensure compatibility with Java.
  • Jon Skeet
    Jon Skeet almost 15 years
    I prefer a static class to a namespace because it's a smaller unit - usually static classes work around a single type (e.g. Enumerable working with IEnumerable, Queryable working with IQueryable). I find that a better unit than just "there's a bunch of stuff in this namespace". I do agree that it would be nice to have the equivalent of Java's static import - because that's explicit (once). It means you can either use the explicit form everywhere, making the source of the method clear where that's beneficial or you can use the static import.
  • Jon Skeet
    Jon Skeet almost 15 years
    (Continued) Why remove that flexibility by having them as just methods in the namespace? If the post had been arguing for more control over the import process, I'd have certainly been for it. @jalf: "Anonymous classes are not members of the class in which they're created, however." Indeed - because there would be no benefit there. This is very different from anonymous functions. Anonymous types wouldn't benefit from increased access to members of the class using them - anonymous functions do.
  • Jon Skeet
    Jon Skeet almost 15 years
    Lambda functions are defined as either members of the declaring type, or of nested classes (for captured variables). Otherwise they wouldn't have access to private variables. (Expression trees cause headaches for the accessibility model...)
  • josesuero
    josesuero almost 15 years
    Implementation detail. :) The concept of a lambda expression is based on a closure, not on class membership. It has access to all variables visible at the site where it's declared, because that's how a closure works. That doesn't (conceptually) make it a "member" of anything. That's just how .NET chose to implement it.
  • Jon Skeet
    Jon Skeet almost 15 years
    A namespace contains top-level classes. That certainly feels like a bigger type of unit than a class, to me.
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    One difference is that a static class is closed (it has a single definition in one assembly) whereas a namespace can be added to by several assemblies. If you try that with static classes, you get an error about multiple definitions, instead of their members being "merged". Even partial classes aren't nearly so flexible.
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    If for some daft reason you had to type MONKEY in front of every identifier in C#, we could defend this by saying "Is it really such a big deal having to type MONKEY in front of every identifier? Come on, don't make such a fuss about a little bit of typing!" But that wouldn't stop it from being a strange and unnecessary imposition. It's the same with requiring all references to static functions to be qualified by a class name. No need for it, waste of everyone's time.
  • Jon Skeet
    Jon Skeet almost 15 years
    @Earwicker: Absolutely. I'm not sure whether you're suggesting that's a good thing or not :) Of course, with extension methods you can have multiple types "extending" a single type. If we had more control via using directives (e.g. extension methods by class, and Java-like "import static" abilities) would you still want namespace-level methods?
  • Jason Baker
    Jason Baker almost 15 years
    @Nemanja - They're still very different languages with different grammars. Look, I agree that global functions would be helpful. But I personally would rather have dynamic typing, co/contravariance, and optional and named parameters before I get free functions.
  • Jason Baker
    Jason Baker almost 15 years
    You can still use static classes to achieve the same effect.
  • Nemanja Trifunovic
    Nemanja Trifunovic almost 15 years
    "Static classes" serve no real purpose. They are just like namespaces (except they are harder to type) - why not use real namespaces instead?
  • Nemanja Trifunovic
    Nemanja Trifunovic almost 15 years
    Again, what is the purpose of classes? They are templates for objects. Classes that cannot be used to create objects are not serving their purpose. Namespaces or modules are far better mechanisms for grouping related functions.
  • Eric Lippert
    Eric Lippert almost 15 years
    "C# doesn't allow it because Java didn't allow it." -- I would be fascinated to hear how you came up with this particular conclusion. Were you in the design meeting that day? Have you read the design team's notes? Did one of the designers tell you that?
  • Jon Skeet
    Jon Skeet almost 15 years
    @Nemanja: I don't think of classes as only templates for objects. I think of them as containers for members including methods... whereas I think of namespaces as containers for types.
  • Eric Lippert
    Eric Lippert almost 15 years
    We added extension methods because they are necessary to make query comprehensions work as a syntactic, rather than semantic transformation.
  • MSalters
    MSalters almost 15 years
    @Eric: Microsoft at the end of the previous century was very much in copy mode, at least publicly. With stuff like J# and the whole Sun/Microsoft row, it's impossible to deny that Java influenced C# and CLI. It doesn't follow automatically that this applies to this particular (mis)feature. But it's quite remarkable that such a common language feature is missing from the Common Language Infrastructure.
  • Nemanja Trifunovic
    Nemanja Trifunovic almost 15 years
    @Jon. Traditionally, modules are containers of "members" - classes were introduced with the purpose of creating objects.
  • Eric Lippert
    Eric Lippert almost 15 years
    Of course Java was an influence on C#. As was C, C++, JScript, Visual Basic, Pascal, and a great many other languages. But C# is not "Java with the stupid parts taken out", as many people seem to think.
  • Jon Skeet
    Jon Skeet almost 15 years
    @Nemanja: That may be the case in C++ and other environments - but what would be the tangible benefits in .NET, which uses slightly different terminology?
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    @Jon - with Java-like "import static" I'd be good to go, and I'd assume from the perspective of evolving the CLR/CLS/C# combination in a backward compatible way, it's probably the only realistic option.
  • Beska
    Beska almost 15 years
    Good point, but it should be (and is) a comment, rather than an answer.
  • Eric Lippert
    Eric Lippert almost 15 years
    And in fact you will get all of those things before you get "free" methods. :-)
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    @Jason - I shouldn't be too concerned that the outcome of this discussion will impact on the feature set of C# 4.0!
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    @Beska, given that it is clearly an answer to the original question (and the only answer here with any claim to provenance!) how do you figure that?
  • Eric Lippert
    Eric Lippert almost 15 years
    Absolutely. C# and Java share a large number of their confusing or error-prone idioms. We have tried to learn from the shortcomings of the Java design; there are a great many places where the C# compiler produces warnings or errors for idioms where the equivalent Java code is legal but misleading. But we by no means got anywhere close to all of them.
  • Beska
    Beska almost 15 years
    Ah...missed the actual link to the answer at the bottom...distracted by the bold up above. I stand by my statement that an answer that is an lengthy outraged growl (whether or not justified) followed by a mere link to the real answer, isn't really ideal. I'm not clear on why you got rid of your original answer text, where you actually addressed the question. shrug. No offense intended.
  • Beska
    Beska almost 15 years
    (Why did the original answer text get deleted...where you were actually addressing the question directly?)
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    A big irony here is that if you look at the Java community's typical wish list for features in Java 7, a great deal of them are things already in C#, and experience from C# is frequently cited as justification for adding those features to Java. Java would certainly benefit from absorbing more ideas from C#. Unfortunately somethings were made slightly worse by the journey, e.g. compare two boxed integers for referential equality, and if they are <= 255 they will be equal (i.e. the sane object). If > 255, they won't be equal. And the language spec even allows the implementation to change this!
  • MbaiMburu
    MbaiMburu almost 15 years
    @Beska There are hundreds of answers on SO that are simply links. Usually because 99% of us don't know, but we know we've read someone who does know. Eric Lippert is simply refuting the other posters, and then posting a link to a blogger he respects.
  • Eric Lippert
    Eric Lippert almost 15 years
    I am not merely posting "a link to a blogger I respect", I am posting a link to my own blog.
  • configurator
    configurator almost 15 years
    @Eric: I seriously hope this is one of the bloggers you respect, being that it is yourself.
  • Daniel Earwicker
    Daniel Earwicker almost 15 years
    Maybe he's trying to earn his own respect. Perhaps by submitting to a series of painful ordeals. Such as visiting SO! :)
  • Axarydax
    Axarydax over 14 years
    @Eric and will we also get to type MONKEY in front of every identifier too? :-)
  • d..
    d.. about 14 years
    "What's the benefit of not putting each method in a named class?" Jesus, and to think that I was planning on buying your book...
  • Jon Skeet
    Jon Skeet about 14 years
    @d: Your comment suggests that you think there's an obvious benefit to non-member methods. Could you elaborate as to what that benefit is, and how it fits in with C# in general? I'm not claiming that other languages with different aims may not find non-member functions useful, but I don't think they really fit in with C# in its current form.
  • d..
    d.. about 14 years
    (1) - My apologies; I don't think that came across as intended (I've learnt a lot from you and I still plan to by your new book!). That said, time to elaborate: how many C# projects have we seen not featuring a "Tools"/"Utils"/"HelperClass" class? Not many. IMHO, this alone defeats the actual concept or idea of "class" itself: there has to be a common denominator (e.g. methods working on the same stuff), a pattern, a shared space, an idea that we humans can understand, relate to and that we represent by means of a class in computer programs.
  • d..
    d.. about 14 years
    (2) - So, for example, if I had to write a program that deals with animals and cars (as we see in the road); I'd probably have two classes: "Animal" and "Car". Now, where do I put that additional method that I need to check the current date and move it backwards by one month? Well, in "Utils". But then, what concept, what common denominator, what idea - in the Platonic sense of the word - does the class "Utils" represent? None. Where do the inevitable misfits in every application go? IMHO, having to put everything in a class is simply OOP approach taken to the extreme.
  • d..
    d.. about 14 years
    (3) - Unless, of course, someone gives me a good answer as to why everything should go in a class. Was this the case before, in other languages? So, if it wasn't the case, why go for the approach? What exactly is the benefit? Remark: I'm aware that all this is mostly philosophical, totally subjective and that many others may disagree.
  • d..
    d.. about 14 years
    (4) - Finally: when a language implements a new feature, I don't think it's up to the other languages to explain what the benefit is of not having that feature; I think it's more about that language explaining the benefits of the said feature. Personally, I don't see any advantages in having to put everything in a class. But, again, this is all opinion...
  • configurator
    configurator over 13 years
    @Eric: I happen to know for a fact that you like it when we speculate about your mental state and present it as facts.
  • configurator
    configurator over 13 years
    @Daniel: That's not because of a C# feature that transferred; that's because of a feature that didn't: Sane == comparisons.
  • configurator
    configurator over 13 years
    @Eric: Since I worked on C# before I had any real experience with Java, I tend not to think of C# as "Java with the stupid parts taken out". Rather, Java is "Like C# but bloody stupid and never works right".
  • configurator
    configurator over 13 years
    And if anyone plans to counter my claim that Java is bloody stupid, I will refer you to generics. That's enough to win quite a lot of arguments.
  • josesuero
    josesuero over 13 years
    @Eric: no, I wasn't in that meeting. :) But given that C# drew a lot of inspiration from Java (as you have stated), and that C++ does allow non-member functions, and has some very good reasons for doing so (beyond just "we need to be compatible with C"), I can't really think of any reasons other than variations on the theme of "hey, it worked in Java, let's stick with that", I find it to be the most likely explanation. Whatever the reasoning behind this decision, would you have even considered it if Java hadn't done it first?
  • Mark K Cowan
    Mark K Cowan about 9 years
    @DanielEarwicker: Reminds me of the Windows media APIs
  • Daniel Earwicker
    Daniel Earwicker about 9 years
    Fast forward 6 MONKEY.years: C#6 dashes to the MONKEY.rescue!
  • Everyone
    Everyone about 7 years
    Idk what @EricLippert reputation was back then but damn right now Beska's comments do seem really ... not in place.
  • Pac0
    Pac0 over 6 years
    Was about to flag this as low-quality due to being link-only answer ;) . I just edited and copied some relevant part, feel free to choose better ones. But remember : links die (even, and maybe especially msdn one's )
  • code_dredd
    code_dredd about 6 years
    So, for someone who's looking to use analogous functionality, is using static NameSpace.ClassName; to then be able to call Function(arg1, arg2, ...) an good alternative or is that someone we should generally avoid (i.e not a "best/recommended practice")? Perhaps there's another "better" option to achieve the goal?
  • ZEE
    ZEE over 3 years
    error CS0138: A 'using namespace' directive can only be applied to namespaces;
  • Dylan Nicholson
    Dylan Nicholson over 3 years
    I didn't say anything about "using namespace" directives.
  • stackoverblown
    stackoverblown almost 3 years
    Is this not a funny comment? Historically there were only free functions. Class methods came much much later! So to say modern languages support free functions as if free functions are a modern invention ??