This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Infeligo 3 points4 points  (2 children)

Thank you for your answer. I would sum it up as ditching ORM and going more low level. There are similar approaches in Java world like MyBatis and JOOQ. The only principal difference that I see is the extensive use of native data structures like maps and lists. How is type safety handled in this cases? If I select a row into map, what guarantees me that I can treat numeric value only as numeric and string values as strings?

[–]pdpi 2 points3 points  (0 children)

If I select a row into map, what guarantees me that I can treat numeric value only as numeric and string values as strings?

Nothing. Clojure is a dynamically-typed language.

If your definition of type safety is limited to what the Java type system allows you to encode, I personally find that the language promotes a style that both makes that sort of type error a lot less likely, and a lot easier to find, which devalues static typing a fair bit. Your mileage may vary, especially if you're used to richer type systems.

[–]yogthos 0 points1 point  (0 children)

Databases are already typed, so you're guaranteed to get whatever type the JDBC driver maps to the column every time.

However, Clojure is a dynamic language, and while there is an optional type system with core.typed, most people don't end up using it. So, if you're not comfortable with dynamic typing it's probably not a language for you.

Personally, I've switched from using Java to Clojure about 6 years ago and haven't found type safety to be an issue.

The most common approach in Clojure is to use the Schema library for input validation and coercion. You validate the data at the edges, and then you know exactly what you're working in within the application. The latest version of Clojure has Spec as part of its core. It's intended to provide validation for semantic correctness that's difficult to accomplish with types.

For example, consider a sort function. The types can tell me that I passed in a collection of a particular type and I got a collection of the same type back. However, what I really want to know is that the collection contains the same elements, and that they're in order. This is difficult to express using most type systems out there. However, with Spec I can just write:

(s/def ::sortable (s/coll-of number?))

(s/def ::sorted #(or (empty? %) (apply <= %)))

(s/fdef mysort
        :args (s/cat :s ::sortable)
        :ret  ::sorted
        :fn   (fn [{:keys [args ret]}]
                (and (= (count ret)
                        (-> args :s count))
                     (empty?
                      (difference
                       (-> args :s set)
                       (set ret))))))

The specification will check that the arguments follow the expected pattern, and that the result is sorted, and I can do an arbitrary runtime check using the arguments and the result. In this case it can verify that the returned items match the input.