Function overloading

Last updated

In some programming languages, function overloading or method overloading is the ability to create multiple functions of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context.

Contents

For example, doTask() and doTask(object o) are overloaded functions. To call the latter, an object must be passed as a parameter, whereas the former does not require a parameter, and is called with an empty parameter field. A common error would be to assign a default value to the object in the second function, which would result in an ambiguous call error, as the compiler wouldn't know which of the two methods to use.

Another example is a Print(object o) function that executes different actions based on whether it's printing text or photos. The two different functions may be overloaded as Print(text_object T); Print(image_object P). If we write the overloaded print functions for all objects our program will "print", we never have to worry about the type of the object, and the correct function call again, the call is always: Print(something).

Languages supporting overloading

Languages which support function overloading include, but are not necessarily limited to, the following:

Rules in function overloading

Function overloading is usually associated with statically-typed programming languages that enforce type checking in function calls. Overloaded function is really just a set of different functions that happen to have the same name. For any particular call, the compiler determines which overloaded function to use, and resolves this at compile time. This is true for programming languages such as Java. [10]

Sometime overloading wrongly taken as a classification of static polymorphism in which a function call is resolved using some "best match" algorithm, where the particular function to call is resolved by finding the best match of the formal parameter types with the actual parameter types or/and number of parameters. The mistake comed from confusion in each form of static polymorphism as following:

Function overloading differs from forms of polymorphism where the choice is made at runtime, e.g. through virtual functions, instead of statically.

Example: Function overloading in C++

#include<iostream>intVolume(ints){// Volume of a cube.returns*s*s;}doubleVolume(doubler,inth){// Volume of a cylinder.return3.1415926*r*r*static_cast<double>(h);}longVolume(longl,intb,inth){// Volume of a cuboid.returnl*b*h;}intmain(){std::cout<<Volume(10);std::cout<<Volume(2.5,8);std::cout<<Volume(100l,75,15);}

In the above example, the volume of each component is calculated using one of the three functions named "volume", with selection based on the differing number and type of actual parameters.

Constructor overloading

Constructors, used to create instances of an object, may also be overloaded in some object-oriented programming languages. Because in many languages the constructor's name is predetermined by the name of the class, it would seem that there can be only one constructor. Whenever multiple constructors are needed, they are to be implemented as overloaded functions. In C++, default constructors take no parameters, instantiating the object members with their appropriate default values, "which is normally zero for numeral fields and empty string for string fields". [11] For example, a default constructor for a restaurant bill object written in C++ might set the tip to 15%:

Bill():tip(0.15),// percentagetotal(0.0){}

The drawback to this is that it takes two steps to change the value of the created Bill object. The following shows creation and changing the values within the main program:

Billcafe;cafe.tip=0.10;cafe.total=4.00;

By overloading the constructor, one could pass the tip and total as parameters at creation. This shows the overloaded constructor with two parameters. This overloaded constructor is placed in the class as well as the original constructor we used before. Which one gets used depends on the number of parameters provided when the new Bill object is created (none, or two):

Bill(doubletip,doubletotal):tip(tip),total(total){}

Now a function that creates a new Bill object could pass two values into the constructor and set the data members in one step. The following shows creation and setting the values:

Billcafe(0.10,4.00);

This can be useful in increasing program efficiency and reducing code length.

Another reason for constructor overloading can be to enforce mandatory data members. In this case the default constructor is declared private or protected (or preferably deleted since C++11) to make it inaccessible from outside. For the Bill above total might be the only constructor parameter  since a Bill has no sensible default for total  whereas tip defaults to 0.15.

Complications

Two issues interact with and complicate function overloading: Name masking (due to scope) and implicit type conversion.

If a function is declared in one scope, and then another function with the same name is declared in an inner scope, there are two natural possible overloading behaviors: the inner declaration masks the outer declaration (regardless of signature), or both the inner declaration and the outer declaration are both included in the overload, with the inner declaration masking the outer declaration only if the signature matches. The first is taken in C++: "in C++, there is no overloading across scopes." [12] As a result, to obtain an overload set with functions declared in different scopes, one needs to explicitly import the functions from the outer scope into the inner scope, with the using keyword.

Implicit type conversion complicates function overloading because if the types of parameters do not exactly match the signature of one of the overloaded functions, but can match after type conversion, resolution depends on which type conversion is chosen.

These can combine in confusing ways: An inexact match declared in an inner scope can mask an exact match declared in an outer scope, for instance. [12]

For example, to have a derived class with an overloaded function taking a double or an int, using the function taking an int from the base class, in C++, one would write:

classB{public:voidF(inti);};classD:publicB{public:usingB::F;voidF(doubled);};

Failing to include the using results in an int parameter passed to F in the derived class being converted to a double and matching the function in the derived class, rather than in the base class; Including using results in an overload in the derived class and thus matching the function in the base class.

Caveats

If a method is designed with an excessive number of overloads, it may be difficult for developers to discern which overload is being called simply by reading the code. This is particularly true if some of the overloaded parameters are of types that are inherited types of other possible parameters (for example "object"). An IDE can perform the overload resolution and display (or navigate to) the correct overload.

Type-based overloading can also hamper code maintenance, where code updates can accidentally change which method overload is chosen by the compiler. [13]

See also

Citations

  1. "Clojure - Learn Clojure - Functions". clojure.org. Retrieved 2023-06-13.
  2. "Kotlin language specification". kotlinlang.org.
  3. Bloch 2018, p. 238-244, §Chapter 8 Item 52: Eliminate unchecked warnings.
  4. "37.6. Function Overloading". PostgreSQL Documentation. 2021-08-12. Retrieved 2021-08-29.
  5. "Database PL/SQL User's Guide and Reference". docs.oracle.com. Retrieved 2021-08-29.
  6. "Nim Manual". nim-lang.org.
  7. "Crystal Docs". crystal-lang.org.
  8. "Embarcadero Delphi". embarcadero.com.
  9. Watt, David A.; Findlay, William (1 May 2004). Programming Language Design Concepts. John Wiley & Sons, Inc. pp. 204–207. ISBN   978-0-470-85320-7.
  10. Bloch 2018, p. 238-244, §Chapter 8 Item 52: Use overloading judiciously.
  11. Chan, Jamie (2017). Learn C# in One Day and Learn It Well (Revised ed.). p. 82. ISBN   978-1518800276.
  12. 1 2 Stroustrup, Bjarne. "Why doesn't overloading work for derived classes?".
  13. Bracha, Gilad (3 September 2009). "Systemic Overload". Room 101.

Related Research Articles

In computer programming, the scope of a name binding is the part of a program where the name binding is valid; that is, where the name can be used to refer to the entity. In other parts of the program, the name may refer to a different entity, or to nothing at all. Scope helps prevent name collisions by allowing the same name to refer to different objects – as long as the names have separate scopes. The scope of a name binding is also known as the visibility of an entity, particularly in older or more technical literature—this is in relation to the referenced entity, not the referencing name.

<span class="mw-page-title-main">C++</span> General-purpose programming language

C++ is a high-level, general-purpose programming language created by Danish computer scientist Bjarne Stroustrup. First released in 1985 as an extension of the C programming language, it has since expanded significantly over time; as of 1997, C++ has object-oriented, generic, and functional features, in addition to facilities for low-level memory manipulation for systems like microcomputers or to make operating systems like Linux or Windows. It is usually implemented as a compiled language, and many vendors provide C++ compilers, including the Free Software Foundation, LLVM, Microsoft, Intel, Embarcadero, Oracle, and IBM.

Generic programming is a style of computer programming in which algorithms are written in terms of data types to-be-specified-later that are then instantiated when needed for specific types provided as parameters. This approach, pioneered by the ML programming language in 1973, permits writing common functions or types that differ only in the set of types on which they operate when used, thus reducing duplicate code.

A method in object-oriented programming (OOP) is a procedure associated with an object, and generally also a message. An object consists of state data and behavior; these compose an interface, which specifies how the object may be used. A method is a behavior of an object parametrized by a user.

In computer science, a type signature or type annotation defines the inputs and outputs of a function, subroutine or method. A type signature includes the number, types, and order of the function's arguments. One important use of a type signature is for function overload resolution, where one particular definition of a function to be called is selected among many overloaded forms.

In computer programming, a parameter or a formal argument is a special kind of variable used in a subroutine to refer to one of the pieces of data provided as input to the subroutine. These pieces of data are the values of the arguments with which the subroutine is going to be called/invoked. An ordered list of parameters is usually included in the definition of a subroutine, so that, each time the subroutine is called, its arguments for that call are evaluated, and the resulting values can be assigned to the corresponding parameters.

In computer programming, a default argument is an argument to a function that a programmer is not required to specify. In most programming languages, functions may take one or more arguments. Usually, each argument must be specified in full. Later languages allow the programmer to specify default arguments that always have a value, even if one is not specified when calling the function.

In object-oriented programming such as is often used in C++ and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method that is dispatched dynamically. Virtual functions are an important part of (runtime) polymorphism in object-oriented programming (OOP). They allow for the execution of target functions that were not precisely identified at compile time.

This article compares two programming languages: C# with Java. While the focus of this article is mainly the languages and their features, such a comparison will necessarily also consider some features of platforms and libraries. For a more detailed comparison of the platforms, see Comparison of the Java and .NET platforms.

In compiler construction, name mangling is a technique used to solve various problems caused by the need to resolve unique names for programming entities in many modern programming languages.

In class-based, object-oriented programming, a constructor is a special type of function called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

In some programming languages, const is a type qualifier that indicates that the data is read-only. While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in that it is part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking. In other languages, the data is not in a single memory location, but copied at compile time for each use. Languages which use it include C, C++, D, JavaScript, Julia, and Rust.

In computer science, a type class is a type system construct that supports ad hoc polymorphism. This is achieved by adding constraints to type variables in parametrically polymorphic types. Such a constraint typically involves a type class T and a type variable a, and means that a can only be instantiated to a type whose members support the overloaded operations associated with T.


A class in C++ is a user-defined type or data structure declared with any of the keywords class, struct or union that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class declared with the keyword class is private. The private members are not accessible outside the class; they can be accessed only through member functions of the class. The public members form an interface to the class and are accessible outside the class.

The curiously recurring template pattern (CRTP) is an idiom, originally in C++, in which a class X derives from a class template instantiation using X itself as a template argument. More generally it is known as F-bound polymorphism, and it is a form of F-bounded quantification.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

This comparison of programming languages compares how object-oriented programming languages such as C++, Java, Smalltalk, Object Pascal, Perl, Python, and others manipulate data structures.

In programming languages, name resolution is the resolution of the tokens within program expressions to the intended program components.

References