# Non-negative integers

I want to do some things with non-negative integers and use it in function signatures. Is this idiomatic?

``````# Concrete subtypes should have a `val` attribute.
abstract type NonNegativeInteger <: Integer end

struct NonNegativeInt{T} <: NonNegativeInteger
val::T
end

Base.:+(x::T, y::T) where T <: NonNegativeInteger = T(x.val + y.val)
Base.:*(x::T, y::T) where T <: NonNegativeInteger = T(x.val * y.val)
Base.:^(x::T, y::T) where T <: NonNegativeInteger = T(x.val ^ y.val)

a = NonNegativeInt(2)
b = NonNegativeInt(3)
(a + b, a * b, a ^ b)
``````

Out of curiosity, why not using `UInt*` types?

I could probably use `SaferIntegers.UInt`. So maybe nonnegative real/rational/float would be a better example to ask the question with.

There isn’t such a type for floating-point numbers; you could define one, of course, but this is something that’s probably better done with a runtime argument check:

``````function f(x::Real)
x ≥ 0 || throw(DomainError("negative x=\$x not allowed"))
...
end
``````

Note that if `x` is an `Unsigned` type (like `UInt`, and also things like `Rational{UInt}`), the compiler will know that `x ≥ 0` is always `true` and optimize out the check.

1 Like

Is `>= 0` a special case, or can I somehow make my own compiler-optimized predicates?

`≥ 0` is not a special case, in the sense that the compiler (LLVM) does constant folding and dead-code elimination on any predicate that is inlined (any sufficiently short function). Whether this results in an elided check depends on what you are doing and the limits of LLVM.

1 Like