Once upon a time in a kingdom far far away someone wrote a code that required two string arguments:
public class Worker
{
public void DoWork( string name, string surname )
{
Console.WriteLine( $"{name} {surname}" );
}
}
All the people used the code for years without any issues:
new Worker().DoWork( "john", "doe" );
Then, someone in a hurry did something bad which should never happen. Arguments were swapped in a call:
new Worker().DoWork( "doe", "john" );
Consequences were severe.
The culprit was tried and expelled from the kingdom. The king called for his best wizards and asked them to do something so that it never ever happens in the future.
One of the wizards suggested that introducing types would make it clear of what real intentions of arguments are:
public class Name
{
public Name( string value )
{
this.Value = value;
}
public string Value { get; set; }
public override string ToString()
{
return this.Value;
}
}
public class Surname
{
public Surname( string value )
{
this.Value = value;
}
public string Value { get; set; }
public override string ToString()
{
return this.Value;
}
}
public class Worker
{
public void DoWork( Name name, Surname surname )
{
Console.WriteLine( $"{name} {surname}" );
}
}
Initially people complained a bit but then started to get used to the new calling convention:
new Worker().DoWork( new Name( "john" ), new Surname( "doe" ) );
The problems were gone. Everyone was happy.
Years passed, some wizards were gone, new wizards came to the kingdom. One of new wizards reviewed the code and came up with an idea.
- Why this convention is that awkward, why wrap strings in auxiliary types? - thought the wizard.
And he came up with an idea to add implicit conversion operators:
public class Name
{
public Name( string value )
{
this.Value = value;
}
public string Value { get; set; }
public override string ToString()
{
return this.Value;
}
public static implicit operator Name( string value )
{
return new Name( value );
}
}
public class Surname
{
public Surname( string value )
{
this.Value = value;
}
public string Value { get; set; }
public override string ToString()
{
return this.Value;
}
public static implicit operator Surname( string value )
{
return new Surname( value );
}
}
The new wizard was very proud of himself. He barely told anyone of his conversion operators so everyone else was still using the well established convention:
new Worker().DoWork( new Name( "john" ), new Surname( "doe" ) );
But, since the conversion was now implicit, the wizard was able to make his own code shorter:
new Worker().DoWork( "john", "doe" );
Years passed, new people arrived and then, someone in a hurry did something bad which should never happen. Arguments were swapped in a call:
new Worker().DoWork( "doe", "john" );
Consequences were severe.
Was the culprit tried and expelled from the kingdom, same as last time?
Not really, the Wizard Council blamed the new wizard, the one who introduced both implicit conversion operators.
He was tried and expelled from the kingdom. His changes were reverted forever and everyone lived happily ever after.
This is based on a (almost) true story.