LiamRyan
LiamRyan

Reputation: 1928

Is there a smart way to validate function input in Clojure?

I'm writing a simple DiceRoller application and I've created the primary function, however I'm wondering if there is a "smart" way to validate function inputs in Clojure rather than using branching conditionals to validate input? My function is below with a sample test, I would have to also test if n is not a number with another if or an or and it feels messy.

Also if anyone can point out a smarter way to do this function I would appreciate any feedback, this is my first attempt at trying to program functionally

(ns DiceRoller)

(defn roll
"rolls a specified number of n sided dice "
([] (roll 1 6))
([number] (roll number 6))
([number n]
  (if-not number? number (throw (IllegalArgumentException. (str "incorrect input, integers only"))))
  (take number (repeatedly #(+ (rand-int n) 1)))
  )
)

Upvotes: 10

Views: 2303

Answers (2)

Bozhidar Batsov
Bozhidar Batsov

Reputation: 56665

Sure there is - you can use a :pre assertion for that.

(defn some-fun [x]
  {:pre [(number? x)]}
  (foo x))

Now you'll get AssertionError Assert failed: (number? x) if you pass the function a non-numeric argument x.

Checking whether the input is a number is kind of useless as @amalloy already pointed out, but there are lots of totally valid precondition (and postcondition for that matter) checks that you might want to apply to your function. You can see some more details on the subject here and here.

Upvotes: 25

amalloy
amalloy

Reputation: 92117

Mostly the Clojure attitude is "just assume you got the right thing". In this case, if you took out your check entirely, the user would get basically the same exception eventually. But if you really wanted to do this, you should do it correctly! Right now your code throws an exception on every input, because you're missing parens around (number? number).

Upvotes: 7

Related Questions