programming in c equality n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Programming in C# Equality PowerPoint Presentation
Download Presentation
Programming in C# Equality

Loading in 2 Seconds...

play fullscreen
1 / 44

Programming in C# Equality - PowerPoint PPT Presentation


  • 144 Views
  • Uploaded on

Programming in C# Equality. CSE / ECE 668 Prof . Roger Crawfis. Equality. What does it mean for to variables to be equal: Numeric types – easy Strings – some caveats Employee records - ?. Equality. Two basic types of equality: Value equality

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Programming in C# Equality' - bary


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
programming in c equality

Programming in C#Equality

CSE / ECE 668

Prof. Roger Crawfis

equality
Equality
  • What does it mean for to variables to be equal:
    • Numeric types – easy
    • Strings – some caveats
    • Employee records - ?
equality1
Equality
  • Two basic types of equality:
    • Value equality
      • Two variables are equal if they have the same value (mean the same thing).
    • Referential equality
      • Two variables are equal if they refer to the same instance (pointer or storage equality).
  • Difference:
    • Are two 2008 Lamborghini Gallardo’s equal?
      • Theoretically, it depends on the context.
default equality
Default Equality
  • As expected, all value types have value-based equality.

double a = 1.2;

double b = 1.2;

boolareEqual = a == b; // true.

  • Strings also have value equality.

string name = “Crawfis”;

string instructor = “Crawfis”;

boolareEqual = a == b; // true.

default equality1
Default Equality
  • What is the default equality for classes?
  • In C++ there is none.
  • In C# there is. It is referential equality.

classfoo {…};

foo A = newfoo();

foo B = newfoo();

boolareEqual = A == B; // false.

object C = A; // C refers to the same instance as A.

boolareEqual = C == A; // true.

default equality2
Default Equality
  • Subtleties:

int[] a = {0,1,2,3};

int[] b = {0,1,2,3};

int[] a = {0,1,2,3};

int[] b = a;

int[] a = null;

int[] b = null;

a == b => false

a == b => true

a == b => true!

default equality3
Default Equality
  • The default equality for structs is simply the pairwise comparison between each of its fields.
  • That is, two structs are equal if all of their fields are equal.
    • Value-based field are compared by value.
    • Reference fields are compared by reference (by default).
testing for equality
Testing for Equality
  • There are actually five protocols or methods that you can use to test for equality.
  • They may provide different results!!!
    • Witness one says they are the same.
    • Witness two says they are different.
testing for equality1
Testing for Equality
  • Operators for equality (== and !=).
  • Recall that all operators are defined as static methods for a type.
    • If there are different types on each side of the conditional, the compiler decides which type to use.
  • All types have these operators defined.
    • Unlike C++.
testing for equality2
Testing for Equality
  • The Object.Equals method exists for all types.
  • It is virtual and hence can be overridden.
  • Determines at run-time which type’s Equals method is called (Polymorphic).

int x = 5;

object y = 5;

x == y => compile time error

x.Equals(y) => true

y.Equals(x) => true

Note: x is boxed!

testing for equality3
Testing for Equality
  • Why have both of these?
    • If a variable is null, calling Equals on it will result in a run-time exception.
    • There is overhead associated with virtual function calls (and all function calls).
    • The == operator can be statically inlined.
    • Sometimes we want different behavior:
      • We both own the same car (equals) but mine is not yours (not equals).
testing for equality4
Testing for Equality
  • There are also two static methods in the object class.

static bool object.Equals(object o1, object o2);

    • Simply calls o1.Equals if o1 != null.

static bool object.ReferenceEquals(object o1, object o2);

    • Since Equals can be overridden, this provides a forced reference equality check.
    • Note: object.ReferenceEquals(5,5) = false!
the iequatable t interface
The IEquatable<T> interface
  • Although the System.Object.Equals method can be applied to any type it will force a boxing of value types.
  • The IEquatable<T> interface allows value types which implement the interface to be called using a.Equals(b) without the boxing.
  • Used as a generic constraint on user classes:

class Test<T> where T : IEquatable<T>

overriding equality
Overriding Equality
  • In general, do not change the default behavior (semantics).
  • Implementing the default behavior for structs and the IComparable<T> interface can avoid boxing and provide good performance improvements.
  • Some immutable types may want different semantics: string, DateTime
overriding equality1
Overriding Equality
  • But what if I have Employee records and I want to check if two instances are equal?
  • Do not build this into the Employee class.
  • Use plug-in comparison classes to dynamically specify the behavior you want.
  • This is what is used in the collection classes.
equality semantics
Equality Semantics
  • If you override the semantics, then you must also override the hash code algorithm.
  • There are several rules that you should make sure you follow for each of ==, Equals, and GetHashCode.
  • If you override one of these you should probably override them all.
overriding gethashcode
Overriding GetHashCode
  • Rules for GetHashCode:
    • Consistency – it must return the same value if called repeated on the same object.
      • Even if you change the object!!!!
      • Base it on an immutable value of the object.
    • Equality – it must return the same value on two objects for which Equals returns true.
    • Robust – it should not throw exceptions.
    • Efficient – GetHashCode should generate a random distribution among all inputs.
overriding gethashcode1
Overriding GetHashCode
  • For reference types, each instance has a unique hash-code based on the storage location.
  • Can add it to a Collection (Dictionary), change the contents, and still get it back out using the hash code.
  • If you override the hash code based on content rather than storage location, then the instance may need to be removed from the Dictionary, changed and added back.
overriding gethashcode2
Overriding GetHashCode
  • Structs and value types are different, since they are never changed in-place, they are copied out, modified and copied back in.
  • Hence this problem exists regardless of whether you override GetHashCode.

structX { publicint x; }

Dictionary<X, int> test = newDictionary<X, int>();

X t1 = newX();

test[t1] = 5;

t1.x = 3;

test[t1] = 4;

Adds a new entry to the dictionary

overriding equals
Overriding Equals
  • Rules for overriding equals:
    • An object should equal itself (reflexive).
    • An object can not equal null
      • Since it is an instance method call.
      • Unless it is a Nullable type.
    • Equality is commutative and transitive.
      • a == b => b == a; b == c => a ==c;
    • Equality operations are repeatable
    • Equality is robust – no exceptions.
overriding and
Overriding == and !=
  • You should always override == for value types for efficiency.
  • You should never (or rarely) override it for reference types.
  • Rules for overriding ==
    • a != b should be equal to !(a == b).
    • It should have the same semantics as Equals.
      • Hence the previous rules apply.
example craps
Example - Craps

namespaceOSU.Gambling.Craps

{

structDiceRoll : IEquatable<DiceRoll>

    {

internalDiceRoll(int die1, int die2)

        {

this.die1 = die1;

this.die2 = die2;

        }

privateint die1, die2;

example craps1
Example - Craps

I’ve never played this game.

Alas structs always have a public default constructor

I really want to control the creation, so make this constructor internal or private.

namespaceOSU.Gambling.Craps

{

structDiceRoll : IEquatable<DiceRoll>

    {

internalDiceRoll(int die1, int die2)

        {

this.die1 = die1;

this.die2 = die2;

        }

privateint die1, die2;

Requires two dice.

example craps2
Example - Craps

publicint Die1 { get { return die1+1; } }

publicint Die2 { get { return die2+1; } }

Add one to allow for a default value of zero.

Error checking should be done to ensure that die1 and die2 lie between 0 and 5.

example craps3
Example - Craps

publicbool Equals(DiceRoll other)

        {

return die1 == other.die1 && die2 == other.die2

            || die1 == other.die2 && die2 == other.die1;

        }

publicoverridebool Equals(object other)

        {

if (!(other isDiceRoll)) returnfalse;

return Equals((DiceRoll)other); // unbox the struct and compare.

        }

example craps4
Example - Craps

publicstaticbooloperator ==(DiceRoll die1, DiceRoll die2)

        {

return die1.Equals(die2);

        }

publicstaticbooloperator !=(DiceRoll die1, DiceRoll die2)

        {

return !die1.Equals(die2);

        }

example craps5
Example - Craps

publicoverrideintGetHashCode()

        {

return die1*11 + die2;

        }

publicoverrideintGetHashCode()

        {

if (die1 > die2)

return 11 * die1 + die2;

else

return 11 * die2 + die1;

        }

example craps6
Example - Craps

      public override int GetHashCode()

        {

            return die1*11 + die2;

        }

publicoverrideintGetHashCode()

        {

if (die1 > die2)

return 11 * die1 + die2;

else

return 11 * die2 + die1;

        }

example craps7
Example - Craps

publicstaticDiceRollRollDice()

        {

DiceRoll roll = newDiceRoll();

            roll.die1 = random.Next(0,5);

            roll.die2 = random.Next(0,5);

return roll;

        }

privatestaticreadonlyRandomrandom;

staticDiceRoll()

        {

            random = newRandom(System.DateTime.Now.Millisecond);

        }

    }

design principle
Design Principle
  • The previous code illustrated a good design principle you should follow:

Ensure that zero is a valid state for all value types.

  • Dice only have values from 1 to 6, so to make 0 a valid state we add one on the output.
avoiding all of this
Avoiding all of this
  • The previous example can be made trivial and avoid all of this by simply requiring that die1 always be greater than die2 in the implementation.
    • Control the creation.
  • Works theoretically, but you may want the die to look more random for presentation purposes.
example2 craps class
Example2 – Craps class

publicclassDiceRoll : IEquatable<DiceRoll>

    {

publicbool Equals(DiceRoll other)

        {

if (other == null)

returnfalse;

return(die1 == other.die1 && die2 == other.die2)

            || (die1 == other.die2 && die2 == other.die1);

        }

example2 craps class1
Example2 – Craps class

publicoverridebool Equals(object other)

        {

if (other == null)

returnfalse;

if (object.ReferenceEquals(this, other))

returntrue;

if (this.GetType() != other.GetType())

returnfalse;

return Equals(other asDiceRoll);

        }

example2 craps class2
Example2 – Craps class

publicstaticDiceRollRollDice()

        {

returnnewDiceRoll(random.Next(0,5), random.Next(0,5));

        }

  • The only way to create a DiceRoll now.
programming in c comparison sorting

Programming in C#Comparison (Sorting)

CSE / ECE 668

Prof. Roger Crawfis

comparison
Comparison
  • Comparing two instances of a type has many of the same properties and pitfalls as testing for equality.
  • Equality is generally more fussy.
  • Only two protocols for a type providing its own comparison:
    • The IComparable interface
    • The > and < operators
icomparable
IComparable
  • The IComparable<T> and IComparable interfaces allow for sorting or ordering of a collection.
  • They are used in the Array.Sort method.

public interfaceIComparable <T>{

intCompareTo(T other); // -1 if this < other, 0 if this == other, 1 if this > other

}

5.CompareTo(7) => -1

“World”.CompareTo(“Hello”) => 1

32.CompareTo(8*4) => 0

icomparable1
IComparable
  • Classes implementing IComparable are
    • Values types like Int32, Double, DateTime, …
    • The class Enum as base class of all enumeration types
    • The class String
  • Defines a type to be is-aIComparable.
the and operators
The > and < operators
  • Value types that have a clear context independent concept of less than and greater than should implement the < and > operators.
  • These are compiled statically into the code, making value types more efficient.
programming in c changing comparison

Programming in C#Changing Comparison

CSE 494R

(proposed course for 459 Programming in C#)

Prof. Roger Crawfis

icomparer
IComparer
  • IComparer is used to provide pluggable (or interchangable) comparisons.
  • Used with a type, not part of the type.

public interfaceIComparer {

intCompare(object x, object y); // -1 if x < y, 0 if x == y, 1 if x > y

}

  • IComparer implementations:
    • Comparer, CaseInsensitiveComparer: for string comparisons
custom icomparer
Custom IComparer
  • Creation of table of strings:

string[][] Table = {

new string[] {"John", "Dow", "programmer"},

new string[] {"Bob", "Smith", "agent"},

new string[] {"Jane", "Dow", "assistant"},

new string[] {"Jack", "Sparrow", "manager"}

};

  • Printing the table:

foreach (string[] Row in Table) {

Console.WriteLine(String.Join(", ", Row));

}

custom icomparer1
Custom IComparer
  • Comparer for single table (array) column:

classArrayComparer<T> : IComparer<T[]> where T : IComparable<T> {

private int m_Index;

publicArrayComparer(intindex) {

this->index = index;

}

publicint Compare(T[] x, T[] y) {

returnx[index ].CompareTo( y[index ] );

}

}

  • Printing the table:

Array.Sort(Employees, newArrayComparer<string>(2));

foreach (string[] Row in Employees) {

Console.WriteLine(String.Join(", ", Row));

}

Bob, Smith, agent

Jane, Dow, assistant

Jack, Sparrow, manager

John, Dow, programmer

custom icomparer2
Custom IComparer
  • Implement IComparableand IComparable<T>

public interface IComparable {

intCompareTo(object obj); // -1: this < obj, 0: this == obj, 1: this > obj

}

public interface IComparable<T> {

intCompareTo(T obj); // -1: this < obj, 0: this == obj, 1: this > obj

}

class Fraction : IComparable, IComparable<Fraction> {

private int n, d;

public intCompareTo(object o) {

return CompareTo((Fraction) o);

}

public intCompareTo(Fraction f) {

return n*f.d – f.n*d

}

}