This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-08
Channels
- # announcements (2)
- # aws (1)
- # beginners (134)
- # calva (26)
- # cider (48)
- # cljdoc (41)
- # cljs-dev (12)
- # clojure (178)
- # clojure-brasil (1)
- # clojure-europe (16)
- # clojure-italy (30)
- # clojure-nl (13)
- # clojure-spec (118)
- # clojure-uk (81)
- # clojurescript (209)
- # community-development (77)
- # cursive (7)
- # datomic (23)
- # duct (6)
- # emacs (15)
- # events (2)
- # figwheel (13)
- # figwheel-main (18)
- # fulcro (4)
- # jackdaw (4)
- # jobs (6)
- # jobs-discuss (6)
- # kaocha (2)
- # lein-figwheel (3)
- # off-topic (4)
- # other-languages (22)
- # pathom (2)
- # pedestal (9)
- # perun (10)
- # portkey (1)
- # re-frame (41)
- # reagent (6)
- # reitit (4)
- # remote-jobs (1)
- # ring-swagger (6)
- # rum (5)
- # shadow-cljs (300)
- # sql (3)
- # test-check (6)
- # testing (7)
- # vim (1)
- # yada (9)
this might be a silly spec question, but is there a way to use a def'ed collection of keywords with, say, the :opt
group in s/keys
? i'm trying to define a map with a large list of optional keywords defined elsewhere:
(def some-test-keys [:test/a :test/b :test/c ... +100 more])
(s/def :test/labels (s/keys :opt some-test-keys))
CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
@joshkh Not with spec as it stands, but programmatic specs are coming in the next version (aka spec2).
ah clever! i did something similar to turn forms back into spec maps. it didn't cross my mind that i could use the same technique -- thanks for the suggestion. https://github.com/joshkh/specalog/blob/dev/src/specalog/jig.clj#L9
What you can do is define the spec with the literal set of keys and then use s/form
to get back the form of the spec and take it apart to get the list of keys in it. In other words, let the spec by the "System of Record" and extra your "collection of keywords" from it.
user=> (s/def ::my-spec (s/keys :opt [::key1 ::key2 ::key3]))
:user/my-spec
user=> (let [[_ _ ks] (s/form (s/get-spec ::my-spec))] (println ks))
[:user/key1 :user/key2 :user/key3]
nil
user=>
You can get fancier and check what you get back from s/form
actually has clojure.spec.alpha/keys
as the first element and :opt
as the second element and/or handle :req
/`:req-un`/etc as well.is there an equivalent to defonce
like doonce
I just want to execute some code only one time, not each time I reload my src file.
Having code executing when a namespace is loaded is generally a bad idea (since it will run if you compile the ns, for example when building an uberjar with Leiningen or Boot).
A bit out of context, but in clojurescript this is normal in order to activate your application.
If this is for dev work, you're probably better off putting it inside a (comment ..)
form and manually evaluating it when you need to @fenton
@seancorfield thats a great point, thanks sean! stinky code 😉
Many of my source files end with a (comment ..)
form that contains all sorts of expressions to do dev setup and some testing, including require
s that are only needed for dev work, setup for Components, etc.
Hi all!
Is it possible to define mutually recursive functions with metadata in a local scope?
I want to define f
and g
, and attach metadata (using with-meta
or something similar) such that each can see the other's metadata within its body.
(This has come up while implementing a fn
-like macro that creates a function and attaches some metadata to it. I'd like these "fake fn
s" to be useable anywhere a real Clojure function can be made, which led me down the road of trying to create a letfn
-like macro that attached metadata to all the functions declared in the letfn
. But I ran into the issue of not being able to create a letfn
that binds metadata to the functions it creates.)
I guess something like this should work:
(letfn
[(f-thunk []
(with-meta (fn f [] (meta (g-thunk))) {:b 3}))
(g-thunk []
(with-meta (fn [] (meta (f-thunk))) {:a 2}))]
(let [f (f-thunk) g (g-thunk)]
[(f) (g)]))
Apologies if this is noise, but is there any plan to add metadata to EDN?
Ech I always forget this….
(re-matches #"(?i)<message>(.+)</message>" "<message>foo</message>baz<message>bar</message>")
How to get foo
and bar
from here? I am trying half an hour 🙂
Hi there!
Is there anybody, who knows about a problem with slurp
? I try to fetch some websites, that I can reach via browser, but slurp
throws an exception:
(slurp "")
FileNotFoundException sun.net.www.protocol.http.HttpURLConnection.getInputStream0 (HttpURLConnection.java:1836)
Tested the same URL with curl
and it works fine. Any ideas?lein version
Leiningen 2.8.3 on Java 1.8.0_91 Java HotSpot(TM) 64-Bit Server VM
org.clojure/clojure “1.9.0”@kwladyka re-seq . But the regex is not quite right - the .+ is too greedy and may consume the end tag
I am after week 16h work everyday after breaking changes third party system update. My mind is almost turned off 🙂
definline
is still labeled as experimental in the docs, but it seems hardly ever used. what is its official status ?
Would like to deemphasize - primarily used in Clojures implementation
@kwladyka another approach:
(require '[hickory.core :as hickory]
'[hickory.select :as select])
(def parsed-doc
(hickory/as-hickory (hickory/parse "<message>foo</message>baz<message>bar</message>")))
(mapcat :content (select/select (select/tag :message) parsed-doc))
;; => ("foo" "bar")
Can it find all <errors><error><messsage>…..</message>… in string? Because in reality it is very complex XML structure.
Of course
It is bad practice to use regex for parsing XML 😉 See this famous answer: https://stackoverflow.com/a/1732454/2609980
Sometimes it can be easier
Alright let me know how it goes
Unfortunately I don’t have time to try it now. But I wrote it in my notes to try later 🙂
I have a collection c
which can be a list, a vector or a set. How do I remove an item from it while keeping the type of c
?
those are different kinds of things so there is no common operation to do that
usually if I encounter a question like this, I step back and look at how I got to wanting to remove things from a non-indexed collection
@alexmiller So you mean, I should avoid having to remove individual items from lists or vectors? Just from sets?
yes, generally I try to never remove anything from the middle of a list or vector
sets are fine - they are designed for that
@alexmiller Thank you. I'm going to think about that...
@witek if you are okay with O(n):
(let [xs [1 2 3] ;; or '(1 2 3) or #{1 2 3}
el 1]
(into (empty xs) (remove #(= % el)) xs))
beware that into
on a seq reverses order
How does Calva find test namespaces?
I have ["src/a/b.cljc", a.b]
and ["test/a/b_test.cljc", a.b-test]
, and :source-paths ["src", "test"]
, but Calva says "No tests found. 😱"
Is there a more idiomatic way of doing an or
check with multiple =
checks involving the same variable?
(or (= panel-name :general-info) (= panel-name :permanent-address) (= panel-name :school-info))
@U994BRXMF try (#{:general-info :permanent-address :school-info} panel-name)
Ah yes, I have used something like this before.
May I ask, I was wondering why this works, is a set somehow also a function?
I know it does work, but come to think about it I don’t know why :’)
(I meant under the hood)
Right I see now, then we are on the same page. Thanks!
Yeah I know it works for months now, but I never stopped an thought about why
specifically this i think: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentSet.java#L49
What a curious interface iFn, it has invokes for 0..20 arity plus 20 arity and varargs
there's some different between a form run in the repl, compiled in the repl and run normally too. invoke, run, etc
Yeah I know that varargs are slow
but it's so hazy for me that i'm almost certainly wrong but just a grain of truth there
Always interested in more knowledge, but not always at the expense of time of others ;)
If that makes any sense
class clj_dict(dict): def call__(self,item,default): return self.get(item,default) f = clj_dict(a=1,b=2) print(f('c','not_here!'))
Same goes for equality, math ops, lookup, etc
I’ve seen python code that repurposes **
for something clever
Language design is such a fascinating subject
hahaha, right
contains? at the front if nil or false are one of your cases
the set works because a set acts as a function returning an item if found in the set
also, depending on where the or is:
(case panel-name
(:general-info :permanent-address :school-info) (some-action))
- but this only works if your matches are compile time literals(the case would potentially replace if/cond here)
(#{:general-info :permanent-address :school-info} panel-name)
^^ enumerate things in a set and use set membership
literally, is panel-name in this set of values
if you want to improve readability you can make that more explicit:
(contains? #{:general-info :permanent-address :school-info} panel-name)
oh sorry, I didn’t see @dpsutton s reply above, sorry to duplicate
what's an isomorphic web framework?
ah cool, okay
most cljs react wrappers can probably be retrofitted to work isomorphic style, with some elbow grease. But rum was able to do it out of the box when it first shipped (or pretty early)
tooting my own horn here, but https://github.com/cjohansen/dumdom can render the same components server and client side on both the JVM (native, no JavaScript runtime) and Node
I hope I'm not beating a dead horse, but I wanted to ask some conceptual questions about clojure startup time. Some things I understand:
- The JVM startup time is a relatively small component
- Clojure itself has to evaluate all of its internal code when you start it up, which is the bulk of the time
- I've read that some lisp implementations are able to save an "image" of a system
- Subsequent invocations can start quicker by simply loading the image
- I think GraalVM supports a similar notion, but that might be only for compiled code (you lose eval
?)
- Clojurescript / Lumo, etc have a faster startup time (on platforms for which Node is available)
My question was: are there any technical limitations which would make it impossible for clojure to eventually support this notion of saving to / starting from an "image"?
Startup times on machines I own, if anyone is curious 🙂
startup times:
* macbook pro 2015: clojure(1.9): ~1.2 seconds
* macbook pro 2012: clojure(1.9): ~1.2 seconds
* HP [email protected]: clojure(1.8,openjdk): ~6.1 seconds
* raspi 3: clojure(1.8,oracle): ~16 seconds
* OLPC: clojure(1.6,openjdk): ~20 seconds
* raspi zero w: clojure(1.6,oracle): ~81 seconds
* raspi zero w: clojure(1.6,openjdk): ~97 seconds
* pogoplug: clojure(1.6,openjdk): ~98 seconds
* NSLU2: clojure(1.9,openjdk): ~284 seconds
what are you starting in each of those cases? lein? the clojure command line tool? java -jar ...
?
so the clojure command line tool
just make sure it's not the first run from that directory (cached deps list / downloads)
(I should also state that I'm a clojure noob -- please point out any glaring mistakes I'm making)
@noisesmith yeah, thanks, I did see a speedup on subsequent runs!
there are a few things that can be sped up, where speeding them up removes desired dev-time features of the language (eg. redefinitions of vars) - some of them are provided by default for clojure.core but can be turned on for other namespaces
for the "image" idea, I'm curious how that is implemented on other lisps. literally dumping a copy of the stack / heap to disk? seems like that would be large
@jasonpepas precisely, it's a space/speed tradeoff (java makes enough of those already that the size of allocations becomes a factor...)
yeah, that's the one
As of Clojure 1.8, the Clojure core library itself is compiled with direct linking. oh interesting, so I should definitely be comparing 1.8 to other versions
I guess it doesn't apply to your test, as it defines no clojure code outside clojure.core
might explain why the raspi zero w was way slower than I expected vs. the rasp 3 -- I was running 1.6 on one and 1.8 on the other
@noisesmith oh, if I don't use clojure.core then it doesn't get evaled on startup?
what I mean is that the flag I menion above doesn't do anything if you aren't compiling anything - I guess your one interop call gets compiled but that should be minor
if you had a significant app to compile and run, I would expect that flag to make a difference
One the conceptual things I seemed to gather was that porting clojure to a different platform doesn't address the startup issue, because it is mostly due to the need to evaluate a bunch of clojure code on startup. I grabbed a copy of clojure_py and observed similar results.
The thing which struck me was the difference between clojure startup times and some common-lisp implementation startup times. e.g. on my lowly NSLU2, gcl starts in 0.26 seconds. So it must not be evaluating much on startup.
Anyway, just wanted to ask if there was any knowledge / current efforts around the idea of starting clojure from an "image" in a way similar to e.g. common-lisp (I think emacs does this as well?) (related: https://stackoverflow.com/a/7686350/7543271)
While there is ongoing work to help reduce Clojure's startup time on the JVM, the idea of an "image" is a non-starter, in my opinion, since you're talking about the JVM itself really -- you'd need to be able to save and load JVM images for Clojure to be able to leverage that.
AppCDS does this on the jvm and it does help a lot, but kind of requires you to know everything you’re going to load
Clojure just has a lot of .class
files to load and initialize.
It would require a fairly fundamental change to the (Clojure) compiler to produce something that loaded and initialized faster for clojure.core
(and the handful of other namespaces that actually get pulled in for -main
to run) -- and that's just not a concern for server-based software which is really Clojure's target.
thanks for the perspective @seancorfield
I would recommend watching this great talk from Gary Fredericks: https://www.youtube.com/watch?v=-Qm09YiUHTs - IMO there is no low hanging fruit (without introducing breaking changes)
On a reasonably fast laptop/desktop, clojure
is fast enough for scripting for most purposes tho', unless you're looking for sub-second response times...
Gary's talk is excellent!
yeah, I gather that most people are using a SLIME-style workflow anyway, so they infrequently see the startup time lag
I guess a lot depends on which languages you're coming from... I've been on the JVM primarily for about twenty years so... 🙂
Aye, I start a REPL up and leave it running for days. In fact, I often have two or three REPLs running in different contexts, and switch my editor between them as needed.
And "Welcome to Clojure!" @jasonpepas 🙂
(just scrolled back and saw your comment that you're new-ish to the language)
One difference between 1.8 and 1.9 is the addition of clojure.spec
and core.specs
so I suspect that's part of the slowdown from 1.8 to 1.9
Correct. 1.8 had some cost from incidental loading from the socket server stuff
yeah even though I'm new, I've been watching rich's talks for years and they have influenced my thinking in other languages. my goal for 2019 is to get serious with clojure
Locally, it looks like startup times were pretty consistent from 1.2 up to 1.7 (about 1.15 - 1.2s on my desktop), then dropped to just under 1s with 1.8, and went back up to about 1.1-1.2 with 1.9.
ah, so that reflects the change to direct linking in core and then the introduction of spec
And 1.10 and 1.11 (master) seem about the same as 1.9 (again, consistent).
You might find the analysis here interesting https://dev.clojure.org/display/design/Improving+Clojure+Start+Time
You can shave some startup time off for clojure
with -J'-Xverify:none'
(per that wiki page -- but see the caveats around that)
This is consistently 0.9s for me
time echo '(System/exit 0)' | clojure -A:1.10 -J'-Xverify:none' -J-client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1
A late-2012 27" iMac with 16GB RAM and a 3.4GHz Core i7 with SSD drives.