# Setting boundaries for integer function parameters

Is it possible to set a function parameter so that an integer number entered is within a certain range i.e. between zero and fifteen. Much like making the parameter type safe, only a step further so that it has an upper limit ?

This sounds like an ideal use for an integer based enum.

One cannot do this trivially when accepting `Int`. This is because the problem youâ€™re expressing (â€śmust be within the range of zero and fifteenâ€ť) is currently expressed in the value domain, not the type domain.

You can transform this by forcing the transformation of the `Int` into a different type that does provide that constraint. @Joanna_Carter has suggested one alternative, but here is mine:

``````struct ZeroToFifteenInt: RawRepresentable, ExpressibleByIntegerLiteral {
var rawValue: Int {
didSet {
precondition((0...15).contains(newValue))
}
}

init(rawValue: Int) {
precondition((0...15).contains(rawValue))
self.rawValue = rawValue
}

init(integerLiteral: Int) {
self = .init(rawValue: integerLiteral)
}
}
``````
2 Likes

Unfortunately, this can fail at runtime.

Here is the enum idea, which is safe :

``````enum ZeroToFifteen: Int
{
case zero = 0
case one
case two
case three
case four
case five
case six
case seven
case eight
case nine
case ten
case eleven
case twelve
case thirteen
case fourteen
case fifteen
}

func testZeroToFifteen(value: ZeroToFifteen)
{
let intValue = value.rawValue

// â€¦
}

{
testFifteen(value: .seven)
}
``````

It can fail at runtime because I wrote it that way, but the same is true in general if you have to transform between `Int` and your other type. It is not possible to transform an `Int` into another type without dealing with the situation where the `Int` is out of range.

Mine can't fail at runtime if you check for the result of the failable initialiser.

``````    if let test = ZeroToFifteen(rawValue: 16)
{
print(test) // never gets executed
}
``````

Thatâ€™s just choosing the type of failure you prefer. You are using a faisable initializer, which by definition can fail.

@glessard is right. Transforming my version to yours is trivial: replace the `preconditionFailure` with an `init?` and all is well again. The two approaches are not meaningfully different in what they can express (though they are different in their runtime layout).

This is the key, and why Iâ€™d rather go for your version personally (with an appropriate failure mode for the context where it will be used).

One approach (the wrapper struct) is an `Int` that has been validated to be within a specific range; the other is an enum which is representable as an `Int`. Itâ€™s a subtle difference, but Iâ€™d guess that the former is friendlier for the optimiser.