This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-14
Channels
- # arachne (5)
- # architecture (2)
- # bangalore-clj (7)
- # beginners (96)
- # boot (34)
- # braveandtrue (1)
- # cider (12)
- # cljs-dev (38)
- # cljsrn (59)
- # clojure (326)
- # clojure-dev (35)
- # clojure-greece (1)
- # clojure-italy (6)
- # clojure-russia (47)
- # clojure-spec (16)
- # clojure-uk (25)
- # clojurescript (136)
- # core-async (18)
- # cursive (18)
- # datascript (2)
- # datomic (28)
- # dirac (6)
- # emacs (4)
- # garden (3)
- # hoplon (28)
- # instaparse (1)
- # jobs (4)
- # juxt (1)
- # lein-figwheel (10)
- # liberator (1)
- # mount (3)
- # off-topic (39)
- # om (16)
- # om-next (1)
- # onyx (15)
- # pedestal (9)
- # proton (1)
- # random (1)
- # re-frame (48)
- # reagent (8)
- # ring-swagger (4)
- # rum (3)
- # specter (5)
- # sql (3)
- # unrepl (273)
- # untangled (27)
- # vim (4)
- # yada (7)
So, with socket server I could examine internal state of a running clojure server in production?
if I have a macro that creates bunch of def
s, something like:
(defmacro multidef
[table-names]
`(do ~@(for [t table-names]
`(def ~(symbol t) (str ”def-” t)))))
if used: (multidef [”foo” “bar”)
it will create my-ns/foo
and my-ns/bar
and now I also want them to be in a vector where each element of is reference to defs, e.g. (def tables [foo bar])
how do I do that?You can do that, but an alternative, which knowing nothing about your macro, I think would be superior, would be to get your macro out of the def
business altogether. Have your macro expand to a vector, def the result if you must
If you expand to vector, you can bind that vector to any name you like, in whatever scope
If you bake in global name definition in your macro, it can only be used to create global names
ok, let me dig from the other side: let’s say I have bunch of defs in the namespace, eg: (def a 1)
(def b 2)
(def c 3)
… how do I “collect” all into one vector?
Anyway, whatever system you are creating, I encourage consideration of objects bound to local names, or objects not bound to a name at all
Also, if I read your code I now need to understand what a multidef is. So that's more work on the part of the reader, for the gain of a bit less typing on your part. Often it's better to structure code for the ease of use of the people that come after you as we tend to read code much more often than we write it.
(also true of all macros, not just ones that def something)
TL;DR: use macros very sparingly 🙂
Spec might be a good case study, it has more macros than I would like, but it at least distinguishes spec construction from binding to a name
Logging question: I have a logback.xml with specific appender that I want to enable in production only. Is there any way around using conditionals in the xml file? Some one-liner to enable a named appender or something?
I figured out a way to get the appender via Interop now just need to find the on-off switch 😄
ha, .start
& .stop
@mpenet thanks for the pointer but I think I’ll stick to these for now, Java logging is a bit overwhelming...
Ended up trying unilog anyways but I needed a custom Syslog appender (Papertrail) and that seemed a bit more involved @mpenet
pretty nice otherwise 👍
@martinklepsch i get away with java logging by just dumping to stdout and stderr. it is the environment responsibility to process that however you would like
@martinklepsch FWIW I have a srv/dev/log4j.properties
and src/production/log4j.properties
where only src/production
is included in the uberjar
but never in dev
Is there a built-in fn (or alternative) to do this more concisely? (reduce #(%2 %1) {} fns)
@martinklepsch In the XML you may want to wrap the appender definition with
<if condition=‘p(”logback.appender.syslog.enabled”).equalsIgnoreCase(”true")'><then>
…appender-config-here...
</then></if>
but you need a system property logback.appender.syslog.enabled
defined to make it work
@kumarshantanu I looked into that but then I needed another depenency for it and also XML CONDITIONALS? 😄
Yes, I think you need Janino. See: https://github.com/kumarshantanu/logback-bundle/blob/master/core-bundle/project.clj#L6-L8
The XML config is well documented and searchable, but it’s weirdly evolved 😬
@martinklepsch have you considered using a boot task with edn and stencil to gen xml config files? works great for boot-gae.
@martinklepsch I created this a while ago: https://gist.github.com/rauhs/129a1fbca375ef8972902161e594bc39 , maybe it'll help you. It's nothing fancy.
@mobileink this project doesn’t use boot unfortunately so I wanted to avoid any build-time-solutions for now. That’s probably what I’ll go for later though.
@rauh looks pretty similar to unilog 🙂
@kumarshantanu Do you have an example of what you use (reduce #(%2 %1) {} fns)
for?
@curlyfry I am trying roll an init-map (empty in the beginning) through a bunch of initializer fns
@kumarshantanu - If you know the fns at code-writing time, you can use ->
. Otherwise, not sure how I'd improve that.
@hiredman - Wouldn't the order of application be different with comp
?
Might still work, if the order of application doesn't matter.
@hiredman - true.
So to summarize: ((-> fns reverse comp) {})
.
Right, good catch.
Try 2: ((->> fns reverse (apply comp)) {})
. I think it just got longer than the original. :-)
as a bonus, it’s also harder to understand
@alexmiller - Agreed. For the sake of legibility I might say:
(letfn [(step [m f] (f m))]
(reduce step {} fns))
no need for thread macro @jeff.terrell .. ((apply comp (reverse fns)) {})
... but i think the original reduce
is also easier to understand as @alexmiller said
Yeah…I tend not to use comp
very often because I always have to stop and think about the order of application, so to me, the reduce
is clearer. But then, I also had to stop and think about the order of application to the reducing function (and even initially got it wrong in my "legible" snippet above), so I guess YMMV.
I like the step version
seems like there has to be an iterate
version of this too?
I guess not as the function changes
you have to combine the list of functions and the seed value, and iterate taking a function and applying it to the seed value, then returning a new combination of the rest of the functions and the new seed value
@hiredman iterate requires that f must be free of side effects, so shouldn’t be stateful
this is actually the same idea as that one transducer ticket
@alexmiller when spec is finalized, will it be a package that must be imported in a project.clj file (think core.match) or will it just be referenced similar to clojure.string or set?
@dpsutton not yet determined
it will be a required part of Clojure in either case
either it will be in core or core will depend on it
separating it would allow spec to rev faster than core and that would be the reason to separate
so we won't need to version it? ie cider-nrepl has spec 0.2 and your project has spec 0.4
we do not intend to make it independent or backport it
user=>
(take-while :value
(iterate
(fn [{:keys [fns value]}]
(when (seq fns)
{:fns (rest fns) :value ((first fns) value)}))
{:fns [inc inc inc] :value 0}))
({:fns [#object[clojure.core$inc 0x4df5bcb4 "clojure.core$inc@4df5bcb4"] #object[clojure.core$inc 0x4df5bcb4 "clojure.core$inc@4df5bcb4"] #object[clojure.core$inc 0x4df5bcb4 "clojure.core$inc@4df5bcb4"]], :value 0} {:fns (#object[clojure.core$inc 0x4df5bcb4 "clojure.core$inc@4df5bcb4"] #object[clojure.core$inc 0x4df5bcb4 "clojure.core$inc@4df5bcb4"]), :value 1} {:fns (#object[clojure.core$inc 0x4df5bcb4 "clojure.core$inc@4df5bcb4"]), :value 2} {:fns (), :value 3})
user=>
so this reminds me of http://dev.clojure.org/jira/browse/CLJ-1906
I think there is some missing thing in this area, but I have not sorted through all the stuff on that page enough to have an opinion on it
(defprotocol SetA (seta [x a]))
=> SetA
(defrecord X [a]
SetA
(seta [this newa] (set! (.a this) newa)))
=> user.X
(def x (->X 0))
=> #'user/x
x
=> #user.X{:a 0}
(seta x 1)
=> 1
x
=> #user.X{:a 1}
The best I can guess is that "final" is only a compile-time concept in java and does not exist in the jvm?
I echo bronsa’s surprise
unless record fields aren’t marked final!?
@alexmiller I verified via reflection, they are
well that’s good
public final java.lang.Object a;
descriptor: Ljava/lang/Object;
flags: ACC_PUBLIC, ACC_FINAL
public java.lang.Object seta(java.lang.Object);
descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: checkcast #2 // class test/X
4: aload_1
5: aconst_null
6: astore_1
7: dup_x1
8: putfield #18 // Field a:Ljava/lang/Object;
11: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Ltest/X;
0 11 1 newa Ljava/lang/Object;
LineNumberTable:
line 5: 0
line 7: 7
I mean depending on the JDK version, it is possible to modify final fields
(subject to security policy)
but I didn’t think you could do that ^^
I think I know what's causing the compile-time check to not fail for (.a this)
but it is for a
>>> The HotSpot VM did not implement the new checks until JDK-8157181. However, the changes by JDK-8157181 have introduced the checks only for class files with version 9 and onwards.
well, needless to say, don’t do that :)
if someone wants to file a ticket, it might be useful to a future person that runs into it. I guess we could probably enhance the compiler to detect that the field is final and this should fail, but I’m not sure if the effort is worth it.
@alexmiller I'm working on that patch, should be relatively straightforward
amusingly, this was not an issue before because set!
was broken for that use case pre 1.8 http://dev.clojure.org/jira/browse/CLJ-1226
how about checking explicitly for target being a final field before AssignExpr is constructed at the top of the diff?
should it not be put into analyze
? so that analyze won't return an AssignableExpr
if it's not in fact assignable?
yeah, to determine if a field is final, you have to know the type of the object, which clojure doesn't always
ah. and if it wasn't, you would need a type that would hold this notion of an NonAssignableExpr
, right?
or even at compile time -- in (deftype a [x] Foo (bar [this] (set! x 1)))
x
is AssignableExpr
but fails at compile time already
@yonatanel - Yes, see: https://groups.google.com/d/msg/clojure/7ZqGTjJoQEQ/RkUYCCbeAwAJ
Not a big delta, but more stuff moved behind that for the next alpha too
is it a convention in clojure to name :private functons with - prefix, e.g. defn ^:private -my-private-defn
@jasonjckn there's the defn-
shortcut
gen-class by default looks for functions that provide the implementation for methods by prefixing with '-' but, if I recall that is configurable, but people rarely change it
bronsa: I mean, generating a static main method for classes must be special cased in someway
oh, right, it defaults to generating a main, the default name for the function is "main" plus the prefix
I remember there being a reason proxy isn't a java Proxy, but I cannot remember it now
@hiredman you prefer that java mess over gen-class? de gustibus non disputandem, but i don't see it.
@mobileink how's that java a mess? it's very simple and clean
well let's not get religious, i just genuinely do not see the problem with gen-class. i've use it to great effect, never with more than a few lines of code.
aot compilation is a huge source of maintenance headaches because it tends to break things in weird ways that show up far from the cause of the breakage
all that stuff in the java code is easily done in clojure. re: aot, how do you use java without compiling? i don't get it.
so just aot compile your gen-class stuff. i don't see why this is any more of a problem than javac.
no one is disputing that it can be done, but in practice it always breaks, the amount of times people have come in here or on irc with an issue that ultimately comes down to a problem with aot is huge
i think you may need to think more diabolically about gen-class. you don't use it to implement anything, only as a kind of bridge.
@mobileink sure, but then you start limiting what you can do if you're using gen-class, at that point just don't use it at all, avoid potential headaches, write a few lines of java and be done with it
if you look through the clojure jira for issues related to aot compilation it is like a game of whack a mole
there's a lot you need to know and that's easy to fuck up with gen-class, that's exactly the point
why would you want to risk it if it's super easy to just write 10 lines of java that do the same w/o the incidental complexity
it's just for stubs, effectively, so the servlet container can find some bytecode on disc. that generalizes to for example alexa.
try writing something like clojure.lang.ExceptionInfo
using gen-class, making sure it doesn't use any reflection and include it in a project that uses something like reloaded
i might not do that. but that has nothing to do with the virtues of gen-class. just because it's not the right tool for your task does not mean it sucks in general.
I can't speak for Rich but I seriously doubt gen-class would be included in clojure if he was to make that decision now
there are simpler ways to do interop. writing a java class is often vastly simpler and more powerful than gen-class
use it when the execution env. requires bytecode on disk. then it works fantastically well.
I think it would but he considers it low level
http://dev.clojure.org/jira/browse/CLJ-1916 oof right that
I prefer to use Java in most cases, but then I have 20 years of familiarity with it
@hiredman so don't aot compile all nss. I'm genuinely puzzled here. gen-class, esp. with :impl-ns, works absolutely perfectly for my use cases.
you say aot compilation works perfectly for you, that is 1, I am saying I see people have issues with it here or on irc about once a week
to the point where I have a pr on the clojure-site to explain how to launch a clojure program without aot compiling anything, because people are mostly aot compiling just for a launcher
gen-class has a number of issues, but for me, the nail in the coffin is aot, because aot causes more weird issues
as that company grew and the code base started to be broken up, aot compilation caused issues, so I ripped aot out and replaced the parts that needed to be replaced with java
ok just to make sure we don't talk past each other: i isolate my gen-class code. that makes it easy to only aot that. of course it depends on your build tooling.
that addresses hiredman’s concerns but not bronsa’s I think
@noisesmith specifically?
it addresses my concerns in a shallow way. when you move on to another job and another programmer takes over, or you hire someone new that isn't aware this section of code is an isolated garden, boom
@mobileink a hacky implementation that needs to use reflection
it sounds like you aren’t trying to use gen-class for anyting perf critical anyway
"stop writing software in languages that permit buffer overflows" "I write in languages that permit buffer overflows and have never had a problem"
well, maybe i'm misunderestimating sth. why would we need gen-class, ever? i'm assuming because the runtime env (a container of some kind?) needs to find code on disk. if not, just use def*. but maybe my view is overly narrow? i know that when that is the case, gen-class works very well.
@mobileink you can use gen-class without making class files on disk, you can create class files on disk without gen-class
oh, OK
before gen-class existing clojure had gen-and-load-class (or whatever it is classed)
unless what you're talking about is the potential issue of dyn classes being GC'ed before use?
@noisesmith regarding performance critical stuff, true, i do not think of gen-clasd in those terms. i might go with java for that. but my point is there are many cases where gen-class works perfectly well.
bronsa: no, I don't know the exact reasoning, but gen-and-load-class got replaced with gen-class when aot was introduced. I suspect because gen-and-load-class would always define a new class in a dynamic classloader, anything using the system classloader would get the wrong class
@noisesmith how do you create bytecode on disk without gen-class?
@hiredman i don't see how AOT/JIT gen-class would have differnt issues thatn AOT/JIT deftype?
clojure.core/compile can do that - it doesn’t give you something directly loadable by a java program though, for that I use clojure.core
I've used asm directly https://github.com/hiredman/jenkins-clojure-injector/blob/master/src/leiningen/jpi.clj I think for that there was some reason gen-class wouldn't work, but I forget what it was
i never quite understood why gen-class just does writeClassFile
and doesn't also (.defineClass ^DynamiClassLoader Compiler/LOADER ..)
like definterface does
clearly it’s a conspiracy against inheritence
just imagine the terrible code from java users newly trying clojure and defining everything via gen-class
(defn load [gzip-input-stream]
(let [rdr (transit/reader gzip-input-stream :json)
eof :_EOF_]
(loop [res []]
(let [chunk (try (transit/read rdr)
(catch Exception e
eof))]
(if (= chunk eof)
(walk/keywordize-keys res)
(recur (into res chunk)))))))
I wonder if it is some other type of exception, with an EOF as the cause, and you have some tooling that is unwrapping to the root-cause
https://github.com/cognitect/transit-clj/blob/master/src/cognitect/transit.clj#L292-L296