Value restrtictions in function parameters

When I write a function I can declare the type of the parameters fibonacci(n : Int32), but can I further restrict it to, for example, only positive integers, or only even numbers? What is the recommended way for input validation for functions?

There is no such functionality. You just raise an exception in such a case.

https://crystal-lang.org/api/1.0.0/ArgumentError.html

Or… you can use macros!

Without the error…

macro fib(n)
  {% raise "fib expected n > 0, got #{n}" if n < 0 %}
  {% if n < 2 %}
    {{ n }}
  {% else %}
    {% prev, curr = 0, 1 %}
    {% (0...n-1).each { prev, curr = curr, curr + prev } %}
    {{ curr }}
  {% end %}
end

puts fib(1)
puts fib(10)

I can’t begin to imagine how dependent types would work in crystal, but they sure would be cool.

2 Likes

erlang guard?

fibonacci(n : Int32) where(i>0)
or
fibonacci(n : Int32) where(i.odd?)

1 Like

Nice, but I’d only do the check in macro code and compute normally at runtime.
fib(rand(10)) (or any non-constant value for that matter) doesn’t work if it’s all done in macro.
And I bet if the argument is constant the compiler will optimize the whole thing at compile time anyways.

Maybe something like GitHub - Groogy/crystal-clear: Design by Contract for Crystal could be useful for this? I really think this should use annotations, though.

2 Likes