What is the difference between casting and coercing?

Casting is the process by which you treat an object type as another type, Coercing is converting one object to another.

Note that in the former process there is no conversion involved, you have a type that you would like to treat as another, say for example, you have 3 different objects that inherit from a base type, and you have a method that will take that base type, at any point, if you know the specific child type, you can CAST it to what it is and use all the specific methods and properties of that object and that will not create a new instance of the object.

On the other hand, coercing implies the creation of a new object in memory of the new type and then the original type would be copied over to the new one, leaving both objects in memory (until the Garbage Collectors takes either away, or both).

As an example consider the following code:

class baseClass {}
class childClass : baseClass {}
class otherClass {}

public void doSomethingWithBase(baseClass item) {}

public void mainMethod()
{
    var obj1 = new baseClass();
    var obj2 = new childClass();
    var obj3 = new otherClass();

    doSomethingWithBase(obj1); //not a problem, obj1 is already of type baseClass
    doSomethingWithBase(obj2); //not a problem, obj2 is implicitly casted to baseClass
    doSomethingWithBase(obj3); //won't compile without additional code
}
  • obj1 is passed without any casting or coercing (conversion) because it's already of the same type baseClass
  • obj2 is implicitly casted to base, meaning there's no creation of a new object because obj2 can already be baseClass
  • obj3 needs to be converted somehow to base, you'll need to provide your own method to convert from otherClass to baseClass, which will involve creating a new object of type baseClass and filling it by copying the data from obj3.

A good example is the Convert C# class where it provides custom code to convert among different types.


Usages vary, as you note.

My personal usages are:

  • A "cast" is the usage of a cast operator. A cast operator instructs the compiler that either (1) this expression is not known to be of the given type, but I promise you that the value will be of that type at runtime; the compiler is to treat the expression as being of the given type, and the runtime will produce an error if it is not, or (2) the expression is of a different type entirely, but there is a well-known way to associate instances of the expression's type with instances of the cast-to type. The compiler is instructed to generate code that performs the conversion. The attentive reader will note that these are opposites, which I think is a neat trick.

  • A "conversion" is an operation by which a value of one type is treated as a value of another type -- usually a different type, though an "identity conversion" is still a conversion, technically speaking. The conversion may be "representation changing", like int to double, or it might be "representation preserving" like string to object. Conversions may be "implicit", which do not require a cast, or "explicit", which do require a cast.

  • A "coercion" is a representation-changing implicit conversion.


Casting preserves the type of objects. Coercion does not.

Coercion is taking the value of a type that is NOT assignment compatible and converting to a type that is assignment compatible. Here I perform a coercion because Int32 does NOT inherit from Int64...so it's NOT assignment compatible. This is a widening coercion (no data lost). A widening coercion is a.k.a. an implicit conversion. A Coercion performs a conversion.

void Main()
{
    System.Int32 a = 100;
    System.Int64 b = a;
    b.GetType();//The type is System.Int64.  
}

Casting allows you to treat a type as if it were of a different type while also preserving the type.

    void Main()
    {
        Derived d = new Derived();
        Base bb = d;
        //b.N();//INVALID.  Calls to the type Derived are not possible because bb is of type Base
        bb.GetType();//The type is Derived.  bb is still of type Derived despite not being able to call members of Test
    }

    class Base 
    {
        public void M() {}
    }

    class Derived: Base
    {
        public void N() {}
    }

Source: The Common Language Infrastructure Annotated Standard by James S. Miller

Now what's odd is that Microsoft's documentation on Casting does not align with the ecma-335 specification definition of Casting.

Explicit conversions (casts): Explicit conversions require a cast operator. Casting is required when information might be lost in the conversion, or when the conversion might not succeed for other reasons. Typical examples include numeric conversion to a type that has less precision or a smaller range, and conversion of a base-class instance to a derived class.

...This sounds like Coercions not Casting.

For example,

  object o = 1;
  int i = (int)o;//Explicit conversions require a cast operator
  i.GetType();//The type has been explicitly converted to System.Int32.  Object type is not preserved.  This meets the definition of Coercion not casting.

Who knows? Maybe Microsoft is checking if anybody reads this stuff.


Type Conversion:

The word conversion refers to either implicitly or explicitly changing a value from one data type to another, e.g. a 16-bit integer to a 32-bit integer.

The word coercion is used to denote an implicit conversion.

The word cast typically refers to an explicit type conversion (as opposed to an implicit conversion), regardless of whether this is a re-interpretation of a bit-pattern or a real conversion.

So, coercion is implicit, cast is explicit, and conversion is any of them.


Few examples (from the same source) :

Coercion (implicit):

double  d;
int     i;
if (d > i)      d = i;

Cast (explicit):

double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; //result == 9

Tags:

C#

Oop