5 ms·
I add :pre and :post assertions to most of my functions, so I know the type of everything coming in, and also what is returned. An example of a function that sa
by lkrubner 13y ago
I add :pre and :post assertions to most of my functions, so I know the type of everything coming in, and also what is returned. An example of a function that saves a document to MongoDB:
(defn persist-this-item [item]
{:pre [
(map? item)
(= (type (:item-name item)) java.lang.String)
(= (type (:item-type item)) java.lang.String)
(if (:created-at item)
(= (type (:created-at item))
org.joda.time.DateTime)
true)
]}
(let [item (if (nil? (:created-at item))
(assoc item :created-at (tyme/current-time-as-datetime))
item)
item (assoc item :updated-at (tyme/current-time-as-datetime))
item (assoc item :_id (ObjectId.))]
(mc/insert "tma" item)))
So this function needs to be given some kind of map, and it needs to have 2 keys, :item-name and :item-type, and both of these need to be strings, and if :created-at is already set, then it needs to be a Joda DateTime.
It's not accurate to say that Clojure has no types. It just gives you some flexibility about how strict you want to be.
I find that Clojure strikes a perfect balance: its flexibility with types allows me to easily integrate a lot of 3rd party tools without much work, but when I need to I can be as strict as a I like with types.
Edit to add: wow, the code is ugly on Hacker News. Funny that this site provides no tools for posting code snippets, given the subject.
- deleted 13y ago[deleted]
- thinkpad20 13y agoMaybe I'm misunderstanding, but it looks like every time these functions get called, they're type checking their inputs and outputs? That seems like a waste of resources. Why not just write unit tests that ensure that they will always be called with the types you expect (or fail at an earlier step if not)? Identify the places where there might be ambiguity in something's type (e.g. when a JSON blob arrives, it might map a key to a list instead of a dictionary, or if a function might return multiple types, etc), and use unit testing to ensure that the type you expect will emerge from those places, or else a failure will occur.
- Tobani 13y agoI believe :pre and :post conditions only get run when assertions are enabled. There are other languages that have this feature (Eiffel touts it pretty heavily), but I haven't seen the AHA! example where this is the long lost feature I've been missing. But that said, :pre/:post w/ unit tests seems pretty powerful. You can assign the invariants to the functions themselves and have a better / more robust set of assertions in your unit tests.
- thinkpad20 13y agoIf it only will get run in some sort of testing mode, that's fine I suppose. Although the other drawback to this sort of thing is that it seems to really decrease readability. Most of the time when you're reading code, you just want to see what's actually happening, and having a big messy set of type assertions would be noise 90% of the time (especially because unlike type signatures in Haskell, say, there's no syntactical difference that would allow syntax highlighters to help you visually see what's actual code and what's type assertions).
- Tobani 13y agoSo I wouldn't confuse invariants w/ type assertions. Clojure does have separate type assert/checking in core.typed. Yes one thing you might use :pre/:post for is type checking, but it can do more than just that.
- thinkpad20 13y agoRight, but unit tests do that too. And that would still be something I would in most cases rather handle in unit tests than in assertions in the code itself, for mostly the same reasons.
- rapala 13y agoHow do you write a unit test that tries to assert that no one calls the function sqrt with a negative integer? Because that is precisely the case where pre-conditions can help.
- vasquez 13y agoI like Clojure, but this looks rather painful. If you're dead set on adding type declarations, perhaps you'd be better off with Haskell or something?
- MrBuddyCasino 13y agoI agree, this looks terrible. It seems every discussion about static vs. dynamic typing on HN ends with the following realizations, spread over multiple comments: - its hard to safely refacture without static types (and the help of the IDE that often comes with it) - dynamic languages must compensate the missing type checking support from the compiler with additional unit tests, negating the productivity gains Sometimes it would be nice to have both worlds in the same language, but the way Clojure does it does't appeal to me at all.
- Mikera 13y agoI'm actually trying to address this in my current language experiment: https://github.com/mikera/kiss https://github.com/mikera/kiss The idea: add static types to Clojure without compromising on the dynamism / flexibility / convenience
- sampo 13y ago> "Funny that this site provides no tools for posting code snippets" Indent code by at least 4 spaces. (Just like in Markdown in e.g. Stack Overflow.) like this and indent some more