Type hints in Clojure have a different purpose to those in Python. In Clojure, type hints are only a mechanism to avoid reflection; their use is solely to improve performance.
So the question "Can I use spec as a type hint?" is actually asking "Will the compiler use specs to avoid reflection?", to which the answer is no. However Spec, and other equivalent libraries, can be used for runtime type checking in Clojure. Where you'd use a dataclass in Python, you'd generally use a map in Clojure. This requires a little explanation because of the different ways Clojure and Python support data modelling. Suppose Python you have a dataclass: @dataclass class InventoryItem: name: str unit_price: float quantity_on_hand: int = 0 def total_cost(self) -> float: return self.unit_price * self.quantity_on_hand Then the *minimal* equivalent Clojure code is simply: (defn total-cost [{:keys [unit-price quantity-on-hand]}] (* unit-price quantity-on-hand)) The Clojure example lacks explicit type checking, but that may not be necessary. In Clojure, we can incrementally add more specific checks as necessary. For example, we could add a precondition to check the inputs: (defn total-cost [{:keys [unit-price quantity-on-hand]}] {:pre [(float? unit-price) (int? quantity-on-hand)]} (* unit-price quantity-on-hand)) Clojure spec allows checks to be taken further, with the caveat that keywords must be namespaced. Spec is more granular than classes, as it's interested in single key/value pairs, rather than grouped properties as in a class or struct. With spec, we might declare: (s/def :inventory.item/name string?) (s/def :inventory.item/unit-price float?) (s/def :inventory.item/quantity-on-hand int?) (defn total-cost [{:inventory.item/keys [unit-price quantity-on-hand]}] (* unit-price quantity-on-hand)) This doesn't automatically perform type checks, as they may not be necessary. We can add type checks to a function with *clojure.spec.test.alpha/instrument*, or add them as a precondition using *clojure.spec.alpha/valid?*. The validation required depends on the origin of the data. Suppose the inventory item comes from a database with its own schema. In which case, we may be reasonably certain that the types are correct and there's no need for additional confirmation. Or suppose instead that we read the inventory item from an external source we may not trust. In that case, we'd want to validate it as input, and reject it if the data is invalid. But after we've validated it, we can pass it around internally without further checks. Perhaps we're worried instead about human error. In this case, we might turn on checking during development and testing, but remove it during production when we're more interested in performance. This is the broad use-case for Spec's *instrument* function. Clojure's takes a more nuanced, and possibly unique approach to data, compared to other languages. Understanding how Clojure views data is understanding Clojure as a language. On Fri, 21 Jan 2022, at 3:22 AM, Kovas Palunas wrote: > Hi all, > > Coming from python, I use dataclasses > <https://docs.python.org/3/library/dataclasses.html> a lot to tie complex > collections of data together. I like using them in combination with type > hints so that it's clearer to me at a glance what kind of data a function is > processing. When my data starts to look like a dict of dicts of lists, I > turn to dataclasses to help my simplify. > > So far in my Clojure journey, I've stumbled across two features that could > help me do something similar. First are datatypes > <https://clojure.org/reference/datatypes> (deftype, defrecord), and second is > using maps with spec <https://clojure.org/guides/spec>. Based on my reading, > using spec to define types seems like a really flexible system that does > built in testing for me. I was surprised to read that specs can't quite be > treated like types though: > https://ask.clojure.org/index.php/10464/can-i-use-spec-as-type-hint. Maybe > the intention is to use the :pre and :post keys in a function's options as > type hints? > > I'm curious if I'm thinking along the right lines here, or if there are other > language features I could be looking at. Also curious if anyone has > suggestions for books or articles that explore data typing options in Clojure. > > Thanks, > > - Kovas > > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/clojure/a5718e8b-71a6-40d5-b1da-ca2cdb10a71en%40googlegroups.com > > <https://groups.google.com/d/msgid/clojure/a5718e8b-71a6-40d5-b1da-ca2cdb10a71en%40googlegroups.com?utm_medium=email&utm_source=footer>. -- James Reeves booleanknot.com -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/da5de1bf-a466-4b78-898a-84d9b6217a53%40www.fastmail.com.