I am currently playing around with ranges in my program, and my goal is to limit what a user can supply to a proc, either with a compiler error or an exception if at runtime. Currently the compiler error will happen, but if your error is at runtime you will get a RangeDefect, I'm not very well versed in the effects system so I started trying to annotate my proc with {.raises: [RangeDefect].}, this results in a XCannotRaiseY which I'm told is because Defects are fundamentally different from exceptions and cannot or should not be caught, however at least in nim 2.0 you can try except a RangeDefect.
My first instinctual thought was that conversion to a range, outside the range, should not be a Defect unless it truly is outside the range of the base type.
import std/strutils
type myRange = range[1'u8..128'u8]
proc foo(x: myRange) = discard
foo(129) # In my head should be a compile time error, which it is
foo(parseInt(readLine(stdin))) # if user enters 120 I expect no issue, if they enter from 129..255 I would expect an Exception and for greater than 255 a Defect
I'm just curious why my thinking does not line up with what actually happens, educate me.
The following program emits from the conversion a RangeDefect when the input isn't in the range, and from parseInt a ValueError when it's no a number at all:
import std/strutils
type myRange = range[1'u8..128'u8]
proc foo(x: myRange) = discard
foo(stdin.readLine.parseInt.myRange)
if they enter from 129..255 I would expect an Exception and for greater than 255 a Defect
What you're wanting is for the conversion to have different errors depending on whether the value is representable by the base type of the range, which is IMO a very strange thing to want, which requires the reader to keep in mind the base type of the range, which is not much emphasized by the feature. You have, however, some time between the parseInt and the conversion to the range:
proc weird(x: int): myRange =
when myRange.sizeof == 1:
if x notin 0..255: raise newException(RangeDefect, "value not in range")
else: assert(false, "do this some nicer way")
if x notin myRange.low.int .. myRange.high.int: raise newException(ValueError, "value not in range")
return x.myRange
foo(stdin.readLine.parseInt.weird)
How about this ?
import std/strutils
type myRange = range[1'u8..128'u8]
proc foo(x: myRange) =
echo("got : ",x)
#foo(129) # In my head should be a compile time error, which it is
let inp = parseInt(readLine(stdin))
proc checkMyRange(value: int):myRange =
if value<myRange.low.int() or value>myRange.high.int():
raise newException(ValueError,"Invalid value")
else:
return myRange(value)
foo(checkMyRange(inp)) # if user enters 120 I expect no issue, if they enter from 129..255 I would expect an Exception and for greater than 255 a Defect