This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-10
Channels
- # beginners (61)
- # boot (264)
- # cider (125)
- # cljs-dev (3)
- # clojure (118)
- # clojure-gamedev (3)
- # clojure-greece (1)
- # clojure-italy (1)
- # clojure-nl (2)
- # clojure-poland (3)
- # clojure-russia (38)
- # clojure-spain (2)
- # clojure-spec (17)
- # clojure-taiwan (1)
- # clojure-uk (42)
- # clojurescript (118)
- # clojutre (5)
- # cursive (24)
- # datomic (22)
- # emacs (3)
- # events (2)
- # figwheel (19)
- # funcool (1)
- # jobs-discuss (224)
- # jobs-rus (1)
- # klipse (14)
- # luminus (1)
- # lumo (49)
- # off-topic (51)
- # om (34)
- # pedestal (1)
- # perun (1)
- # planck (93)
- # powderkeg (1)
- # re-frame (15)
- # ring (4)
- # rum (9)
- # slack-help (3)
- # spacemacs (2)
- # specter (13)
- # uncomplicate (1)
- # unrepl (22)
- # untangled (10)
- # yada (36)
specifically that I want to bind something in the macro, and then have that outputted as the arguments to the defn
but because of the way bindings work after compile time, I don't think that's a thing I can do right? because I can't like
so you want to create d
inside the macro, and for that d
to be used by the macro? are you intending that "test" become the name of the arg to the defn or? also that defn is missing a name, I don't know if that is on purpose
I'm not really sure what d should be doing here
basically the macro is to get rid of a bunch of boilerplate. every function that I am exposing in this SDK I'm writing has basically the same first 20 lines or so
so anyway, ignoring some gross code / probably me not doing this the most efficient way I can be
(defmacro def-sdk-fn [name spec topic body]
`(defn ~name
([& args#]
(let [args# (map iu/extract-params args#)
callback# (second args#)]
(if-let [error# (cond
(or (> (count args#) 2))
(do (js/console.log "args > 2")
(e/wrong-number-of-args-error))
(and (first args#)
(not (map? (first args#))))
(do (js/console.log "first arg not map")
(e/invalid-args-error))
(and (not (nil? callback#))
(not (fn? callback#)))
(do (js/console.log "cb isnt a fn")
(e/invalid-args-error))
:else false)]
(p/publish {:topics ~topic
:error error#})
(let [params# (first args#)
params# (assoc params# :callback (second args#))]
(if (not (s/valid? ~spec params#))
(do (js/console.info "Params object failed spec validation: " (s/explain-data ~spec params#))
(p/publish {:topics ~topic
:error (e/invalid-args-error)}))
~body)))))))
and how I'd like to use it is basically this:
(def-sdk-fn login
::login-spec
"cxengage/authentication/login-response"
(do (js/console.log "test" topic)
(p/publish {:topics topic
:response "aww yiss"})))
that's something that I'm both:
- passing to the macro itself (3rd argument after name and spec)
- wanting to be available as a binding to the ~body that they pass in
OK - this is called an anaphoric macro
they are well documented
clojure tends to discourage them, but they are possible by using a ' to prevent evaluation inside a ~ unquote
so you end up with ~'topic inside the code
also, the idomatic way to do a body for a macro is [... & body]
in the args and then ~@body
in the code, then you don't need the do
block in the input
for usage of topic in the body of the call to work, you might need something like [~'topic ~topic]
in the let block
right, like I said these are called anaphoric macros, if you google for "anaphoric macro clojure" you'll probably see a few good examples of using the ~'foo combo
oops 🙂
Would it be resonable to solve problems the “Bridge Design Pattern” using multimethods? It seems to me the goal is to have flexibility in extending our types and the functions that operate over those types.
Can a defrecord have two protocals it references?
@drewverlee Do you have an example? The text book shape-drawing-itself one doesn't seem like idiomatic clojure.
@yonatanel The goal here is educational, I both want to understand a bit about these patterns and see how they relate between java and clojure. The second goals is that several of my co-workers have experessed their inerested in FP, but aren’t sure how to apply their oop patterns to FP. I assume many of the patterns to be some form of missing language feature.
Best java example (i think at least) was from this: http://www.journaldev.com/1491/bridge-design-pattern-java
Frankly in this kind of discussion you'll have to show them how to solve real problems, because in clojure you'll just have {:shape :circle, :color :red}
and any number of functions that can draw them with different implementations.
I agree. It helped a lot of have someone else echo my thoughts. An actual problem would probably be better, but also more time consuming and harder to understand, ill see what i can come up with 🙂
@drewverlee I'm interested if you're trying to convince everyone to switch to clojure at the workplace or if you're just talking about it, and how it goes :)
@drewverlee here is a link to one way to tackle the problem Bridge pattern is trying to solve using Clojure http://mishadoff.com/blog/clojure-design-patterns/#bridge This example uses multi methods as you suggest but also introduces hierarchy in the keywords to dispatch on (i.e. keywords can derive
from other keywords). Lots of other interesting patterns in the link BTW
Thanks agile geek, i have worked though some of those. I really like it, but I wanted to create something more technically in depth
@drewverlee I think that Bridge pattern example shows the fundamental difference between OOP and FP in it's approach. In the FP version only the data has a hierarchy. I.e. data can inherit but behaviour cannot. You can dispatch to different implementations of behaviour based on data. It's the clean separation of data and behaviour that makes it powerful. I don't know how often in OOP I've made the point that you should not inherit only for behaviour but delegate. It's great to have a language that reinforces that concept.
Very well put. That's a great way of comparing the two styles.
Hi. Is there any way to "alias" a classname? trying to do something like this:
(def assertion-error
#?(:clj java.lang.AssertionError :cljs js/Error))
;...
(is (thrown? assertion-error (assert nil)))
Works in cljs, but clj complains about being "Unable to resolve classname: assertion-error"since is
is a macro, you might need to write a macro for this
(or rewrite is to evaluate the first arg to a thrown? clause)
iirc is uses a multimethod, and one of the method dispatches hard-codes the path for thrown?
yes, you are correct regarding use of a multimethod (which is exactly the same in clj and cljs, btw)
so you could just use defmethod to override that multi... monkey-patch style - this may be a bad idea though
oh yeah - and extend it yourself - that's much more sensible
I recently had a related problem (which is why I know about is using a multimethod etc. etc.) it turns out that futures capture Exceptions and you can try/catch around the deref, but AssertionErrors don't behave as nicely / testably. I basically just gave up on using AssertionErrors so that the code would be testable.
well, no AssertionErrors in cljs either...