Skip to content
This repository has been archived by the owner on Nov 14, 2017. It is now read-only.

Use function metadata to specify any Dire functionality you want to use #30

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

MatthewDarling
Copy link
Contributor

(this is currently a WIP, and only supports the features of Dire that I use personally, but I think it will be trivial to extend)

This allows the user to forget about all the with-X, remove-X functions and use a single function to either add or remove anything they want attached to the function.

Example usage

(defn ^{::preconditions '[precondition]
        ::handlers {::pre-handlers '[pre-handler]}
        ::eager-pre-hooks '[eager-pre-hook]
        ::wrap-hooks '[wrap-hook]}
  test-fn
  "Docstring"
  [a b]
  (/ a b))

(apply-dire-meta! test-fn)
(remove-dire! test-fn)

Rationale

I really like the separation of concerns that Dire enables, but as I was converting the project I work on to use Dire, I realized that I couldn't just add a precondition and forget about it entirely. In order to understand the possible return values of the function, I needed to look at what the handler would do with failure cases, and that made the code more difficult to reason about.

So I wanted a way to add metadata to functions in order to tell readers of the code that there was more going on besides what was visible in the current namespace.

The other issue I had was that, because I was using the mutating functions, loading the namespaces that used Dire would cause side effects, and that's not great. When I saw the example of using Dire with Component, I knew that was a better way of doing things, but I really didn't want to add/remove dozens of handlers and hooks manually.

Remaining issues

  • It doesn't actually seem to work :( When I run (meta (var test-fn)), I see both the metadata that I specified, as well as the appropriate :dire/preconditions style stuff. But running the function doesn't print out anything, in the way that it did in the mutation test file I was copying from.
  • Need to sort out the right metadata to use, in order to avoid conflicting with the metadata added by Dire itself.
  • Figure out if it's possible to write something similar for the non-mutating functions.

@MatthewDarling
Copy link
Contributor Author

Example of the fact that it doesn't work:

dire.metadata> (apply-dire-meta! #'test-fn)
({:dire.core/supervisor-hook-key #<core$partial$fn__4190 clojure.core$partial$fn__4190@44708681>})
dire.metadata> (clojure.pprint/pprint (meta (var test-fn)))
{:arglists ([a b]),
 :dire/eager-pre-hooks #{eager-pre-hook},
 :dire/preconditions {:pre precondition},
 :ns #<Namespace dire.metadata>,
 :name test-fn,
 :dire.metadata/handlers {:dire.metadata/pre-handlers [pre-handler]},
 :dire.metadata/wrap-hooks [wrap-hook],
 :column 1,
 :dire/error-handlers {{:precondition :pre} pre-handler},
 :dire.metadata/eager-pre-hooks [eager-pre-hook],
 :doc "Docstring",
 :dire.metadata/preconditions [precondition],
 :dire/wrap-hooks #{wrap-hook},
 :line 75,
 :file "/Users/matthewdarling/src/dire/src/dire/metadata.clj"}
nil
dire.metadata> (test-fn 10 2)
5

(also, apologies for the probable e-mail spam, I keep seeing issues that need to be fixed before anyone else can actually try this out)

@MichaelDrogalis
Copy link
Owner

This is a terrific idea! Thanks for contributing! I, too, wanted something along these lines. I never had time to chase it down though.

I don't have time to look at this today, but I'll try to diagnose what's happening in the next few days. I think this would be a massive step forward for Dire if we can pull it off, though. Maybe try Alex Miller in #clojure if you're totally stumped. He's a pro with the innards of Clojure. :)

@MichaelDrogalis
Copy link
Owner

@MichaelDrogalis (Tagging myself so I get email notifications, GitHub is pretty terrible about this)

@ghost
Copy link

ghost commented Aug 22, 2015

I wanted to do this as well and was disappointed when I found this on google and it wasn't working. I dived a bit deeper to see if I could figure it out myself, and it seems dire already does this? Or at least, does what I needed (and thought this was):

(require '[dire.core :as dire])
(defn ^{:dire/preconditions {:not-three (fn [x] (= x 3))}} increase [x] (inc x))
(increase 3)                            ;=> 4
(increase 2)                            ;=> 3
(dire/supervise #'increase 3)           ;=> 4
(dire/supervise #'increase 2)           ;=> ExceptionInfo throw+: {:type :dire.core/precondition, :precondition :not-three}
(dire/hook-supervisor-to-fn #'increase) ;=> {:dire.core/supervisor-hook-key #<core$partial$fn__4228 clojure.core$partial$fn__4228@72ad15e6>}
(increase 3)                            ;=> 4
(increase 2)                            ;=> ExceptionInfo throw+: {:type :dire.core/precondition, :precondition :not-three}  dire.core/eval1887/fn--1888 (core.clj:210)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants