I'm developing a statically- and strongly-typed, compiled language, and I'm revisiting the idea of whether to include function overloading as a language feature. I realized that I'm a little bit biased, coming mainly from a C[++|#] background.

What are the most convincing arguments for and against including function overloading in a language?

EDIT: Is there nobody who has an opposing opinion?

Bertrand Meyer (creator of Eiffel back in 1985/1986) calls method overloading this: (source)

a vanity mechanism that brings nothing to the semantic power of an O-O language, but hampers readability and complicates everyone's task

Now those are some sweeping generalizations, but he's a smart guy, so I think it's safe to say he could back them up if he needed to. In fact, he almost had Brad Abrams (one of the CLSv1 developers) convinced that .NET shouldn't support method overloading. (source) That's some powerful stuff. Can anyone shed some light on his thoughts, and whether his viewpoint is still justified 25 years later?

  • This question is closed, but I have an opinion. You shouldn't. Here, function overloading is defined as giving more that one signature to a function, so Haskell's operator + typeclass doesn't count because (+) has only one type: Num a => a -> a -> a, while C#'s + has multiple signatures. Function overloading breaks an important property of type system: every expression has one most general type. Working with C#, I'm frustated that I cannot have a generalized function over summable types, precisely because (a, b) => a+ b does not have type assignment that accepts every usage of the type.
    – Xwtek
    Dec 2, 2021 at 9:40
  • Well, other than Func<dynamic, dynamic, dynamic>, but then you give up type safety. Losing this property also makes type inference impossible, making auto the next best thing that can be done.
    – Xwtek
    Dec 2, 2021 at 9:47

10 Answers 10


Function overloading is absolutely critical for C++-style template code. If I have to use different function names for different types, I can't write generic code. That would eliminate a large and heavily used part of the C++ library, and much of C++'s functionality.

It's usually present in member function names. A.foo() can call an entirely different function from B.foo(), but both functions are named foo. It's present in operators, as + does different things when applied to integers and floating-point numbers, and it's often used as a string concatenation operator. It seems odd not to allow it in regular functions as well.

It enables the use of Common Lisp-style "multimethods", in which the exact function called depends on two data types. If you haven't programmed in the Common Lisp Object System, try it before you call this useless. It's vital for C++ streams.

I/O without function overloading (or variadic functions, which are worse) would require a number of different functions, either to print values of different types or to convert values of different types to a common type (like String).

Without function overloading, if I change the type of some variable or value I need to change every function that uses it. It makes it much harder to refactor code.

It makes it easier to use APIs when the user doesn't have to remember which type naming convention is in use, and the user can just remember standard function names.

Without operator overloading, we'd have to label each function with the types it uses, if that base operation can be used on more than one type. This is essentially Hungarian notation, the bad way of doing it.

Overall, it makes a language far more usable.

  • 1
    +1, all very good points. And trust me, I don't think multimethods are useless... I curse the very keyboard I type on every time I'm forced to use the visitor pattern. Sep 29, 2010 at 17:11
  • 1
    Is't this guy describing function overriding and not overloading ?
    – dragosb
    Sep 20, 2017 at 12:18

I recommend at least being aware of type classes in Haskell. Type classes were created to be a disciplined approach to operator overloading, but have found other uses, and to an extent, made Haskell what it is.

For instance, here's an example of ad-hoc overloading (not quite valid Haskell):

(==) :: Int -> Int -> Bool
x == y = ...
x /= y = not (x == y)

(==) :: Char -> Char -> Bool
x == y = ...
x /= y = not (x == y)

And here's the same example of overloading with type classes:

class Eq a where
    (==) :: a -> a -> Bool
    (/=) :: a -> a -> Bool

    x /= y  =  not (x == y)

instance Eq Int where
    x == y  = ...

instance Eq Char where
    x == y  = ...

A downside of this is that you have to come up with funky names for all your typeclasses (like in Haskell, you have the rather abstract Monad, Functor, Applicative as well as the simpler and more recognizable Eq, Num, and Ord).

An upside is that, once you're familiar with a typeclass, you know how to use any type in that class. Plus, it's easy to guard functions from types that don't implement the needed classes, as in:

group :: (Eq a) => [a] -> [[a]]
group = groupBy (==)

Edit: In Haskell, if you wanted an == operator that accepts two different types, you could use a multi-parameter type class:

class Eq a b where
    (==) :: a -> b -> Bool
    (/=) :: a -> b -> Bool

    x /= y  =  not (x == y)

instance Eq Int Int where
    x == y  = ...

instance Eq Char Char where
    x == y  = ...

instance Eq Int Float where
    x == y  = ...

Of course, this is probably a bad idea, since it explicitly lets you compare apples and oranges. However, you might want to consider this for +, since adding a Word8 to an Int really is a sensible thing to do in some contexts.

  • +1, I've been trying to grasp this concept ever since I first read it, and this helps. Does this paradigm make it impossible to define, for example, (==) :: Int -> Float -> Bool anywhere? (regardless of whether it's a good idea, of course) Sep 29, 2010 at 17:17
  • If you allow multi-parameter type classes (which Haskell supports as an extension), you can. I updated the answer with an example.
    – Joey Adams
    Sep 29, 2010 at 17:44
  • Hmm, interesting. So basically, class Eq a ... translated into pseudo-C-family would be interface Eq<A> {bool operator==(A x, A y);}, and instead of using templated code to compare arbitrary objects, you use this 'interface'. Is that right? Sep 30, 2010 at 19:41
  • Right. You might also want to take a quick look at interfaces in Go. Namely, you don't have to declare a type as implementing an interface, you just have to implement all the methods for that interface.
    – Joey Adams
    Oct 2, 2010 at 2:07
  • 1
    @Notetoself-thinkofaname: Regarding additional operators - yes and no. It allows for == to be in a different name-space but doesn't allow to override it. Please note that there is a single namespace (Prelude) included by default but you can prevent loading it by using extensions or by importing it explicitly (import Prelude () will import nothing from Prelude and import qualified Prelude as P will not insert symbols into current namespace). Jan 18, 2013 at 18:48

Allow function overloading, you can't do the following with optional parameters (or if you can, not nicely).

trivial example assumes no base.ToString() method

string ToString(int i) {}
string ToString(double d) {}
string ToString(DateTime d) {}
  • For a strongly typed language, yes. For a weakly typed language, no. You can do the above with only one function in a weakly typed language.
    – spex
    Dec 10, 2018 at 20:30

Use-case against implementing function overloading: 25 like-named methods that kind of do the same things but with completely different sets of arguments in a wide variety of patterns.

Use-case against not implementing function overloading: 5 similarly-named methods with very similar sets of types in the exact same pattern.

At the end of the day, I'm not looking forward to reading the docs for an API produced in either case.

But in one case it's about what users might do. In the other case it's what users must do because of a language restriction. IMO, it's better to at least allow for the possibility of program authors being smart enough to overload sensibly without creating ambiguity. When you slap their hands and take the option away you're basically guaranteeing ambiguity is going to happen. I'm more about trusting the user to do the right thing than assume they'll always do the wrong thing. In my experience, protectionism tends to lead to even worse behavior on the part of a language's community.


I've always preferred default parameters over function overloading. Overloaded functions generally just call a "default" version with default parameters. Why write

int indexOf(char ch)
  return self.indexOf(ch, 0);

int indexOf(char ch, int fromIndex)
  // Do whatever

When I could do:

int indexOf(char ch, int fromIndex=0)
  // Do whatever

That said, I realize sometimes overloaded functions do different things, rather than just calling another variant with default parameters...but in such a case, it's not a bad idea (in fact, it's probably a good idea) to just give it a different name.

(Also, Python-style keyword arguments work really nicely with default parameters.)

  • Okay, let's try that again, and I'll try to make sense this time... What about Array Slice(int start, int length) {...} overloaded with Array Slice(int start) {return this.Slice(start, this.Count - start);}? That can't be coded using default parameters. Do you think they should be given different names? If so, how would you name them? Oct 22, 2010 at 23:00
  • That doesn't address all uses of overloading. Nov 26, 2010 at 21:22
  • @MetalMikester: What uses do you feel I missed?
    – mipadi
    Nov 29, 2010 at 15:57
  • @mipadi It misses things like indexOf(char ch) + indexOf(Date dt) on a list. I like default values too but they're not interchangeable with static typing.
    – Mark
    Apr 16, 2017 at 18:14

You just described Java. Or C#.

Why are you reinventing the wheel?

Make sure that the return type is part of the method signature and Overload to your hearts content, it really cleans up the code when you don't have to say.

function getThisFirstWay(int type)
{ ... }
function getThisSecondWay(int type, double limit)
{ ... }
function getThisThirdWay(int type, String match)
{ ... }
  • 7
    There's a reason why the return type isn't part of the method signature--or at least not a part that can be used for overload resolution--in any language I'm aware of. When you call a function as a procedure, without assigning the result to a variable or property, how is the compiler supposed to figure out which version to invoke if all the other arguments are identical? Sep 29, 2010 at 16:09
  • @Mason: You could heuristically detect the expected return type based on what is expected to be returned, however I don't expect that to be done.
    – Josh K
    Sep 29, 2010 at 16:43
  • 1
    Umm... how does your heuristic know what is expected to be returned when you're not expecting any return value? Sep 29, 2010 at 17:07
  • 1
    The type-expectation heuristic actually is in place... you can do things like EnumX.Flag1 | Flag2 | Flag3. I won't be implementing this, though. If I did and the return type wasn't used, I'd look for a return type of void. Sep 29, 2010 at 17:15
  • 1
    @Mason: That's a good question, but in that case I would look for a void function (as mentioned). Also in theory you could choose any of them, because they will all perform the same function, simply return data in a different format.
    – Josh K
    Sep 29, 2010 at 17:39

Grrr .. not enough privilege to comment yet ..

@Mason Wheeler: Be aware then of Ada, which does overload on return type. Also my language Felix does it too in some contexts, specifically, when a function returns another function and there is a call like:

f a b  // application is left assoc: (f a) b

the type of b can be used for overload resolution. Also C++ overloads on return type in some circumstances:

int (*f)(int) = g; // choses g based on type, not just signature

In fact there are algorithms for overloading on return type, using type inference. It's actually not that hard to do with a machine, the problem is that humans find it hard. (I think the outline is given in the Dragon Book, the algorithm is called the see-saw algorithm if I remember correctly)


I chose to provide ordinary overloading and multi-type type-classes in my language Felix.

I consider (open) overloading essential, especially in a language which as a lot of numeric types (Felix has all C's numeric types). However unlike C++ which abuses overloading by making templates depend on it, Felix polymorphism is parametric: you need overloading for templates in C++ because templates in C++ are badly designed.

Type classes are provided in Felix as well. For those that know C++ but don't grok Haskell, ignore those who describe it as overloading. It isn't remotely like overloading, rather, it is like template specialisation: you declare a template which you don't implement, then provide implementations for particular cases as you need them. The typing is parametrically polymorphic, the implementation is by ad hoc instantiation but it is not intended to be unconstrained: it has to implement the intended semantics.

In Haskell (and C++) you cannot state the semantics. In C++ the "Concepts" idea is roughly an attempt to approximate the semantics. In Felix, you can approximate the intention with axioms, reductions, lemmas and theorems.

The main, and only advantage of (open) overloading in a well principled language like Felix is that it makes it easier to remember library function names, both for the program writer and for the code reviewer.

The primary disadvantage of overloading is the complex algorithm required to implement it. It also doesn't sit very well with type inference: although the two are not entirely exclusive, the algorithm to do both is complex enough the programmer probably wouldn't be able to predict the results.

In C++ this is also a problem because it has a sloppy matching algorithm and also supports automatic type conversions: in Felix I "fixed" this problem by requiring an exact match and no automatic type conversions.

So you have a choice I think: overloading or type inference. Inference is cute, but it is also very hard to implement in a way that properly diagnoses conflicts. Ocaml, for example, tells you where it detects a conflict, but not where it inferred the expected type from.

Overloading is not much better, even if you have a quality compiler that tries to tell you all the candidates, it can be hard to read if the candidates are polymorphic, and even worse if it's C++ template hackery.

  • Sounds interesting. I'd love to read more, but the link to the docs on the Felix web page is broken. Nov 26, 2010 at 20:36
  • Yes, the whole site is currently under construction (again), sorry.
    – Yttrill
    Dec 4, 2010 at 22:57

Comes down to context, but I think overloading makes a class much more useful when I'm using one written by someone else. You often end up with less redundancy.


If you're looking to have users with familiarity with the C-family languages then yes you should because your users will be expecting it.

Not the answer you're looking for? Browse other questions tagged or ask your own question.