Define a primitive data type: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Java}}: Grammar fix, added convenience add and assign methods, simplified checkBounds)
(Whitespace, VB.NET highlighting might be broken? "End" isn't highlighted.)
Line 196: Line 196:
This class relies on implicit conversions to do most int operations; however the combined operations with assignment have to be coded explicitly.
This class relies on implicit conversions to do most int operations; however the combined operations with assignment have to be coded explicitly.


<lang cpp> #include <stdexcept>
<lang cpp>#include <stdexcept>
class tiny_int
{
public:
tiny_int(int i):
value(i)
{
if (value < 1)
throw std::out_of_range("tiny_int: value smaller than 1");
if (value > 10)
throw std::out_of_range("tiny_int: value larger than 10");
}
operator int() const
{
return value;
}
tiny_int& operator+=(int i)
{
// by assigning to *this instead of directly modifying value, the
// constructor is called and thus the check is enforced
*this = value + i;
return *this;
}
tiny_int& operator-=(int i)
{
*this = value - i;
return *this;
}
tiny_int& operator*=(int i)
{
*this = value * i;
return *this;
}
tiny_int& operator/=(int i)
{
*this = value / i;
return *this;
}
tiny_int& operator<<=(int i)
{
*this = value << i;
return *this;
}
tiny_int& operator>>=(int i)
{
*this = value >> i;
return *this;
}
tiny_int& operator&=(int i)
{
*this = value & i;
return *this;
}
tiny_int& operator|=(int i)
{
*this = value | i;
return *this;
}
private:
unsigned char value; // we don't need more space
};</lang>


class tiny_int
{
public:
tiny_int(int i):
value(i)
{
if (value < 1)
throw std::out_of_range("tiny_int: value smaller than 1");
if (value > 10)
throw std::out_of_range("tiny_int: value larger than 10");
}
operator int() const
{
return value;
}
tiny_int& operator+=(int i)
{
// by assigning to *this instead of directly modifying value, the
// constructor is called and thus the check is enforced
*this = value + i;
return *this;
}
tiny_int& operator-=(int i)
{
*this = value - i;
return *this;
}
tiny_int& operator*=(int i)
{
*this = value * i;
return *this;
}
tiny_int& operator/=(int i)
{
*this = value / i;
return *this;
}
tiny_int& operator<<=(int i)
{
*this = value << i;
return *this;
}
tiny_int& operator>>=(int i)
{
*this = value >> i;
return *this;
}
tiny_int& operator&=(int i)
{
*this = value & i;
return *this;
}
tiny_int& operator|=(int i)
{
*this = value | i;
return *this;
}
private:
unsigned char value; // we don't need more space
};</lang>
=={{header|Common Lisp}}==
=={{header|Common Lisp}}==

The built-in integer type specifier provides range parameters. <code>deftype</code> may be used to define an alias for it.
The built-in integer type specifier provides range parameters. <code>deftype</code> may be used to define an alias for it.


Line 293: Line 291:


=={{header|E}}==
=={{header|E}}==
<lang e> def MyNumber := 1..10
<lang e>def MyNumber := 1..10

for i :MyNumber in [0, 5, 10, 15, 20, 25] {
println(i)
}</lang>


for i :MyNumber in [0, 5, 10, 15, 20, 25] {
println(i)
}</lang>
(Note: The region guard, while provided with E, is entirely unprivileged code, and could be argued not to be "primitive".)
(Note: The region guard, while provided with E, is entirely unprivileged code, and could be argued not to be "primitive".)


Line 439: Line 436:
Haskell doesn't have any built-in subrange types. However, it is possible to declare arbitrary types that "behave like" any of the built-in types on the "usual" numeric etc. operations, because these operations are defined by type-classes. So we generalize the task a bit, and first declare a generic container type that supports an additional ''check'' operation. Then, we lift any operation in the base type to the container type, by executing the check after each operation:
Haskell doesn't have any built-in subrange types. However, it is possible to declare arbitrary types that "behave like" any of the built-in types on the "usual" numeric etc. operations, because these operations are defined by type-classes. So we generalize the task a bit, and first declare a generic container type that supports an additional ''check'' operation. Then, we lift any operation in the base type to the container type, by executing the check after each operation:


<lang haskell> {-# OPTIONS -fglasgow-exts #-}
<lang haskell>{-# OPTIONS -fglasgow-exts #-}

data Check a b = Check { unCheck :: b } deriving (Eq, Ord)
data Check a b = Check { unCheck :: b } deriving (Eq, Ord)

class Checked a b where
class Checked a b where
check :: b -> Check a b
check :: b -> Check a b

lift f x = f (unCheck x)
lift f x = f (unCheck x)
liftc f x = check $ f (unCheck x)
liftc f x = check $ f (unCheck x)

lift2 f x y = f (unCheck x) (unCheck y)
lift2 f x y = f (unCheck x) (unCheck y)
lift2c f x y = check $ f (unCheck x) (unCheck y)
lift2c f x y = check $ f (unCheck x) (unCheck y)
lift2p f x y = (check u, check v) where (u,v) = f (unCheck x) (unCheck y)
lift2p f x y = (check u, check v) where (u,v) = f (unCheck x) (unCheck y)

instance Show b => Show (Check a b) where
instance Show b => Show (Check a b) where
show (Check x) = show x
show (Check x) = show x
showsPrec p (Check x) = showsPrec p x
showsPrec p (Check x) = showsPrec p x

instance (Enum b, Checked a b) => Enum (Check a b) where
instance (Enum b, Checked a b) => Enum (Check a b) where
succ = liftc succ
succ = liftc succ
pred = liftc pred
pred = liftc pred
toEnum = check . toEnum
toEnum = check . toEnum
fromEnum = lift fromEnum
fromEnum = lift fromEnum

instance (Num b, Checked a b) => Num (Check a b) where
instance (Num b, Checked a b) => Num (Check a b) where
(+) = lift2c (+)
(+) = lift2c (+)
(-) = lift2c (-)
(-) = lift2c (-)
(*) = lift2c (*)
(*) = lift2c (*)
negate = liftc negate
negate = liftc negate
abs = liftc abs
abs = liftc abs
signum = liftc signum
signum = liftc signum
fromInteger = check . fromInteger
fromInteger = check . fromInteger
instance (Real b, Checked a b) => Real (Check a b) where
toRational = lift toRational
instance (Integral b, Checked a b) => Integral (Check a b) where
quot = lift2c quot
rem = lift2c rem
div = lift2c div
mod = lift2c mod
quotRem = lift2p quotRem
divMod = lift2p divMod
toInteger = lift toInteger</lang>


instance (Real b, Checked a b) => Real (Check a b) where
toRational = lift toRational

instance (Integral b, Checked a b) => Integral (Check a b) where
quot = lift2c quot
rem = lift2c rem
div = lift2c div
mod = lift2c mod
quotRem = lift2p quotRem
divMod = lift2p divMod
toInteger = lift toInteger</lang>
Now we can declare the a subrange 1..10 of integer like this:
Now we can declare the a subrange 1..10 of integer like this:
<lang haskell> newtype TinyInt = TinyInt Int
instance Checked TinyInt Int where
check x | x >= 0 && x <= 10 = Check x
| otherwise = error "Out of range"</lang>


<lang haskell>newtype TinyInt = TinyInt Int

instance Checked TinyInt Int where
check x | x >= 0 && x <= 10 = Check x
| otherwise = error "Out of range"</lang>
In the same way, we could now declare the subtype of the even integers:
In the same way, we could now declare the subtype of the even integers:
<lang haskell>newtype EvenInt = EvenInt Int


<lang haskell> newtype EvenInt = EvenInt Int
instance Checked EvenInt Int where
check x | even x = Check x
| otherwise = error "Not even"</lang>
instance Checked EvenInt Int where
check x | even x = Check x
| otherwise = error "Not even"</lang>


Similarly, we could declare the subtype of floating point numbers with restricted exponent, and so on.
Similarly, we could declare the subtype of floating point numbers with restricted exponent, and so on.

=={{header|Java}}==
=={{header|Java}}==
The closest you can get to defining a primitive type in Java is making a new wrapper class with methods for math operations.
The closest you can get to defining a primitive type in Java is making a new wrapper class with methods for math operations.
Line 585: Line 578:


=={{header|OCaml}}==
=={{header|OCaml}}==
<lang ocaml>
<lang ocaml>exception Out_of_bounds
exception Out_of_bounds


type 'a bounds = { min: 'a; max: 'a }
type 'a bounds = { min: 'a; max: 'a }
Line 612: Line 604:
(mk_bounded res a.bounds)
(mk_bounded res a.bounds)
;;
;;
(** val op : ('a -> 'a -> 'a) -> 'a bounded -> 'a bounded -> 'a bounded *)
(** val op : ('a -> 'a -> 'a) -> 'a bounded -> 'a bounded -> 'a bounded *)</lang>
</lang>


Using in the interactive top level:
Using in the interactive top level:
<lang ocaml>
<lang ocaml># let range = mk_bounds 1 10 ;;
# let range = mk_bounds 1 10 ;;
val range : int bounds = {min = 1; max = 10}
val range : int bounds = {min = 1; max = 10}


Line 630: Line 620:


# op ( + ) a b ;;
# op ( + ) a b ;;
- : int bounded = {value = 7; bounds = {min = 1; max = 10}}
- : int bounded = {value = 7; bounds = {min = 1; max = 10}}</lang>
</lang>


which can be used with floats in the same way:
which can be used with floats in the same way:
<lang ocaml>
<lang ocaml># let rf = mk_bounds 1.0 10.0 ;;
# let rf = mk_bounds 1.0 10.0 ;;
val rf : float bounds = {min = 1.; max = 10.}
val rf : float bounds = {min = 1.; max = 10.}


Line 641: Line 629:
and b = mk_bounded 5.6 rf in
and b = mk_bounded 5.6 rf in
op ( +. ) a b ;;
op ( +. ) a b ;;
- : float bounded = {value = 7.8; bounds = {min = 1.; max = 10.}}
- : float bounded = {value = 7.8; bounds = {min = 1.; max = 10.}}</lang>
</lang>


=={{header|Perl}}==
=={{header|Perl}}==
{{works with|Perl|5}}
{{works with|Perl|5}}
<lang perl> package One_To_Ten;
<lang perl>package One_To_Ten;
use Carp qw(croak);
use Carp qw(croak);
use Tie::Scalar qw();
use Tie::Scalar qw();
use base qw(Tie::StdScalar);
use base qw(Tie::StdScalar);

sub STORE {
sub STORE {
my $self = shift;
my $self = shift;
my $val = int shift;
my $val = int shift;
croak 'out of bounds' if $val < 1 or $val > 10;
croak 'out of bounds' if $val < 1 or $val > 10;
$$self = $val;
$$self = $val;
};
};
package main;
tie my $t, 'One_To_Ten';
$t = 3; # ok
$t = 5.2; # ok, silently coerced to int
$t = -2; # dies, too small
$t = 11; # dies, too big
$t = 'xyzzy';
# dies, too small. string is 0 interpreted numerically</lang>


package main;
tie my $t, 'One_To_Ten';
$t = 3; # ok
$t = 5.2; # ok, silently coerced to int
$t = -2; # dies, too small
$t = 11; # dies, too big
$t = 'xyzzy';
# dies, too small. string is 0 interpreted numerically</lang>
=={{header|Python}}==
=={{header|Python}}==
This doesn't really apply as Python names don't have a type, but something can be done:
This doesn't really apply as Python names don't have a type, but something can be done:
Line 859: Line 845:


=={{header|Toka}}==
=={{header|Toka}}==
needs quotes
<lang toka>needs quotes
{
{
variable update
variable update
[ update @ [ ! ] [ @ ] ifTrueFalse update off ] is action
[ update @ [ ! ] [ @ ] ifTrueFalse update off ] is action
[ dup >r 0 11 r> within [ update on ] [ drop ." Out of bounds\n " ] ifTrueFalse ]
[ dup >r 0 11 r> within [ update on ] [ drop ." Out of bounds\n " ] ifTrueFalse ]
[ ` [ invoke cell-size malloc # ` action compile ` ] invoke is ]
[ ` [ invoke cell-size malloc # ` action compile ` ] invoke is ]
} is value:1-10:
} is value:1-10:
is to
is to
value:1-10: foo
1 to foo
foo .


value:1-10: foo
1 to foo
foo .</lang>
=={{header|Visual Basic .NET}}==
=={{header|Visual Basic .NET}}==


Line 878: Line 863:
Also note that some operators return a Double instead of a new LimitedInt. This was by choice in order to match the behavior of Integers in VB.
Also note that some operators return a Double instead of a new LimitedInt. This was by choice in order to match the behavior of Integers in VB.


<lang vb> Structure LimitedInt
<lang vbnet>Structure LimitedInt
Implements IComparable(Of LimitedInt)
Implements IComparable(Of LimitedInt)
Implements IEquatable(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")
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
Private m_Value As Integer 'treat the default, 0 as being really 1
Return Me.Value = other.Value
End Function
Public ReadOnly Property Value() As Integer

Get
Public Overrides Function GetHashCode() As Integer
Return If(m_Value = 0, 1, m_Value)
Return Value.GetHashCode
End Get
End Property
End Function

Public Sub New(ByVal value As Integer)
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If TypeOf obj Is LimitedInt Then Return CType(obj, LimitedInt) = Me
If value < 1 Or value > 10 Then Throw New ArgumentOutOfRangeException("value")
End Function
m_Value = value

End Sub
Public Shared Operator =(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
Return left.Equals(right)
Public Function CompareTo(ByVal other As LimitedInt) As Integer Implements System.IComparable(Of LimitedInt).CompareTo
End Operator
Return Me.Value - other.Value

End Function
Public Shared Operator <>(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
Return Not (left = right)
Public Overloads Function Equals(ByVal other As LimitedInt) As Boolean Implements System.IEquatable(Of LimitedInt).Equals
End Operator
Return Me.Value = other.Value

End Function
Public Shared Operator +(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
Dim temp As Integer = left.Value + right.Value
Public Overrides Function GetHashCode() As Integer
Select Case temp
Return Value.GetHashCode
Case 1 To 10 : Return New LimitedInt(temp)
End Function
Case Else : Throw New OverflowException
End Select
Public Overrides Function Equals(ByVal obj As Object) As Boolean
End Operator
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 LimitedInt
Dim temp As Integer = left.Value - right.Value
Public Shared Operator =(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
Select Case temp
Return left.Equals(right)
Case 1 To 10 : Return New LimitedInt(temp)
End Operator
Case Else : Throw New OverflowException
End Select
Public Shared Operator <>(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
End Operator
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
Public Shared Operator +(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
Select Case temp
Dim temp As Integer = left.Value + right.Value
Select Case temp
Case 1 To 10 : Return New LimitedInt(temp)
Case 1 To 10 : Return New LimitedInt(temp)
Case Else : Throw New OverflowException
End Select
Case Else : Throw New OverflowException
End Select
End Operator

End Operator
Public Shared Operator /(ByVal left As LimitedInt, ByVal right As LimitedInt) As Double
Return left.Value / right.Value
Public Shared Operator -(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
End Operator
Dim temp As Integer = left.Value - right.Value

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

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

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
Public Shared Operator \(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
Select Case temp
Dim temp As Integer = left.Value \ right.Value
Select Case temp
Case 1 To 10 : Return New LimitedInt(temp)
Case 1 To 10 : Return New LimitedInt(temp)
Case Else : Throw New OverflowException
End Select
Case Else : Throw New OverflowException
End Select
End Operator

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
Public Shared Operator Mod(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
Select Case temp
Dim temp As Integer = left.Value Mod right.Value
Select Case temp
Case 1 To 10 : Return New LimitedInt(temp)
Case 1 To 10 : Return New LimitedInt(temp)
Case Else : Throw New OverflowException
End Select
Case Else : Throw New OverflowException
End Select
End Operator

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
Public Shared Operator And(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
Select Case temp
Dim temp As Integer = left.Value And right.Value
Select Case temp
Case 1 To 10 : Return New LimitedInt(temp)
Case 1 To 10 : Return New LimitedInt(temp)
Case Else : Throw New OverflowException
End Select
Case Else : Throw New OverflowException
End Select
End Operator

End Operator
Public Shared Operator ^(ByVal left As LimitedInt, ByVal right As LimitedInt) As Double
Return left.Value ^ right.Value
Public Shared Operator Or(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
End Operator
Dim temp As Integer = left.Value Or right.Value

Select Case temp
Case 1 To 10 : Return New LimitedInt(temp)
Public Shared Operator <(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
Return left.Value < right.Value
Case Else : Throw New OverflowException
End Select
End Operator

End Operator
Public Shared Operator >(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
Return left.Value > right.Value
Public Shared Operator Xor(ByVal left As LimitedInt, ByVal right As LimitedInt) As LimitedInt
End Operator
Dim temp As Integer = left.Value Xor right.Value

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

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

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

End Operator
Public Shared Narrowing Operator CType(ByVal left As Integer) As LimitedInt
Return New LimitedInt(left)
Public Shared Operator >(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean
End Operator
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</lang>


End Structure</lang>
{{omit from|JavaScript}}
{{omit from|JavaScript}}
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have user-defined data structures. -->
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have user-defined data structures. -->

Revision as of 17:12, 21 September 2009

Task
Define a primitive data type
You are encouraged to solve this task according to the task description, using any language you may know.

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. Include all bounds checking you need to write, or explain how the compiler or interpreter creates those bounds checks for you.

Ada

type My_Type is range 1..10;

The compiler identifies the range of valid values from the range specification 1..10 and automatically builds in bounds checking where it is needed. The compiler is smart enough to omit bounds checking when it is not needed.

A : My_Type := 3;
B : My_Type := A;

The compiler will omit bounds checking for the assignment of A to B above because both values are of My_Type. A cannot hold a value outside the range of 1..10, therefore the assignment cannot produce an out of bounds result.

ALGOL 68

Built in or standard distribution routines

Bounded data types are not part of standard ALGOL 68, but can be implemented.

Implementation example

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
# assume max int <= ABS - max negative int #
INT max bounded = ( LENG max int * max int > long max int | ENTIER sqrt(max int) | max int );

MODE RANGE = STRUCT(INT lwb, upb);
MODE BOUNDED = STRUCT(INT value, RANGE range);
FORMAT bounded repr = $g"["g(-0)":"g(-0)"]"$;

# Define some useful operators for looping over ranges #
OP LWB = (RANGE range)INT: lwb OF range,
   UPB = (RANGE range)INT: upb OF range,
   LWB = (BOUNDED bounded)INT: lwb OF range OF bounded,
   UPB = (BOUNDED bounded)INT: upb OF range OF bounded;

PROC raise exception = ([]STRING args)VOID: (
  put(stand error, ("exception: ",args, newline));
  stop
);

PROC raise not implemented error := ([]STRING args)VOID: raise exception(args);
PROC raise bounds error := ([]STRING args)VOID: raise exception(args);

PRIO MIN=9, MAX=9;
OP MIN = ([]INT list)INT: ( 
  INT out:= list[LWB list];
  FOR index FROM LWB list+1 TO UPB list DO IF list[index]<out THEN out :=list[index] FI OD;
  out
);
OP MAX = ([]INT list)INT: ( 
  INT out:= list[LWB list];
  FOR index FROM LWB list+1 TO UPB list DO IF list[index]>out THEN out :=list[index] FI OD;
  out
);

PRIO ASSERTIN = 6;
OP ASSERTIN = (INT result, []RANGE range)BOUNDED: (
    BOUNDED out = (result, (MAX lwb OF range, MIN upb OF range));
    IF value OF out < lwb OF range OF out THEN
      raise bounds error(("out of bounds", whole(result, int width)," < [",whole(MAX lwb OF range, int width),":]"))
    ELIF value OF out > upb OF range OF out THEN
      raise bounds error(("out of bounds", whole(result, int width)," > [:",whole(MIN upb OF range, int width),"]"))
    FI;
    out
  ),
  ASSERTIN = (LONG INT result, []RANGE range)BOUNDED: (
    STRUCT (LONG INT value, RANGE range) out = (result, (MAX lwb OF range, MIN upb OF range));
    IF value OF out < lwb OF range OF out THEN
      raise bounds error(("out of bounds", whole(result, long int width)," < [",whole(MAX lwb OF range, int width),":]"))
    ELIF value OF out > upb OF range OF out THEN
      raise bounds error(("out of bounds", whole(result, long int width)," > [:",whole(MIN upb OF range, int width),"]"))
    FI;
    (SHORTEN value OF out, range OF out)
  ),
  ASSERTIN = (INT result, []BOUNDED bounds)BOUNDED: result ASSERTIN range OF bounds,
  ASSERTIN = (LONG INT result, []BOUNDED bounds)BOUNDED: result ASSERTIN range OF bounds;

INT half max int = max int OVER 2;
INT sqrt max int = ENTIER sqrt (max int);

OP + = (BOUNDED a, b)BOUNDED: 
         IF ABS value OF a < half max int AND ABS value OF b < half max int THEN
           value OF a + value OF b ASSERTIN []BOUNDED(a,b)
         ELSE
           LENG value OF a + value OF b ASSERTIN []BOUNDED(a,b)
         FI,
   - = (BOUNDED a, b)BOUNDED: value OF a + -value OF b ASSERTIN []BOUNDED(a,b),
   * = (BOUNDED a, b)BOUNDED: 
         IF ABS value OF a < sqrt max int AND ABS value OF b < sqrt max int THEN
           value OF a * value OF b ASSERTIN []BOUNDED(a,b)
         ELSE
           LENG value OF a * value OF b ASSERTIN []BOUNDED(a,b)
         FI,
   /  = (BOUNDED a, b)REAL: value OF a / value OF b,
   %  = (BOUNDED a, b)BOUNDED: value OF a % value OF b ASSERTIN []BOUNDED(a,b),
   %* = (BOUNDED a, b)BOUNDED: value OF a %* value OF b ASSERTIN []BOUNDED(a,b),
   ** = (BOUNDED a, INT exponent)BOUNDED: value OF a ** exponent ASSERTIN []BOUNDED(a);

OP OVER = (INT value, RANGE range)BOUNDED:
  IF ABS lwb OF range > max bounded THEN
    raise bounds error(("out of bounds, ABS", whole(lwb OF range, int width)," > [:",whole(max bounded, int width),"]"));
    SKIP
  ELIF ABS upb OF range > max bounded THEN
    raise bounds error(("out of bounds, ABS", whole(upb OF range, int width)," > [:",whole(max bounded, int width),"]"));
    SKIP
  ELSE
    value ASSERTIN []RANGE(range)
  FI;

OP INTINIT = (BOUNDED range)REAL: value OF range;

OP <  = (BOUNDED a, b)BOOL: value OF a < value OF b,
   >  = (BOUNDED a, b)BOOL: value OF a > value OF b,
   <= = (BOUNDED a, b)BOOL: NOT ( value OF a > value OF b ),
   >= = (BOUNDED a, b)BOOL: NOT ( value OF a < value OF b ),
   =  = (BOUNDED a, b)BOOL: value OF a = value OF b,
   /= = (BOUNDED a, b)BOOL: NOT (a = b);

# Monadic operators #
OP - = (BOUNDED range)BOUNDED: -value OF range ASSERTIN []BOUNDED(range),
   ABS = (BOUNDED range)BOUNDED: ABS value OF range ASSERTIN []BOUNDED(range);

COMMENT Operators for extended characters set, and increment/decrement "commented out" to save space. COMMENT

Test:

RANGE range = RANGE(0, 10000); 

# override the default exception #
raise bounds error := ([]STRING args)VOID: ( 
    putf(stand error, ($g$, args, $"- exiting to except bounds error"l$)); 
    except bounds error
  );

BOUNDED a, b := 0 OVER range;
FOR step FROM 4 BY 4 TO UPB range DO # something for pythagoras #
  b := b + step OVER range;
  a := ENTIER sqrt( 1.5 + 2 * value OF b ) OVER range OF b;
  printf(($"Sum of "$, bounded repr, a * a, b * b,
          $" is "$,    bounded repr, a * a + b * b, $l$))
OD;
except bounds error: 
  SKIP

Output:

Sum of          +9[0:10000]        +16[0:10000] is         +25[0:10000]
Sum of         +25[0:10000]       +144[0:10000] is        +169[0:10000]
Sum of         +49[0:10000]       +576[0:10000] is        +625[0:10000]
Sum of         +81[0:10000]      +1600[0:10000] is       +1681[0:10000]
Sum of        +121[0:10000]      +3600[0:10000] is       +3721[0:10000]
Sum of        +169[0:10000]      +7056[0:10000] is       +7225[0:10000]
out of bounds    +12544 > [:    +10000]- exiting to except bounds error

Other libraries or implementation specific extensions

As of February 2009 no open source libraries to do this task have been located.

C++

Works with: g++

This class relies on implicit conversions to do most int operations; however the combined operations with assignment have to be coded explicitly.

<lang cpp>#include <stdexcept>

class tiny_int { public:

 tiny_int(int i):
   value(i)
 {
   if (value < 1)
     throw std::out_of_range("tiny_int: value smaller than 1");
   if (value > 10)
     throw std::out_of_range("tiny_int: value larger than 10");
 }
 operator int() const
 {
   return value;
 }
 tiny_int& operator+=(int i)
 {
   // by assigning to *this instead of directly modifying value, the
   // constructor is called and thus the check is enforced
   *this = value + i;
   return *this;
 }
 tiny_int& operator-=(int i)
 {
   *this = value - i;
   return *this;
 }
 tiny_int& operator*=(int i)
 {
   *this = value * i;
   return *this;
 }
 tiny_int& operator/=(int i)
 {
   *this = value / i;
   return *this;
 }
 tiny_int& operator<<=(int i)
 {
   *this = value << i;
   return *this;
 }
 tiny_int& operator>>=(int i)
 {
   *this = value >> i;
   return *this;
 }
 tiny_int& operator&=(int i)
 {
   *this = value & i;
   return *this;
 }
 tiny_int& operator|=(int i)
 {
   *this = value | i;
   return *this;
 }

private:

 unsigned char value; // we don't need more space

};</lang>

Common Lisp

The built-in integer type specifier provides range parameters. deftype may be used to define an alias for it.

<lang lisp>(deftype one-to-ten ()

 '(integer 1 10))</lang>

For a bounds check, one may use typep (a predicate) or check-type (signals an error if not of the type).

<lang lisp>(defun word (i)

 (check-type i one-to-ten)
 (case i
   (1 "one")
   (2 "two")
   (3 "three")
   (4 "four")
   (5 "five")
   (6 "six")
   (7 "seven")
   (8 "eight")
   (9 "nine")
   (10 "ten")))</lang>

(Note that the above can be written without the separate check-type by using ecase instead of case, which signals an error when no case matches.)

To inform the compiler that a variable will be of a certain type, permitting optimizations, use a declaration:

<lang lisp>(dolist (i numbers)

 (declare (type one-to-ten i))
 ...)</lang>

Note, however, that the standard does not specify what happens in the event that a declaration is false (though SBCL, for example, does perform type checks on any declaration except when safety is 0); use check-type for portable bounds checks.

E

<lang e>def MyNumber := 1..10

for i :MyNumber in [0, 5, 10, 15, 20, 25] {

   println(i)

}</lang> (Note: The region guard, while provided with E, is entirely unprivileged code, and could be argued not to be "primitive".)

Fortran

Works with: Fortran version 90 and later

The module gives an example of how a bounded integer could be implemented in Fortran (not all the needed interfaces are implemented, and only the one for the + operator are shown). Bounds are checked at run-time.

<lang fortran>module Bounded

 implicit none
 type BoundedInteger
    integer, private :: v         ! we cannot allow direct access to this, or we
    integer, private :: from, to  !   can't check the bounds!
    logical, private :: critical
 end type BoundedInteger
 interface assignment(=)
    module procedure bounded_assign_bb, bounded_assign_bi !, &
                   ! bounded_assign_ib
 end interface
 interface operator(+)
    module procedure bounded_add_bbb !, bounded_add_bbi, &
                   ! bounded_add_bib, bounded_add_ibb,   &
                   ! bounded_add_iib, bounded_add_ibi,   &
                   ! bounded_add_bii
 end interface
 private :: bounded_assign_bb, bounded_assign_bi, &
            bounded_add_bbb

contains

 subroutine set_bound(bi, lower, upper, critical, value)
   type(BoundedInteger), intent(out) :: bi
   integer, intent(in) :: lower, upper
   integer, intent(in), optional :: value
   logical, intent(in), optional :: critical
   bi%from = min(lower, upper)
   bi%to = max(lower, upper)
   if ( present(critical) ) then
      bi%critical = critical
   else
      bi%critical = .false.
   end if
   if ( present(value) ) then
      bi = value
   end if
 end subroutine set_bound
 subroutine bounded_assign_bb(a, b)
   type(BoundedInteger), intent(out) :: a
   type(BoundedInteger), intent(in)  :: b
   call bounded_assign_bi(a, b%v)
 end subroutine bounded_assign_bb


 subroutine bounded_assign_bi(a, b)
   type(BoundedInteger), intent(out) :: a
   integer,              intent(in)  :: b
   if ( (a%from <= b) .and. (a%to >= b) ) then
      a%v = b
   else
      write(0,*) "BoundedInteger: out of bound assignment"
      if ( a%critical ) then
         stop 
      else
         if ( b < a%from ) then
            a%v = a%from
         else
            a%v = a%to
         end if
         write(0,"(A,' (',I0, ')')") "BoundedInteger: set to nearest bound", a%v
      end if
   end if
 end subroutine bounded_assign_bi


 function bounded_add_bbb(a, b) result(c)
   type(BoundedInteger) :: c
   type(BoundedInteger), intent(in) :: a, b
   integer :: t
   c%from = max(a%from, b%from)
   c%to   = min(a%to,   b%to)
   t = a%v + b%v
   if ( c%from <= t .and. c%to >= t ) then
      c%v = t
   else
      write(0,*) "BoundedInteger: out of bound sum"
      if ( a%critical .or. b%critical ) then
         stop
      else
         if ( t < c%from ) then
            c%v = c%from
         else
            c%v = c%to
         end if
         write(0,"(A,' (',I0,')')") "BoundedInteger: set to nearest bound", c%v
      end if
   end if
 end function bounded_add_bbb

end module Bounded</lang>

<lang fortran>program BoundedTest

 use Bounded
 implicit none
 type(BoundedInteger)     ::  a, b, c
 call set_bound(a, 1, 10)
 ! if we want to stop the program if a is out of bounds...
 ! call set_bound(a, 1, 10, critical=.true.)
 call set_bound(b, 1, 10)
 call set_bound(c, 1, 10)
 ! if we want to init c to a specific value...:
 ! call set_bound(c, 1, 10, value=6)
 a = 1         ! ok
 a = 4         ! ok
 a = -1        ! warning (a=1)
 a = 11        ! warning (a=10)
 a = 3         ! ok
 b = a         ! ok
 c = a + b     ! ok (3+3)
 c = c + a     ! ok (6+3=9)
 c = c + b     ! warning (c=10)

end program BoundedTest</lang>

Haskell

Haskell doesn't have any built-in subrange types. However, it is possible to declare arbitrary types that "behave like" any of the built-in types on the "usual" numeric etc. operations, because these operations are defined by type-classes. So we generalize the task a bit, and first declare a generic container type that supports an additional check operation. Then, we lift any operation in the base type to the container type, by executing the check after each operation:

<lang haskell>{-# OPTIONS -fglasgow-exts #-}

data Check a b = Check { unCheck :: b } deriving (Eq, Ord)

class Checked a b where

 check :: b -> Check a b

lift f x = f (unCheck x) liftc f x = check $ f (unCheck x)

lift2 f x y = f (unCheck x) (unCheck y) lift2c f x y = check $ f (unCheck x) (unCheck y) lift2p f x y = (check u, check v) where (u,v) = f (unCheck x) (unCheck y)

instance Show b => Show (Check a b) where

 show (Check x)        = show x
 showsPrec p (Check x) = showsPrec p x

instance (Enum b, Checked a b) => Enum (Check a b) where

 succ = liftc succ
 pred = liftc pred
 toEnum   = check . toEnum
 fromEnum = lift fromEnum

instance (Num b, Checked a b) => Num (Check a b) where

 (+) = lift2c (+)
 (-) = lift2c (-)
 (*) = lift2c (*)
negate = liftc negate
 abs    = liftc abs
  signum = liftc signum
 fromInteger = check . fromInteger

instance (Real b, Checked a b) => Real (Check a b) where

 toRational = lift toRational

instance (Integral b, Checked a b) => Integral (Check a b) where

 quot = lift2c quot
 rem  = lift2c rem
 div  = lift2c div
 mod  = lift2c mod       
 quotRem = lift2p quotRem
 divMod  = lift2p divMod
 toInteger = lift toInteger</lang>

Now we can declare the a subrange 1..10 of integer like this:

<lang haskell>newtype TinyInt = TinyInt Int

instance Checked TinyInt Int where

 check x | x >= 0 && x <= 10  =  Check x
         | otherwise          =  error "Out of range"</lang>

In the same way, we could now declare the subtype of the even integers: <lang haskell>newtype EvenInt = EvenInt Int

instance Checked EvenInt Int where
  check x | even x     =  Check x
          | otherwise  =  error "Not even"</lang>

Similarly, we could declare the subtype of floating point numbers with restricted exponent, and so on.

Java

The closest you can get to defining a primitive type in Java is making a new wrapper class with methods for math operations.

This example class throws an exception if the value is out of the bounds; it is implemented only in the assignment method "assign" and the addition method "add". The class can be easily extended.

<lang java>class BoundedIntOutOfBoundsException extends Exception {

 public BoundedIntOutOfBoundsException(int v, int l, int u) {
   super("value " + v + " is out of bounds [" + l + "," + u + "]");
 }

}

class BoundedInt {

 private int value;
 private int lower;
 private int upper;
 public BoundedInt(int l, int u) {
   lower = Math.min(l, u);
   upper = Math.max(l, u);
 }
 private boolean checkBounds(int v) {
   return ((v >= this.lower) && (v <= this.upper));
 }
 public void assign(BoundedInt i) throws BoundedIntOutOfBoundsException {{
   assign(i.value()); //could still throw Exception if the other BoundedInt has different bounds
 }
 public void assign(int v) throws BoundedIntOutOfBoundsException {
   if ( checkBounds(v) ) {
     this.value = v;
   } else {
     throw new BoundedIntOutOfBoundsException(v, this.lower, this.upper);
   }
 }
 public int add(BoundedInt i) throws BoundedIntOutOfBoundsException {
   return add(i.value());
 }
 public int add(int i) throws BoundedIntOutOfBoundsException {
   if ( checkBounds(this.value + i) ) {
     this.value += i;
   }  else {
     throw new BoundedIntOutOfBoundsException(this.value + i, this.lower, this.upper);
   }
   return this.value;
 }
 public int value() {
   return this.value;
 }

}


public class Bounded {

 public static void main(String[] args) throws BoundedIntOutOfBoundsException {
   BoundedInt a = new BoundedInt(1, 10);
   BoundedInt b = new BoundedInt(1, 10);
   a.assign(6);
   try {
     b.assign(12);
   } catch (Exception e) {
     System.out.print(e.getMessage() + "\n");
   }
   b.assign(9);
   try {
     a.add(b.value());
   } catch (Exception e) {
     System.out.print(e.getMessage() + "\n");
   }
 }

}</lang>

Modula-3

In Modula-3, subrange types are automatically subtypes of their base type, so if you define a type called MyInt to be the subrange [1..10] then MyInt is a subtype of INTEGER. If we defined MyChar as the subrange ['A'..'C'] then MyChar would be a subtype of CHAR. <lang modula3>TYPE MyInt = [1..10];</lang> MyInt can now be used anywhere an INTEGER can, such as the standard arithmetic functions. Trying to assign a value outside of the range of MyInt will result in a compile time warning, and/or a runtime error.

OCaml

<lang ocaml>exception Out_of_bounds

type 'a bounds = { min: 'a; max: 'a }

type 'a bounded = { value: 'a; bounds: 'a bounds }

let mk_bounds ~min ~max = { min=min; max=max } ;; (** val mk_bounds : min:'a -> max:'a -> 'a bounds *)

let check_bounds ~value ~bounds =

 if value < bounds.min || value > bounds.max then
   raise Out_of_bounds ;;

(** val check_bounds : value:'a -> bounds:'a bounds -> unit *)

let mk_bounded ~value ~bounds =

 check_bounds ~value ~bounds;
 { value=value; bounds=bounds } ;;

(** val mk_bounded : value:'a -> bounds:'a bounds -> 'a bounded *)

let op f a b =

 let res = f a.value b.value in
 if a.bounds <> b.bounds then
   invalid_arg "different bounds";      
 check_bounds res a.bounds;
 (mk_bounded res a.bounds)
 ;;            

(** val op : ('a -> 'a -> 'a) -> 'a bounded -> 'a bounded -> 'a bounded *)</lang>

Using in the interactive top level: <lang ocaml># let range = mk_bounds 1 10 ;; val range : int bounds = {min = 1; max = 10}

  1. let a = mk_bounded 2 range ;;

val a : int bounded = {value = 2; bounds = {min = 1; max = 10}}

  1. let b = mk_bounded 5 range ;;

val b : int bounded = {value = 5; bounds = {min = 1; max = 10}}

  1. let c = mk_bounded 14 range ;;

Exception: Out_of_bounds.

  1. op ( + ) a b ;;

- : int bounded = {value = 7; bounds = {min = 1; max = 10}}</lang>

which can be used with floats in the same way: <lang ocaml># let rf = mk_bounds 1.0 10.0 ;; val rf : float bounds = {min = 1.; max = 10.}

  1. let a = mk_bounded 2.2 rf
 and b = mk_bounded 5.6 rf in
 op ( +. ) a b ;;

- : float bounded = {value = 7.8; bounds = {min = 1.; max = 10.}}</lang>

Perl

Works with: Perl version 5

<lang perl>package One_To_Ten; use Carp qw(croak); use Tie::Scalar qw(); use base qw(Tie::StdScalar);

sub STORE {

   my $self = shift;
   my $val = int shift;
   croak 'out of bounds' if $val < 1 or $val > 10;
   $$self = $val;

};

package main; tie my $t, 'One_To_Ten'; $t = 3; # ok $t = 5.2; # ok, silently coerced to int $t = -2; # dies, too small $t = 11; # dies, too big $t = 'xyzzy';

  1. dies, too small. string is 0 interpreted numerically</lang>

Python

This doesn't really apply as Python names don't have a type, but something can be done: <lang python>>>> class num(int):

   def __init__(self, b):
       if 1 <= b <= 10:
           return int.__init__(self+0)
       else:
           raise ValueError,"Value %s should be >=0 and <= 10" % b


>>> x = num(3) >>> x = num(11)

Traceback (most recent call last):

 File "<pyshell#394>", line 1, in <module>
   x = num(11)
 File "<pyshell#392>", line 6, in __init__
   raise ValueError,"Value %s should be >=0 and <= 10" % b

ValueError: Value 11 should be >=0 and <= 10 >>> x 3 >>> type(x) <class '__main__.num'> >>> </lang>

Ruby

ref http://codeidol.com/other/rubyckbk/Numbers/Simulating-a-Subclass-of-Fixnum/

Some object-oriented languages won't let you subclass the "basic" data types
like integers. Other languages implement those data types as classes, so you
can subclass them, no questions asked. Ruby implements numbers as classes
(Integer, with its concrete subclasses Fixnum and Bignum), and you can subclass
those classes. If you try, though, you'll quickly discover that your subclasses
are useless: they don't have constructors.  

Ruby jealously guards the creation of new Integer objects. This way it ensures
that, for instance, there can be only one Fixnum instance for a given number

The easiest way to delegate all methods is to create a class that's nearly empty
and define a method_missing method.

<lang ruby>require 'test/unit' include Test::Unit::Assertions

class MyInt

 @@min = 1
 @@max = 10
 
 attr_reader :value
 private :value
 
 def initialize(val)
   begin
     v = Integer(val)
   rescue ArgumentError
     raise ArgumentError, "invalid value '#{val}', must be an integer"
   end
   
   unless v.between?(@@min, @@max)
     raise ArgumentError, "invalid value '#{v}', must be between #{@@min} and #{@@max}"
   end
   
   @value = v
 end
 
 def method_missing(m, *args)
   super unless @value.respond_to?(m)
   myint_args = args.collect do |arg|
     arg.kind_of?(self.class) ? arg.to_int : arg
   end
   result = @value.send(m, *myint_args)
   return result if m == :coerce
   case result
   when Integer
     MyInt.new(result)
   when Array
     result.collect do |element|
       element.kind_of?(Integer) ? MyInt.new(element) : element
     end
   else
     result
   end
 end
 
 def respond_to?(method)
   super or @value.respond_to? method
 end
 
 def to_int
   @value
 end
 def to_f
   Float(@value)
 end
 def to_s
   @value.to_s
 end
 def inspect
   to_s
 end

end


assert_raise(ArgumentError) { MyInt.new("foo") } # => invalid value 'foo', must be an integer assert_raise(ArgumentError) { MyInt.new(11) } # => invalid value '11', must be an integer

a = MyInt.new(7) b = MyInt.new(5)

c = 5 + a assert_kind_of(Fixnum, c) assert_equal(12, c)

c = a + 2 assert_kind_of(MyInt, c) assert_equal(9, c.to_int)

c = a + 2.8 assert_kind_of(Float, c) assert_equal(9.8, c)

c = a - b assert_kind_of(MyInt, c) assert_equal(2, c.to_int)

assert_raise(ArgumentError) { c = a + b } # => invalid value '12', must be an integer assert_raise(ArgumentError) { c = b - a } # => invalid value '-2', must be an integer</lang>

Tcl

Tcl does not attach types to values or variables, but it does allow the programmer to create traces on variables that can be used to enforce type-like constraints among other things. Traces are procedures that execute when variables are read, written and/or unset. (Traces are also available for commands and for the execution of a script.) Tcl's compiler does not enforce these constraints; they're strictly runtime entities. <lang tcl>namespace eval ::myIntType {

   variable value_cache
   array set value_cache {}
   variable type integer
   variable min 1
   variable max 10
   variable errMsg "cannot set %s to %s: must be a $type between $min and $max"

} proc ::myIntType::declare varname {

   set ns [namespace current]
   uplevel [list trace add variable $varname write ${ns}::write]
   uplevel [list trace add variable $varname unset ${ns}::unset_var]

} proc ::myIntType::unset_var {varname args} {

   variable value_cache
   unset value_cache($varname)

} proc ::myIntType::validate {value} {

   variable type
   variable min
   variable max
   expr {[string is $type -strict $value] && $min <= $value && $value <= $max}

} proc ::myIntType::write {varname args} {

   variable value_cache
   upvar $varname var
   set value $var
   if {[validate $value]} {
       set value_cache($varname) $value
   } else {
       if {[info exists value_cache($varname)]} {
           set var $value_cache($varname)
       }
       variable errMsg
       error [format $errMsg $varname $value]
   }

}</lang>

So, in an interactive tclsh we can see:

% myIntType::declare foo
% set foo ;# regular Tcl error:  foo is declared but still unset
can't read "foo": no such variable
% set foo bar
can't set "foo": cannot set foo to bar: must be a integer between 1 and 10
% set foo 3
3
% incr foo 10
can't set "foo": cannot set foo to 13: must be a integer between 1 and 10
% incr foo -10
can't set "foo": cannot set foo to -7: must be a integer between 1 and 10
% set foo 0
can't set "foo": cannot set foo to 0: must be a integer between 1 and 10
% set foo
3
% set foo [expr {$foo * 1.5}]
can't set "foo": cannot set foo to 4.5: must be a integer between 1 and 10
% set foo
3
% unset foo
% 

Toka

<lang toka>needs quotes {

 variable update
 [ update @ [ ! ] [ @ ] ifTrueFalse update off ] is action
 [ dup >r 0 11 r> within [ update on ] [ drop ." Out of bounds\n " ] ifTrueFalse ]
 [ ` [ invoke cell-size malloc # ` action compile ` ] invoke is ]

} is value:1-10:

 is to

value:1-10: foo 1 to foo foo .</lang>

Visual Basic .NET

Visual Basic has full support for creating your own primitives, but every operator has to be implemented explicitly. Often developers will only implement the parts they are using and skip the rest.

Also note that some operators return a Double instead of a new LimitedInt. This was by choice in order to match the behavior of Integers in VB.

<lang vbnet>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")
   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</lang>