CSC/ECE 517 Fall 2007/wiki2 8 42: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
mNo edit summary
(Added more outside links, replaced the first example with one from a current project, expanded the discussion on multimethods by better identifying the shortcoming of dynamic method invocation.)
Line 3: Line 3:


== Objective ==
== Objective ==
The objective of this document is to briefly review '''overloading''' and '''overriding''' and to compare/contrast the different way overriding is handled in ''multimethod'' programming languages (like CLOS) and ''non-multimethod'' languages (like C#, Java or C++).
The objective of this document is to present the concepts of method '''overloading''' and method '''overriding'''.  In doing so, it will contrast how method overriding is handled in common object-oriented programming languages (such as C#, Java or C++) and in multimethod languages.


== Overloading ==
Method [http://articles.techrepublic.com.com/5100-22-5074021.html overloading] occurs when there are two methods within the scope of a class that have the same name but different parameter list (and therefore different signatures).  The scope of a class is not necessarily limited to the file that defines it, but it will also include methods from each superclass up the inheritance hierarchy.
The principal becomes a little more complicated when one considers the method in which the compiler uses to determine which overloaded method to activate when parameters involve subtypes.  Consider the following partial class definitions taken from a national dental practice management system.  In it there are Tooth objects and PerioTooth objects, which are a subclass of Tooth objects.  There are also Restorations objects and PerioSplint objects, which are children of Restorations.  The syntax is in C#.


== Overloading ==
Method overloading occurs when one or more methods within the scope of a class share the same name but differ in their parameter list.  Parameters are differentiated by their type and not their names; parameter names can be changed at will (but of course should properly relate to the objects they represent).  For example, the following class definition contains an overloaded method:


<pre>
<pre>
public class Pages
public class Tooth
{
&nbsp;&nbsp;&nbsp;&nbsp;public bool AddRestoration(Restoration restoration) { }
}
 
public class PerioTooth : Tooth
{
{
&nbsp;&nbsp;&nbsp;&nbsp;// add an integer to this list of pages
&nbsp;&nbsp;&nbsp;&nbsp;public bool AddRestoration(PerioSplint restoration) { }
&nbsp;&nbsp;&nbsp;&nbsp;public bool AddPage(int page) { }
}
</pre>


&nbsp;&nbsp;&nbsp;&nbsp;// parse the string argument to an int and
&nbsp;&nbsp;&nbsp;&nbsp;//  add it to this list of pages (via overloaded AddPage(int))
&nbsp;&nbsp;&nbsp;&nbsp;public bool AddPage(string page) { }


}
PerioTooth now has two overloaded methods AddRestoration() that add either a normal Restoration (the first definition) or a PerioSplint, which is specific to periodontal work (the second definition).  They are both within the same class scope of PerioTooth.
Consider the following:
 
 
<pre>
Tooth tooth = new Tooth();
PerioTooth perioTooth = new PerioTooth();
Tooth ptTooth = new PerioTooth();
 
tooth.AddRestoration(new Restoration(Restorations.Amalgam, "MO", 32);
perioTooth.AddRestoration(new Restoration(Restorations.Composite, "O", 3);
ptTooth.AddRestoration(new PerioSplint("4-6");
</pre>
</pre>


Notice that there are two methods named AddPage(), but the type of their argument differs; one method accepts an integer and adds it to an accumulator and one method accepts a string, first parsing it to an int and then adding it to an accumulator (via the AddPage(int) method).  Ultimately both methods accomplish the same task -- which is a fundamental design rule when choosing to overload methods.  Methods should never be overloaded unless their functionality closely mirrors that of the method(s) that it overrides.  It is counterintuitive to have one AddPage() method that adds pages to an accumulator and one AddPage() method that determines the temperature in Guatemala!


When the compiler sees calls to AddRestoration(), it first checks the type of the receiver of the call -- which is determined by the object type followed by the variable name when the object is instantiated.  For example, Tooth in "Tooth tooth = new Tooth()" or PerioTooth in "PerioTooth tooth = new PerioTooth()."  From there it begins looking for a signature match by using the types of the arguments.
Method overloading requires caution.  A method should not be overloaded if it and the newly created method do not mirror functionality almost exactly.  It would be counterintuitive to overload one AddRestoration() to add a Restoration object to a tooth and another AddRestoration() to determine the current temperature in Guatemala!


== Overriding ==
== Overriding ==
Where overloading was creating methods with the same name and different arguments (and therefore a different signature), overriding occurs when a method replaces another method further up the inheritance hierarchy that has the same signature.  For example, consider the following classes:
Where overloading was creating methods with the same name and different arguments (and therefore a different signature), [http://www.akadia.com/services/dotnet_polymorphism.html overriding] occurs when a method replaces another method further up the inheritance hierarchy that has the same signature.  For example, consider the following classes:
 


<pre>
<pre>
public class Button
public class ImageButton
{
{
&nbsp;&nbsp;&nbsp;&nbsp;// in C#, the keyword virtual indicates that a method can be overridden
&nbsp;&nbsp;&nbsp;&nbsp;// in C#, the keyword virtual indicates that a method can be overridden
&nbsp;&nbsp;&nbsp;&nbsp;public virtual void OnClick(object sender, EventArgs e) { }
&nbsp;&nbsp;&nbsp;&nbsp;public virtual void Paint(Graphics graphics, EventArgs e) { }
}
}


public class ToggleButton : Button
public class ToggleButton : ImageButton
{
{
&nbsp;&nbsp;&nbsp;&nbsp;// in C#, overriding is an EXPLICIT action by using the keyword override
&nbsp;&nbsp;&nbsp;&nbsp;// in C#, overriding is an EXPLICIT action by using the keyword override
&nbsp;&nbsp;&nbsp;&nbsp;public override void OnClick(object sender, EventArgs e) { }
&nbsp;&nbsp;&nbsp;&nbsp;public override void Paint(Graphics graphics, EventArgs e) { }
}
}
</pre>
</pre>


The ToggleButton class inherits directly from the Button class.  ToggleButton has a method OnClick() that overrides the OnClick() method of Button that was inherited.  Notice that C# above mandates explicit overriding (the use of the keyword <tt>override</tt>) -- other languages such as Java allow for implicit overriding, where methods with the same signature automatically override their inherited methods without the use of an <tt>override</tt> keyword.
 
The ToggleButton class inherits directly from the ImageButton class.  ToggleButton has a method Paint() that overrides the Paint() method of ImageButton that was inherited.  Notice that C# above mandates explicit overriding (the use of the keyword <tt>override</tt>) -- other languages such as Java allow for implicit overriding, where methods with the same signature automatically override their inherited methods without the use of an <tt>override</tt> keyword.
 


One major advantage of overriding methods is that you get [http://msdn2.microsoft.com/en-us/library/ms173152(VS.80).aspx polymorphic behavior].  For example, if a List object was created and populated as...
One major advantage of overriding methods is that you get [http://msdn2.microsoft.com/en-us/library/ms173152(VS.80).aspx polymorphic behavior].  For example, if a List object was created and populated as...


<pre>
<pre>
List<Button> buttons = new List<Button>();
List<ImageButton> buttons = new List<ImageButton>();


buttons.add(new Button());
buttons.add(new ImageButton());
buttons.add(new ToggleButton());
buttons.add(new ToggleButton());
buttons.add(new Button());
buttons.add(new ImageButton());
</pre>
</pre>


...then polymorphism allows the following actions with the displayed results:
 
...then polymorphism allows the following actions with the displayed results (in C# syntax):
 


<pre>
<pre>
foreach (Button button in buttons)
foreach (ImageButton button in buttons)
&nbsp;&nbsp;&nbsp;&nbsp;button.OnClick(this, new EventArgs());
&nbsp;&nbsp;&nbsp;&nbsp;button.Paint(this.CreateGraphics(), new EventArgs());


// iteration 1 -- calls Button's OnClick()
// iteration 1 -- calls ImageButton's Paint()
// iteration 2 -- calls ToggleButton's OnClick()
// iteration 2 -- calls ToggleButton's Paint()
// iteration 3 -- calls Button's OnClick()
// iteration 3 -- calls ImageButton's Paint()
</pre>
</pre>


This dynamic method invocation (the decision about which method to call being made at runtime) is the polymorphic behavior that was produced from overriding the OnClick() method.
 
This dynamic method invocation (the decision about which method to call being made at runtime) is the polymorphic behavior that was produced from overriding the Paint() method.
 
 
Whereas overloading resolution was a function of the compiler, overriding resolution is a function of the runtime environment.  With overloading, any decisions about which method to call was based first on the type the object was declared to be (for example, Tooth in Tooth ptTooth = new PerioTooth()).  Overriding uses [http://books.google.com/books?id=6N3LNLR4-JAC&pg=PA212&lpg=PA212&dq=%22dynamic+method+invocation%22+overriding+runtime&source=web&ots=4qXmo_tNRm&sig=wWdg7JgweJwWw3e2RZkr7g4Rwgg dynamic method invocation] to look at the actual class type (PerioTooth in the aforementioned example) to determine which override to call.  In the most common object-oriented languages, the types of the arguments are not considered.




=== CLOS (see-loss or kloss) and Multi-Method Language Overriding ===
=== CLOS (see-loss or kloss) and Multi-Method Language Overriding ===
[http://en.wikipedia.org/wiki/Common_Lisp_Object_System Common List Object System (CLOS)] is a dynamic object oriented language that is an extension of [http://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html Common Lisp].  It is a [http://c2.com/cgi/wiki?MultiMethods multi-method language].  A multi-method language is distinguishable from non multi-method languages by the decision mechanism by which overridden methods are chosen at runtime.
[http://en.wikipedia.org/wiki/Common_Lisp_Object_System Common List Object System (CLOS)] is a dynamic object oriented language that is an extension of [http://www.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html Common Lisp].  It is a [http://c2.com/cgi/wiki?MultiMethods multi-method language].  A multi-method language is distinguishable from non multi-method languages by the decision mechanism by which overridden methods are chosen at runtime.


In more common object oriented languages (like Java or C#), the runtime decision about which overloaded is made is based on the type of the object being sent the message and NOT the type of the arguments to that message.  At compile time, the type of the arguments is used to determine an appropriate method in the set of overloaded methods that match a given signature, but this action is strictly  a strategy of the compiler to check for valid code.  At runtime, the type of the arguments play no role.
In more common object oriented languages (like Java or C#), the runtime decision about which overloaded is made is based on the type of the object being sent the message and NOT the type of the arguments to that message.  At compile time, the type of the arguments is used to determine an appropriate method in the set of overloaded methods that match a given signature, but this action is strictly  a strategy of the compiler to check for valid code.  At runtime, the type of the arguments play no role.


For example, consider the following example in C#:
For example, consider the following example in C#:


<pre>
<pre>
Line 92: Line 125:
}
}
</pre>
</pre>


The following code will not run using C# because it is unable to decide which Print() method to call!
The following code will not run using C# because it is unable to decide which Print() method to call!


<pre>
<pre>
Line 100: Line 135:
print.Print(person);
print.Print(person);
</pre>
</pre>


C# is unable to determine which method to call because it is unable to figure out what person really is because it is an argument -- the fact that it is an Administrator is ignored!   
C# is unable to determine which method to call because it is unable to figure out what person really is because it is an argument -- the fact that it is an Administrator is ignored!   


On the other hand, a multi-method language such as CLOS considers the argument types at runtime and will determine which Print() method to call.  In the above example, languages of this type would decide that since the person argument is of type Administrator, FormatPrint::Print(Administrator) will be selected and executed at runtime.
On the other hand, a multi-method language such as CLOS considers the argument types at runtime and will determine which Print() method to call.  In the above example, languages of this type would decide that since the person argument is of type Administrator, FormatPrint::Print(Administrator) will be selected and executed at runtime.


=== C# and Non Multi-Method Language Overriding ===
=== C# and Non Multi-Method Language Overriding ===
Line 130: Line 169:
}
}
</pre>
</pre>


Note that the following code decides which overridden method to call based on the type of argument before the message Print().
Note that the following code decides which overridden method to call based on the type of argument before the message Print().


<pre>
<pre>
Line 148: Line 189:
people[2].Print();
people[2].Print();
</pre>
</pre>


== Summary ==
== Summary ==
Overloading happens when methods in the scope of a class share the name but differ in the type of arguments passed.  The methods do not share a common signature.  Conversely, overriding a method happens when the method a method has the exact signature of one that the class inherited -- in which case the new method replaces the old one.  Multi-method languages differ from non-multi-method languages in how they decide which of the method to invoke.  Multi-method languages use the type of the arguments whereas non multi-method languages use the type of the object being sent the message.
Overloading happens when methods in the scope of a class share the name but differ in the type of arguments passed.  The methods do not share a common signature.  Conversely, overriding a method happens when the method a method has the exact signature of one that the class inherited -- in which case the new method replaces the old one.  Multi-method languages differ from non-multi-method languages in how they decide which of the method to invoke.  Multi-method languages use the type of the arguments whereas non multi-method languages use the type of the object being sent the message.

Revision as of 22:22, 27 October 2007

Author: Matthew B. Simmons


Objective

The objective of this document is to present the concepts of method overloading and method overriding. In doing so, it will contrast how method overriding is handled in common object-oriented programming languages (such as C#, Java or C++) and in multimethod languages.

Overloading

Method overloading occurs when there are two methods within the scope of a class that have the same name but different parameter list (and therefore different signatures). The scope of a class is not necessarily limited to the file that defines it, but it will also include methods from each superclass up the inheritance hierarchy.


The principal becomes a little more complicated when one considers the method in which the compiler uses to determine which overloaded method to activate when parameters involve subtypes. Consider the following partial class definitions taken from a national dental practice management system. In it there are Tooth objects and PerioTooth objects, which are a subclass of Tooth objects. There are also Restorations objects and PerioSplint objects, which are children of Restorations. The syntax is in C#.


public class Tooth
{
    public bool AddRestoration(Restoration restoration) { }
}

public class PerioTooth : Tooth
{
    public bool AddRestoration(PerioSplint restoration) { }
}


PerioTooth now has two overloaded methods AddRestoration() that add either a normal Restoration (the first definition) or a PerioSplint, which is specific to periodontal work (the second definition). They are both within the same class scope of PerioTooth. Consider the following:


Tooth tooth = new Tooth();
PerioTooth perioTooth = new PerioTooth();
Tooth ptTooth = new PerioTooth();

tooth.AddRestoration(new Restoration(Restorations.Amalgam, "MO", 32);
perioTooth.AddRestoration(new Restoration(Restorations.Composite, "O", 3);
ptTooth.AddRestoration(new PerioSplint("4-6");


When the compiler sees calls to AddRestoration(), it first checks the type of the receiver of the call -- which is determined by the object type followed by the variable name when the object is instantiated. For example, Tooth in "Tooth tooth = new Tooth()" or PerioTooth in "PerioTooth tooth = new PerioTooth()." From there it begins looking for a signature match by using the types of the arguments.


Method overloading requires caution. A method should not be overloaded if it and the newly created method do not mirror functionality almost exactly. It would be counterintuitive to overload one AddRestoration() to add a Restoration object to a tooth and another AddRestoration() to determine the current temperature in Guatemala!

Overriding

Where overloading was creating methods with the same name and different arguments (and therefore a different signature), overriding occurs when a method replaces another method further up the inheritance hierarchy that has the same signature. For example, consider the following classes:


public class ImageButton
{
    // in C#, the keyword virtual indicates that a method can be overridden
    public virtual void Paint(Graphics graphics, EventArgs e) { }
}

public class ToggleButton : ImageButton
{
    // in C#, overriding is an EXPLICIT action by using the keyword override
    public override void Paint(Graphics graphics, EventArgs e) { }
}


The ToggleButton class inherits directly from the ImageButton class. ToggleButton has a method Paint() that overrides the Paint() method of ImageButton that was inherited. Notice that C# above mandates explicit overriding (the use of the keyword override) -- other languages such as Java allow for implicit overriding, where methods with the same signature automatically override their inherited methods without the use of an override keyword.


One major advantage of overriding methods is that you get polymorphic behavior. For example, if a List object was created and populated as...


List<ImageButton> buttons = new List<ImageButton>();

buttons.add(new ImageButton());
buttons.add(new ToggleButton());
buttons.add(new ImageButton());


...then polymorphism allows the following actions with the displayed results (in C# syntax):


foreach (ImageButton button in buttons)
    button.Paint(this.CreateGraphics(), new EventArgs());

// iteration 1 -- calls ImageButton's Paint()
// iteration 2 -- calls ToggleButton's Paint()
// iteration 3 -- calls ImageButton's Paint()


This dynamic method invocation (the decision about which method to call being made at runtime) is the polymorphic behavior that was produced from overriding the Paint() method.


Whereas overloading resolution was a function of the compiler, overriding resolution is a function of the runtime environment. With overloading, any decisions about which method to call was based first on the type the object was declared to be (for example, Tooth in Tooth ptTooth = new PerioTooth()). Overriding uses dynamic method invocation to look at the actual class type (PerioTooth in the aforementioned example) to determine which override to call. In the most common object-oriented languages, the types of the arguments are not considered.


CLOS (see-loss or kloss) and Multi-Method Language Overriding

Common List Object System (CLOS) is a dynamic object oriented language that is an extension of Common Lisp. It is a multi-method language. A multi-method language is distinguishable from non multi-method languages by the decision mechanism by which overridden methods are chosen at runtime.


In more common object oriented languages (like Java or C#), the runtime decision about which overloaded is made is based on the type of the object being sent the message and NOT the type of the arguments to that message. At compile time, the type of the arguments is used to determine an appropriate method in the set of overloaded methods that match a given signature, but this action is strictly a strategy of the compiler to check for valid code. At runtime, the type of the arguments play no role.


For example, consider the following example in C#:


public class Person
{
    public string name = string.Empty;
}

public class User : Person { }
public class Administrator : Person { }
public class Maintainer : Person { }

public class FormatPrint 
{
    public void Print(User person) { MessageBox.Show("User"); }
    public void Print(Administrator person) { MessageBox.Show("Administrator"); }
    public void Print(Maintainer person) { MessageBox.Show("Maintainer"); }
}


The following code will not run using C# because it is unable to decide which Print() method to call!


FormatPrint formatPrint = new FormatPrint();
Person person = new Administrator();
print.Print(person);


C# is unable to determine which method to call because it is unable to figure out what person really is because it is an argument -- the fact that it is an Administrator is ignored!


On the other hand, a multi-method language such as CLOS considers the argument types at runtime and will determine which Print() method to call. In the above example, languages of this type would decide that since the person argument is of type Administrator, FormatPrint::Print(Administrator) will be selected and executed at runtime.


C# and Non Multi-Method Language Overriding

Unlike CLOS, C# (and other popular object oriented languages like Java) is not a multi-method language so the decision about which overridden method to call at runtime is based on the type of the object being sent the message. Consider the following modification to the above code:

public class Person 
{
    public string name = string.Empty;
    public virtual void Print() { };
}

public class User : Person
{
    public override void Print() { MessageBox.Show("User"); }
}

public class Administrator : Person
{
    public override void Print() { MessageBox.Show("Administrator"); }
}

public class Maintainer : Person
{
    public override void Print() { MessageBox.Show("Maintainer"); }
}


Note that the following code decides which overridden method to call based on the type of argument before the message Print().


List<Person> people = new List<Person>();
people.Add(new Administrator());
people.Add(new Maintainer());
people.Add(new User());

// prints "Administrator"
people[0].Print();

// prints "Maintainer"
people[1].Print();

// prints "User"
people[2].Print();


Summary

Overloading happens when methods in the scope of a class share the name but differ in the type of arguments passed. The methods do not share a common signature. Conversely, overriding a method happens when the method a method has the exact signature of one that the class inherited -- in which case the new method replaces the old one. Multi-method languages differ from non-multi-method languages in how they decide which of the method to invoke. Multi-method languages use the type of the arguments whereas non multi-method languages use the type of the object being sent the message.