tags:

views:

869

answers:

3

How do I create my own primitive? For example an integer that has a range of to 1-10.

EDIT: This came from a task on Rosetta Code.

Defining Primitive Data Types: Demonstrate how to define a type that behaves like an integer but has a lowest valid value of 1 and a highest valid value of 10.

I added it here because I thought it might be useful to others.

+3  A: 
Structure LimitedInt
  Implements IComparable(Of LimitedInt)
  Implements IEquatable(Of LimitedInt)

  Private m_Value As Integer 'treat the default, 0 as being really 1'

  Public ReadOnly Property Value() As Integer
   Get
     Return If(m_Value = 0, 1, m_Value)
   End Get
  End Property

  Public Sub New(ByVal value As Integer)
   If value < 1 Or value > 10 Then 
      Throw New ArgumentOutOfRangeException("value")
   End If
   m_Value = value
  End Sub

  Public Function CompareTo(ByVal other As LimitedInt) As Integer _
      Implements System.IComparable(Of LimitedInt).CompareTo
   Return Me.Value - other.Value
  End Function

  Public Overloads Function Equals(ByVal other As LimitedInt) As Boolean _
     Implements System.IEquatable(Of LimitedInt).Equals
   Return Me.Value = other.Value
  End Function

  Public Overrides Function GetHashCode() As Integer
   Return Value.GetHashCode
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
   If TypeOf obj Is LimitedInt Then Return CType(obj, LimitedInt) = Me
  End Function

  Public Shared Operator =(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Boolean
   Return left.Equals(right)
  End Operator

  Public Shared Operator <>(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Boolean
   Return Not (left = right)
  End Operator

  Public Shared Operator +(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value + right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator -(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value - right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator *(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value * right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator /(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Double
   Return left.Value / right.Value
  End Operator

  Public Shared Operator \(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value \ right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator Mod(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value Mod right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator And(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value And right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator Or(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value Or right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator Xor(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As LimitedInt
   Dim temp As Integer = left.Value Xor right.Value
   Select Case temp
     Case 1 To 10 : Return New LimitedInt(temp)
     Case Else : Throw New OverflowException
   End Select
  End Operator

  Public Shared Operator ^(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Double
   Return left.Value ^ right.Value
  End Operator

  Public Shared Operator <(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Boolean
   Return left.Value < right.Value
  End Operator

  Public Shared Operator >(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Boolean
   Return left.Value > right.Value
  End Operator

  Public Shared Operator <=(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Boolean
   Return left.Value <= right.Value
  End Operator

  Public Shared Operator >=(ByVal left As LimitedInt, _
     ByVal right As LimitedInt) As Boolean
   Return left.Value >= right.Value
  End Operator

  Public Shared Widening Operator CType(ByVal left As LimitedInt) As Integer
   Return left.Value
  End Operator

  Public Shared Narrowing Operator CType(ByVal left As Integer) As LimitedInt
   Return New LimitedInt(left)
  End Operator


End Structure
Jonathan Allen
Are you fishing for upvotes?
dalle
Why use an Integer when you can use a Byte? It amazes me.
Eduardo León
Puke...VB is so ugly on SO.
FlySwat
@Jonathan: agreed. I'm all sad now. Thanks, Gauenwolf, you've ruined Christmas.
Shog9
Not really sure why this was downvoted. The fact that it's ugly is SO's fault, and the fact that VB is quite verbose is a design decision. Overall, I think that this code snippet can be quite useful, at least to clarify: Data Types are not magical constructs, they are normal classes/structs.
Michael Stum
@Michael: it's a code dump, no explanatory text whatsoever. IMHO, breaking it up with a few non-code paragraphs would go a long way to mask the ugliness (wrapping the longer lines wouldn't hurt either, but i understand some of that is VB's fault). That said, i didn't down vote it; -2 is low enough.
Shog9
write another ' at the end of the comment as a workaround.It would make more sense to use the range check in the constructor (e.g. return New LimitedInt(left.Value Or right.Value) ) rather than checking in most methods
ggf31416
+7  A: 

Ok, lets see. First off, there are some datatypes build into the CLR. Those cannot be modified or new ones added, since they are part of the standard. You can find a list here or here. That's C#, but the list should also exist for VB.net somewhere, and it should look equal because the underlying CLR is the same. Also, the list is not complete because floats and char are missing, but you get the idea.

But then, there are some structs that encapsulate those Data Types and add some Extra functionality. For example, System.Int32 is just a plain standard struct, no magic involved. Feel free to look at it in Reflector, it's in mscorlib:

[Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int>

So you want your own "1 to 10" Integer? Then I recommend looking at the nearest suitable type, which is either Int16 or Byte. If you look at them, you can see that they all look somewhat similar, but that they are based on one of the built-in datatypes.

Just copy/pasting and modifying some of the built-in structs (i.e. System.Byte) does not completely work because some members are internal (i.e. NumberFormatInfo.ValidateParseStyleInteger), but Reflector could help here.

Michael Stum
It's Byte, not Int16. But you got the idea. +1
Eduardo León
+2  A: 

By using Delphi.Net or Delphi Prism (both .Net languages), you can define variables like this:

MyAge : 0..120;
NumOfFingersAfterNewYear : 0..10;

A nice advantage is that you'll get compile-time range-checking with it.

Wouter van Nifterick
Cool. Stuff like this made Delphi so great in the past. Did anyone have a look (Reflector) what Delphi complies this to?
Michael Stum
I think it would be worth picking up Delphi just for that, even if I didn't use it for anything else.
Jonathan Allen