This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-01-08
Channels
- # aleph (1)
- # architecture (4)
- # aws (5)
- # beginners (105)
- # boot (1)
- # boot-dev (72)
- # cider (5)
- # clara (15)
- # cljs-dev (51)
- # cljsrn (5)
- # clojure (155)
- # clojure-austin (3)
- # clojure-dusseldorf (2)
- # clojure-finland (1)
- # clojure-greece (37)
- # clojure-italy (17)
- # clojure-nl (1)
- # clojure-russia (6)
- # clojure-spec (23)
- # clojure-uk (6)
- # clojurescript (7)
- # community-development (1)
- # css (10)
- # cursive (15)
- # datomic (45)
- # defnpodcast (1)
- # duct (97)
- # emacs (5)
- # fulcro (46)
- # hoplon (8)
- # instaparse (25)
- # keechma (11)
- # leiningen (16)
- # off-topic (2)
- # onyx (9)
- # planck (2)
- # re-frame (5)
- # reagent (3)
- # reitit (2)
- # ring (6)
- # shadow-cljs (35)
- # spacemacs (9)
- # specter (9)
- # sql (18)
- # uncomplicate (4)
bronsa mentioned in his decompiler talk from baltimore that he wrote a backend for core.match that didn't use exception based backtracking. I'm not seeing that on github. was that patch accepted?
I don’t think it got looked at before 1.9
and he wasn't kidding about the steps in decompilation. this is basically right from a slide in the talk
(defn class->source [classfile-or-classname bc-for]
(-> classfile-or-classname
(bc/analyze-class)
(ast/bc->ast {:bc-for bc-for})
(sa/ast->sugared-ast)
(src/ast->clj)
(cmp/macrocompact)
(pp/pprint)))
oh, I’m thinking of something different. I’m not sure that backend was ever submitted to core.match
well @bronsa is on here, you should just ask him :)
i don't like pinging people when they aren't active at the moment. really should have been off topic. just a great talk
is it possible to "monkey patch" a symbol in clojure? So that whenever someone calls clojure.tools.logging/info
for example, it calls my function instead? When responding, bear the following 2 things in mind:
1) hook does not work on macros, which is the reason I'm asking
2) Yes, I know this is ugly, and shameful. I'm doing this for my company, we've got a deadline. I'll do it right when I have time to sleep, which is when I'm dead.
the only way to replace a macro is before the code that used the macro is compiled
if hook can't do that to a macro, then you can replace the macro yourself, but either way it won't work unless you also recompile all the code using the macro
the easy choice here is to fork clojure.tools.logging, give it your own group id, and use that instead of the original
it's less complex than the other options
slightly trickier, you can edit the code of clojrue.tools.logging and deploy to your local cache
that way you avoid some dep management complexity in making suer everyone uses your version
putting it in your local cache is a question of running lien install
- that's it, that's all it takes
OK, so you can't use something you jarred locally
well, using your own version of tools.logging is just a question of adding some exclusions to your deps and then deploying / depending on your version
no, you don't need that
all you need is to change the dep in your project file
your fork of tools.logging would define all the same namespaces
or, the other route is to use the normal dep, and have a namespace the does the following: switch to the core.logging namespace, redefine the macro, cause all other namespaces to be reloaded from source
(doseq [name-space (keys (all-ns))] (require name-space :reload))
if that doesn't suffice you can look at what clojure.tools.namespace does
you would have to fix that to exclude the logging ns you are replacing of course, heh
but given those ingredients,the rest is just an exercise
the downside is everything gets compiled twice in order to make sure your replacement macro is working
which means startup is slower
probably can't help with the problem but can you describe the issue that you're running into?
whole codebase currently uses clojure.tools.logging
. clojure.tools.logging
is a chain of macros that cant be hooked. By the time I can hook, all the logging arguments have just been concatenated into a big unstructured string.
I would have to regex it apart to figure out what the data map is and what the message is, parse it back into an edn map, then dump it into a json string.
if I could just hook it at the very beginning, I could cheshire that stuff into place before all the damage was done.
So @noisesmith was helping me figure out how to "hook a macro"
The logging implementation can be explicitly provided by using
binding or alter-var-root to change the value of *logger-factory* to
another implementation of clojure.tools.logging.impl/LoggerFactory
can you make your own with cheshire serializing the edn?well, the logger factory that I implemented would still be passed an unstructured string that typically looks something like this:
"A thing happened!: {:some \"info\"}"
assuming the function was called as:
(clojure.tools.logging/info "A thing happened!:" {:some "info"})
Id have to run some weird regexes to split the data from the message, parse the data into memory from the string, assoc in the message as a keyval, then dump it to json using cheshire
honestly its just madness to me that it was implemented the way it was. clojure.tools.logging
, that is. There must be some kind of crazy performance benefit to using macros over functions that I'm unaware of.
oof. yeah i'm seeing that. it looks like its made for logging unstructured data since it's just calling print-str on the two args
you could perhaps make your own info
macro that calls the logger in a slightly different way
https://github.com/clojure/tools.logging/blob/master/src/main/clojure/clojure/tools/logging.clj#L94 if this branch was taken you would be in the clear
(log* logger# ~level x# (print-str [email protected]))
would do it for you. the branch taken when its a throwable
but it has to be a macro so it doesn't eval args when the level is lower than the logging theshold. or require everything to be wrapped in a thunk
ahhhh, is that why? whoa. I had no idea that optimization was even in place.
so I could do a (logging/debug "hello" :wait (Thread/sleep (* 100000 100000 100000)))
and nothing would happen if my log level was set to error?
we bult a logger in C# at my last job that would collapse a bunch of contexts to give a snapshot of the world at a logging call. expensive if thrown away all the time
think
using (new LoggingContext(a = 3, b = 4)
using (new LoggingContext(c = 5 )
Log("blah blah");
would include the variables you declared to push into the "pancake" we called itvery useful to give extra context to an error. it would put invoice number, customer number, rule, etc when there was an error. it was a stack trace and a snapshot of important things
yeah.. thats a fascinating use case for macros. well, I mean I guess short-circuiting is like the oldest macro use in the book
preventing the evaluation of arguments completely. I mean I guess yeah of course that's a thing...
(defmacro info [level x & more] (logp ~level nil (assoc (first more) :message ~x))
might work for you
(defn foo
"I don't do a whole lot."
[x]
(log/info :info "hi" {:stuff 4})
(hijacked/info :info "hi" {:stuff 6})
(println x "Hello, World!"))
yields
(foo 4)
Jan 07, 2018 10:38:14 PM clojure.tools.logging$eval429$fn__432 invoke
INFO: :info hi {:stuff 4}
Jan 07, 2018 10:38:14 PM clojure.tools.logging$eval429$fn__432 invoke
INFO: {:stuff 6, :message hi}
4 Hello, World!
nil
(ns fact.logging
(:require [clojure.tools.logging :as log]))
(defmacro info [level x & more]
`(log/logp ~level "" (assoc [email protected] :message ~x)))
@tjtoltonyeah, gotcha. Trick is, of course, that I'd have to drop that as the first line of every namespace that uses logging forever after amen. And I also have to rely on the argument being a map. If it is, in fact, an unevaluated function or something (similar to the use case you described), then it's gonna break.
you were saying you could turn it into json. so i assumed there was some kind of convention
yeah, there's probably some loose use of convention. Im sure that at least half of the uses are passing in individual keyvals too, rather than the whole map
@dpsutton glad you liked the talk :) re: the core.match frontend, ATM it’s just defined for tools.decompiler, the reason why I’m not making a patch for core.match is twofold: - that new frontend is only defined for the subset of core.match that tools.decompiler uses, it could be made general but I haven’t had time to do so yet - for “normal” match statements, the current frontend clearly wins — it’s only for very complex, wide and nersted match statements that the one tools.decompiler uses starts being faster
Is the talk online? If so, could you post the link? I couldn't find it after a couple of searches.
Got an interesting issue I was wondering if anyone in the community might be able to help me with. I'm trying to use clojure.jdbc to call a custom function in H2 with a user-defined variable. It doesn't work. Here's the code:
(for [q ["CALL ECHO('1')" ;Works
["CALL ECHO(?1)" "2" ] ;Works
"CALL ECHO(@X)"]] ;Fails
(let [db-spec {:classname "org.h2.Driver" :subprotocol "h2:mem" :subname "demo;" :user "sa" :password ""}
alias "CREATE ALIAS ECHO AS $$ String echo (String s) { return s; } $$"
;Need to keep a local connection handle due to how I spec the db.
c (j/get-connection db-spec)]
(try
;Create a local user variable
(j/db-do-commands db-spec [alias "SET @X='3'"])
;Call my custom function. Note that using the user variable fails. Why?
(j/query db-spec q)
(catch Throwable t {:error {:message (.getMessage t)}})
(finally (.close c)))))
Result:
=> (({:public.echo('1') "1"}) ({:public.echo(?1) "2"}) ({:public.echo(@x) nil}))
Any ideas why? TIA!is this a new 1.9 feature? (let [{:a/keys [b c]} {:a/b 1 :a/b 2}] ....
being able to prefix ;keys
with the all of the keys will have?
Is there something like Project Euler but focused on learning Clojure syntax, code functions and core language? I love P.E. feature of comparing my solution with the top 10 Clojurians however I spend too much time with mathemstics and thus too little eith the lang. Thanks!
(resolve (symbol "+"))
returns #'clojure.core/+
, but (resolve (symbol "System/currentTimeMillis"))
returns nil
. is it possible to parse java functions like this from a string?
along with the other issues mentioned, a java method is not first class, while clojure functions are (clojure functions are objects with invoke methods which is why they are first class)
user=> (macroexpand '(System/currentTimeMillis))
(. System currentTimeMillis)
user=>
didnt know that the /
is basically a macro. interesting
thanks
That's news to me, thanks for sharing!
i'm stumped regarding a problem involving multimethods. i have ProjectA with a defined multimethod and ProjectB which extends the multimethod from ProjectA. ProjectA requires ProjectB thus adding extra functionality to ProjectA. how can i go about developing and compiling ProjectB when its defmethods refer to the defmulti in ProjectA? to avoid the circular dependency i could create a third project with just the multimethod, but that seems a little crazy.
basically your definition of an interface (defmulti) should not depend on an implementation of that interface (defmethod)
maven, if I recall, is perfectly fine with circular dependencies between artifacts if I recall
I dunno, I just avoid having the definition of an interface depend on an implementation of that interface
hmm okay, i'll internalise that and see where i end up. thanks for your input, @hiredman
java is fine with circular dependencies (fine as in "compiles" not as in "good idea") so it makes sense for maven to be as well I suppose. I'm glad it produces a warning
clojure has a circular artifact dependency now, spec.alpha depends on clojure and clojure depends on spec.alpha
hi clojurians, can you recomend a library/framework with low overhead to implement a very simple REST api? I've been looking into luminus, pedestal and immutant but I would love to hear about your experiences.
@h.elmougy looks good! have you used it?
@spacepluk This might be helpful. https://www.reddit.com/r/Clojure/comments/6kuvev/best_frameworktool_set_for_writing_rest_api_in/
I've used liberator many times over the years with success. I'd be interested in knowing whether Liberator and Duct could play nicely.
it’s very full-featured, and helps you stick to proper http/rest according to the spec
Just used https://github.com/metosin/compojure-api which is very simple, easy to use and gets you up and running instantly with swaggerized APIs. Just “lein new compojure-api myapi”
Anyone accessed the OS X Keychain to grab usernames/passwords from Clojure or the JVM? There is a old java repo out there that wraps the Keychain
@ghadi, I have, but I use jna since I’m already using that for other things
@mikera: does core.matrix support strides for gemm ? I have an input matrix that 'self overlaps'
Hi all: curious if anyone has ever tried to use strings with clojure's adhoc hierarchies. As far as I know, you can only use types that implement clojure.lang.Named
with clojure's adhoc hierarchies, and I don't think you can extend java.lang.String
since clojure.lang.Named
is not a protocol, but an interface. So, is there no way to use strings with Clojure adhoc hierarchies? Something like (derive h "child" "parent")
?
No, most people use keywords for hierarchies
00 ;;=> 0
01 ;; => 1
07 ;; => 7
08 ;; clojure.lang.LispReader$ReaderException: java.lang.NumberFormatException: Invalid number: 08
¯\_(ツ)_/¯
numbers starting with 0 are octals, of which only 0-7 are valid values
numbers exist irrespective of what base they are displayed in
@alexmiller Is there a way to add e.g. Artifactory as a repo for deps.edn
? It’s not clear which repositories what :mvn/version
accesses. I assume at least Maven and Clojars
Oh, I see the stuff about procurers now: https://clojure.org/reference/deps_and_cli#_procurers
@U2J7JRTDX if you need auth, then follow https://dev.clojure.org/jira/browse/TDEPS-9
Yeah, you can add repos in a :mvn/repos key
See ~/.clojure/deps.edn
There’s an example there