Page 1 of 1

## A Unit System Rate Topic: //<![CDATA[ rating = new ipb.rating( 'topic_rate_', { url: 'http://www.dreamincode.net/forums/index.php?app=forums&module=ajax&section=topics&do=rateTopic&t=344882&amp;s=10a36d896f2b532d17563d6ace65636a&md5check=' + ipb.vars['secure_hash'], cur_rating: 0, rated: 0, allow_rate: 0, multi_rate: 1, show_rate_text: true } ); //]]>

• MrCupOfT

Reputation: 2290
• Posts: 9,529
• Joined: 29-May 08

Posted 15 April 2014 - 06:34 PM

A Unit System

Having a System of Units encode the context of the value.
For example 10 10 what? Without context is useless.
Let's add a context Water Depth:= 10 Ok, we now know the water depth is 10 but we still don't know 10 of what? 10 cats, 10 feet, 10 metres.

For Example Water Depth:= 10(metres)

Also by using a System of Units you can rather refine the parameters required for a function.

```''  TaxiFare : ICurrency = <Distance : IUnitOfDistance> * <Price : ICurrency>
Function TaxiFare( Distance : IUnitOfDistance, Price As IUnitOfCurrency ) : ICurrency
''
End Function

```

The Base Interface
All of my units in my system will have a Value and Symbol associated with it.
```Public Interface IUnitOfMeasure
End Interface

```

Let's define an Interface that describes a unit of distance. Metres, Inches, etc
```Public Interface IUnitOfDistance
Inherits IUnitOfMeasure
Function ToMetres() As Metres
Function FromMetres(m As Metres) As IUnitOfDistance
Function CreateInstance(v As Double) As IUnitOfDistance
End Interface

```

Now let's create so concrete instance of those interface, so out units can inherit from them.

```Public MustInherit Class UnitOfMeasure
Implements IUnitOfMeasure
Private _Value As Double
Private _PostFix As Boolean
Private _Symbol As String

Friend Sub New(Value As Double, Postfix As Boolean, Symbol As String )
_Value   = Value
_PostFix = Postfix
_Symbol  = Symbol
End Sub

Public ReadOnly Property Value As Double Implements IUnitOfMeasure.Value
Get
Return _Value
End Get
End Property

Public ReadOnly Property PostFix As Boolean
Get
Return _PostFix
End Get
End Property

Public ReadOnly Property Symbol As String Implements IUnitOfMeasure.Symbol
Get
Return _Symbol
End Get
End Property

Public Overrides Function ToString() As String
If PostFix Then Return String.Format("{0}{1}",Value,Symbol)
Return String.Format("{0}{1}",Symbol,Value)
End Function

End Class

```

```Public  MustInherit Class UnitOfDistance
Inherits UnitOfMeasure
Implements IUnitOfDistance

Friend  Sub New(Value As Double, Symbol As string)
MyBase.New(Value ,True,Symbol )
End Sub
MustOverride Function ToMetres() As Metres Implements IUnitOfDistance.ToMetres
MustOverride Function CreateInstance(Value As Double) As  IUnitOfDistance Implements IUnitOfDistance.CreateInstance
MustOverride Function FromMetres(m As metres) As  IUnitOfDistance Implements IUnitOfDistance.FromMetres

Public Shared Operator +(ByVal x As UnitOfDistance, y As UnitOfDistance) As IUnitOfDistance
If x.GetType = y.GetType then Return x.CreateInstance(x.Value + y.Value)
Return x.FromMetres( x.ToMetres + y.ToMetres)
End Operator

Public  Shared Operator -(ByVal x As UnitOfDistance, y As UnitOfDistance) As IUnitOfDistance
If x.GetType = y.GetType then Return x.CreateInstance(x.Value - y.Value)
Return x.FromMetres( x.ToMetres - y.ToMetres)
End Operator

Public Shared Function Convert(Of T1 As UnitOfDistance,
T2 As {New, UnitOfDistance})(value As T1) As T2
Dim p1 = value.ToMetres
Dim tmp As New T2
Return DirectCast(tmp + p1, T2)
End Function

End Class

```

Now we finally ready to implement a couple of UnitOfDistances.

Metres
```Public Class Metres
Inherits UnitOfDistance
Public Sub New()
MyBase.New(0, "m")
End Sub

Public sub new(Value As Double)
MyBase.New(Value,"m")
End Sub

Public Overrides Function CreateInstance(Value As Double) As IUnitOfDistance
Return New Metres(Value)
End Function

Public Overrides Function FromMetres(m As Metres) As IUnitOfDistance
Return New Metres(Me.Value)
End Function

Public Overrides Function ToMetres() As Metres
Return New Metres(Me.Value)
End Function

Public Shadows Shared Operator +(x As Metres, y As Metres) As Metres
Return New Metres(x.Value + y.Value)
End Operator
Public Shadows Shared Operator -(x As Metres, y As Metres) As Metres
Return New Metres(x.Value + y.Value)
End Operator
Public Shared Widening Operator CType (ByVal v As Double) As Metres
Return New Metres(v)
End Operator

End Class

```

Inches
```Public Class Inches
Inherits UnitOfDistance

Public Sub New()
MyBase.New(0, """")
End Sub

Public Sub New(Value As Double)
MyBase.New(Value, """")
End Sub
Public Overrides Function CreateInstance(Value As Double) As IUnitOfDistance
Return New Inches(value)
End Function

Public Overrides Function ToMetres() As Metres
Return New Metres((Value * 2.54) / 100)
End Function

Public Overrides Function FromMetres(m As Metres) As IUnitOfDistance
Return New Inches((m.Value * 100) / 2.54)
End Function

Public Shared Widening Operator CType(ByVal v As Double) As Inches
Return New Inches(v)
End Operator
End Class

```

Usage Example

```Module Module1

Sub Main()
Dim m0 = New Metres(1)
Dim i0 = New Inches(12)
Dim m1 = (1.0).ToUnitOfDistance(Of Metres)
Dim i1 = (12.0).ToUnitOfDistance(Of Inches)
Dim m2 As Metres = 1
Dim i2 As Inches = 12

Dim r0_mi = m0 + i0
Dim r0_im = i0 + m0
Dim r1_mi = m1 + i1
Dim r1_im = i1 + m1
Dim r2_mi = m2 + i2
Dim r2_im = i2 + m2
Dim r3 = UnitOfDistance.Convert(Of inches,Metres)(i0)
Dim r4 = UnitOfDistance.Convert(Of Metres,Inches)(m0)
End Sub

<Extension> Function ToUnitOfDistance(Of T As {New, UnitOfDistance})(value As Double) As T
Return DirectCast( (New T).CreateInstance(value),T)
End Function
end Module

```

Did you notice something surprising? Even though in derived units (metres and inches) we didn't implement any operators for performing adding and subtracting values in those units? We can still perform those operations. How?

Spoiler

Exercises

• Add the ability to compare UnitsOfDistace
• Add a new UnitOfMeasure (eg Temperature, Time, Energy etc) (SI Units)

• Add some unit of measure that are a function two of different units of measure systems. Eg
```Speed = IUnitOfDistance / ITime  (aka IRate(Of Ta, Tb )
Area = IUnitOfDistance * IUnitOfDistance

```

Is This A Good Question/Topic? 0

## Replies To: A Unit System

### #2 Curtis Rutland

• （╯°□°）╯︵ (~ .o.)~

Reputation: 4748
• Posts: 8,453
• Joined: 08-June 10

Posted 17 April 2014 - 11:31 AM

Very neat concept. I wonder if you could also do implicit casting, so assigning one unit to another (of the same "kind") would handle the conversion automatically?

• MrCupOfT

Reputation: 2290
• Posts: 9,529
• Joined: 29-May 08

Posted 17 April 2014 - 07:36 PM

Curtis Rutland You probably could implement a implicit cast, but I'm not a fan of implicit casts.
I like to make the cast explicit.
For example if you where using the above classes in a C# project.
```var x =  12.0(inches);
var d = 100.0(metres);

```

It doesn't make the code look much worse, if anything rather neat looking.
Not far away from the syntax use in F#
```1.0<cm>
55.0<miles/hour>

```

### #4 Curtis Rutland

• （╯°□°）╯︵ (~ .o.)~

Reputation: 4748
• Posts: 8,453
• Joined: 08-June 10

Posted 18 April 2014 - 07:27 AM

Agreed, I usually prefer explicit casting as well. I feel that implicit is occasionally appropriate, but it does make the code more readable with the cast operator being explicit.