Define a primitive data type: Difference between revisions
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> |
<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> |
<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> |
<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 |
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> |
|||
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 |
|||
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> |
<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'; |
|||
# 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}}== |
||
<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 . |
|||
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 |
<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 |
|||
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 Function |
|||
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 |
|||
Case 1 To 10 : Return New LimitedInt(temp) |
|||
Case Else : Throw New OverflowException |
|||
End Select |
|||
Case Else : Throw New OverflowException |
|||
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 |
|||
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 |
|||
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 |
|||
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 |
|||
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 |
|||
Case 1 To 10 : Return New LimitedInt(temp) |
|||
Case Else : Throw New OverflowException |
|||
End Select |
|||
Case Else : Throw New OverflowException |
|||
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 |
|||
Case 1 To 10 : Return New LimitedInt(temp) |
|||
Case Else : Throw New OverflowException |
|||
End Select |
|||
Case Else : Throw New OverflowException |
|||
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 |
|||
Case 1 To 10 : Return New LimitedInt(temp) |
|||
Case Else : Throw New OverflowException |
|||
End Select |
|||
Case Else : Throw New OverflowException |
|||
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 |
|||
Public Shared Operator <(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean |
|||
Return left.Value < right.Value |
|||
Case Else : Throw New OverflowException |
|||
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 |
|||
Public Shared Operator <=(ByVal left As LimitedInt, ByVal right As LimitedInt) As Boolean |
|||
Return left.Value <= right.Value |
|||
Case Else : Throw New OverflowException |
|||
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. --> |