Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using real world units instead of types

I have a project with many calculations involving a lot of real world units :

  • Distance;
  • Temperature;
  • Flow rate;
  • ...

This project involves complicated and numerous calculation formulas.

That's why I supposed the use of custom types like Temperature, Distance... can be good for code readability. For example:

Temperature x = -55.3;
Meter y = 3;

or

var x = new Temperature(-55.3);

I tried to make a Temperature class that uses a double internal value.

public class Temperature
{
    double _Value = double.NaN;

    public Temperature() { }

    public Temperature(double v) {
        _Value = v;
    }

    public static implicit operator Temperature(double v) {
        return new Temperature(v);
    }
}

But class are nullable. This mean that something like :

Temperature myTemp;

is "correct" and will be null. I dont want this. I dont want to use structs because they are too limited :

  • They cannot use parameterless constructor nor instance field intializers like double _Value = double.Nan; to define a default value (I wand default underlying double value to be NaN)
  • They cannot inherits from classes, they only can implement Interfaces

Them I wonder whether there is a way to tell C#:

Temperature myTemp = 23K; // C# does not implement anything to make K unit...

but I know C# does not handle no custom units.

Temperature myTemp = new Kelvin(23); // This might work

So I imagine I could create two Celsius and Kelvin classes that inherits from Temperature, and then I started to wonder if the idea really worth it, because it involves a lot of coding and testing.

That's the discussion I would like to start :

Would the use of real world units in my code instead of .NET types would be a good thing or not ? Did anyone this already ? What are the pitfalls and the best practices ? Or should I better keep stay away from this and use standard .NET types ?

like image 605
Larry Avatar asked Oct 22 '10 10:10

Larry


2 Answers

Why not try a struct that looks like this:

/// <summary>
/// Temperature class that uses a base unit of Celsius
/// </summary>
public struct Temp
{
    public static Temp FromCelsius(double value)
    {
        return new Temp(value);
    }

    public static Temp FromFahrenheit(double value)
    {
        return new Temp((value - 32) * 5 / 9);
    }

    public static Temp FromKelvin(double value)
    {
        return new Temp(value - 273.15);
    }

    public static Temp operator +(Temp left, Temp right)
    {
        return Temp.FromCelsius(left.Celsius + right.Celsius);
    }

    private double _value;

    private Temp(double value)
    {
        _value = value;
    }

    public double Kelvin
    {
        get { return _value + 273.15; }
    }

    public double Celsius
    {
        get { return _value; }
    }

    public double Fahrenheit
    {
        get { return _value / 5 * 9 + 32; }
    }
}

Then use it like, say, this:

    static void Main(string[] args)
    {
        var c = Temp.FromCelsius(30);
        var f = Temp.FromFahrenheit(20);
        var k = Temp.FromKelvin(20);

        var total = c + f + k;
        Console.WriteLine("Total temp is {0}F", total.Fahrenheit);
    }
like image 185
OJ. Avatar answered Nov 04 '22 01:11

OJ.


One way to achieve this would be to use composition of the basic object (Temperature in your case) with a TemperatureTraits class that specializes the basic object. By analogy to C++, the String equivalent class basic_string is actually a class template (generic in C# terms) that has template parameters not only for the string element (char, wide char) but also a traits class that elaborates on how the class behaves for a given type of string element (e.g. char_traits).

In your case, you might define a generic like

public class MeasurableWithUnits<class M MEASURABLE, class U UNITS>

and then implementation would depend not only on the measurable class but also on the units class. How useful this would be in practice would depend on how much of such an object could be made truly generic - what operations are common across combinations of Measurable and Units?

There is a research paper on C# traits here, if this approach looks interesting.

like image 28
Steve Townsend Avatar answered Nov 04 '22 00:11

Steve Townsend