This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-17
Channels
- # 100-days-of-code (5)
- # announcements (13)
- # beginners (98)
- # boot (19)
- # cider (10)
- # cljdoc (32)
- # clojure (142)
- # clojure-dev (37)
- # clojure-italy (3)
- # clojure-nl (2)
- # clojure-spec (30)
- # clojure-uk (18)
- # clojurescript (28)
- # cursive (8)
- # datomic (25)
- # duct (18)
- # editors (5)
- # emacs (39)
- # events (4)
- # figwheel (7)
- # figwheel-main (5)
- # fulcro (38)
- # graphql (19)
- # jobs-discuss (1)
- # jobs-rus (7)
- # keechma (1)
- # lumo (47)
- # off-topic (28)
- # om-next (3)
- # parinfer (3)
- # re-frame (18)
- # reagent (37)
- # reitit (8)
- # shadow-cljs (101)
- # specter (7)
- # tools-deps (8)
- # vim (1)
Thinking about maybe starting a local Clojure meetup and/or a regional conference. I have no experience in either (outside of attending), but I want to foster a community in my area. Are there any resources in the community (guides, templates) around planning/managing these sorts of events?
There is actually a guide I wrote long ago! Now if I can only find it....
Talk to @ericnormand
My experience with starting a local Python UG some years ago is that it’s easy to start, harder to grow and maintain.
In my case, I had a few Twitter followers/followees that I knew were local. I set a date/time to go grab some coffee, with the success bar being that someone other than me would show up.
Turns out a handful of people showed up, we chatted, then found a proper venue and set a date for an actual meetup. We also got a mailing list.
I’ve since moved out of both Python and the city, but meetups have been happening without me, so success?
Is there a way to get to the source string of multimethods? I’m trying todo something like
(->> (methods my-multi)
(map (fn [[k f]] (clojure.repl/source-fn f))))
How many JVM threads are dedicated to go blocks in standard core.async? This answer says 42 + the number of processors… (I think he means cores), but in the source code I found 8?
see https://github.com/clojure/core.async/commit/a690c4f3b7bf9ae9e7bdc899c030955d5933042d
did you guys see this? looks amazing (I think heads up from Alex here on slack helped 🙂 )
As far as clojure is the best I wouldn't consider it being off topic 😄 And yeah, it probably also depends on how much the scala/kotlin communities were aware of the survey taking place... But overall (and regardless) I think it is a good news for clojure.
Hello! Quick question: I would like to use keywords like this in spec: ::person/first-name
. Afaik I can only do this is I have a namespace that I alias to person, i.e.. (require '[... :as person])
. Is there any way I can do this without creating such a namespace in another file and aliasing it?
@hmaurer At work we're currently using (alias 'person (create-ns 'the.full.person))
at the top of the namespace (after the ns
form) where we want to use ::person
aliases without requiring a namespace. We're looking forward to whatever Rich comes up with as an alternative tho'...
@alexmiller Thanks. Is it a sensible thing to do to create namespaces for this purpose then?
Also, unrelated but I recall you tweeting about working on improving error messages for Clojure? Or was that someone else?
One approach is to call create-ns / alias at the top of a namespace using spec. But this is an area that Rich has some future ideas about.
Yes, there is a lot of error rework in the latest 1.10.0-beta3, please give it a try!
Brilliant; that has always been my major pain-point with Clojure. Will give it a try! 🙂
You should see it in the structure of all errors
Some examples there
Also, while you are around, I’ve another question on Spec (if you have the time). I have to model a pretty extensive hiearchy for a project. This is a small example: https://puu.sh/BM1sE/7aaf4c8e7b.png. I was going to tag all my maps with a :type
, use derive
on the types to express the hierarchy and use a multispec. This seems to work o.k. so long as only “leaf types” have attributes. If the intermediate types have attributes that need to be merged into child specs it seems to become a bit messier. Do you have any advice on how to do this, and/or link to a project that takes a similar approach, or a differnt approach solving the same problem?
I don’t really care how I model the hiearchy, but I want to be able to express that some things are part of a “concept”. For example, I have a bunch of maps which correspond to “failures” (similar to Cognitect’s Anomaly library). I want to be able to express that all of those are “failures”, and I was going to do so by deriving
their type from :failure
Well, you could not use inheritance and instead just collect attributes into containers, then model those as partial maps combined with s/merge
using derive
and isa?
for a hierarchy of keywords seem straightforward enough; my issue is how to make it play nicely with Spec
@alexmiller I need to be able to express things such as “this attribute on this map has type Compound
, which means it can be anything that derives from Compound
”
Well, I generally try to avoid doing oo things like that
@alexmiller is this OO though? I just think of it as a hiearchy of concepts, which is quite natural in language and shows up in a bunch of places. For example here I am modelling an AST for first-order logic, and it’s very natural to say that a negation (i.e. not X
) can be constructed by putting not
in front of any formula
, etc
I would focus on the attributes instances have most importantly - each of those should be a known spec
Then you have collections of attributes that make sense at different places in the hierarchy
If they are additive then you can describe the root as a keys spec and each other node as an s/merge of parent and that node
@hmaurer > This seems to work o.k. so long as only “leaf types” have attributes. If the intermediate types have attributes that need to be merged into child specs it seems to become a bit messier. This is a problem i have tackled to build map of attributes, although not for clojure.spec. https://github.com/TristeFigure/methodman
I’d like for the JVM to crash and burn and exit when an exception is uncaught on the main thread, but it seems like it stays in limbo. I’m not sure if there are unjoined threads or not — how should I go about figuring this out?
Hello friends, I made a hiccup->clj-pdf convertor, written as a bunch of multimethods for all html elements like [:b] [:i] [:div] etc, which uses recursion (ie. it’s a recursive-descent parser)
I think though, that this is a bit problematic due to potential overflows right? I mean, if the hiccup is very large that is
could this be refactored using trampoline? I can’t really use recur
, since I use a helper function that emits stuff, called from the multimethod instances.
but, is it problematic in the first place? (ie. is my understanding correct about tail-call optimization?)
Yes, if you want tail-call optimization, you need to use recur
. Clojure can't tail call optimize two functions calling each other "in a loop".
if you check line 179 where i parse a bold tag, i call emit-element
, inside emit-element
i call parse
again to descend the parser
A little different, even. You'd call parse
using trampoline
to begin with, and instead of calling parse
or emit-element
, you return a function that calls it. Trampoline will then call it.
yeah i played around a bit, i think i have this working, although it sometimes doesnt seem to call the function rather return it, but that might have a different reason (ie. a bug)
So at the beginning you call something like (trampoline parse all-args)
, then parse
will, instead of calling, return #(emit-element "paragraph" {} all-args)
and so on
@hmaurer At work we're currently using (alias 'person (create-ns 'the.full.person))
at the top of the namespace (after the ns
form) where we want to use ::person
aliases without requiring a namespace. We're looking forward to whatever Rich comes up with as an alternative tho'...
hello, I'm trying to use Transit default handler on Clj, but that doens't seem to be working, in CLJS I can do this:
(deftype DefaultHandler []
Object
(tag [this v] "unknown")
(rep [this v] (pr-str v)))
(def write-handlers
{"default" (DefaultHandler.)})
(defn write [x]
(let [writer (ft/writer {:handlers write-handlers})]
(t/write writer x)))
(write {:foo (fn [] "bogus that transit cant encode")})
and because fn is not valid, it will iuse the DefaultHandler, but on clj when I try the same it doens't work, it fails complaining it's not supported
clj code:
(deftype DefaultHandler []
WriteHandler
(tag [this v] "unknown")
(rep [this v] (pr-str v)))
(def write-handlers
{"default" (DefaultHandler.)})
(defn write [x]
(let [baos (ByteArrayOutputStream.)
w (fulcro.transit/writer baos {:handlers write-handlers})
_ (transit/write w x)
ret (.toString baos)]
(.reset baos)
ret))
(write {:foo (fn [] "bogus that transit cant encode")})
am I missing something?
a quick look through transit-clj and transit-java, it doesn't look like the string literal "default" appears in either of those libraries, which suggests it isn't a feature they have. transit-cljs seems to also not have the string "default" and seems to want the keyword :default. transit-js seems to look for "defaultHandler"
I would just look at the default-write-handlers: https://github.com/cognitect/transit-clj/blob/master/src/cognitect/transit.clj#L86-L104
the keys are not strings, so maybe try Object
or clojure.lang.AFn
as a key instead @wilkerlucio
Hello ALL, do you think a problem solution is most performatic using reduce or recursion?
@fabrao depends on the specific problem and the specific solution, so without those two you will not be able to say 😉
my personal rule is reduce for simple stuff and recursion when i need more flexibility
n.b. having multiple accumulator values or exiting before the end of the input are both things reduce does easily
yeah, reducing with a tuple accumulator is something I see all the time and reduced
is right there.
reduce is the best.
I often write gnarly loop recur things and then rewrite it with reduce in a much nicer way
(nicer to me anyway)
testing performance for this is hard, since the performance problems with reduce only show up under load. Normally reduce involves more allocations and garbage creation.
Which normally isn't a problem, but I've seen it become a problem in some situations
so luckily I have a nice case just above, this recursive descent parsing of hiccup data and converting it to clj-pdf datastructures 😉
i’m trying to get it to work with trampoline, but i seem to hit a wall, since I’m doing this breadth first, the recursion of child elements will return a map rather than a function
@isak thanks, if I add the clojure.lang.AFn
it works for fns, but what I really need is a "catch all", which Object
is not doing =/
@kah0ona I don't think I've ever hit a situation where a data-structure needed to be deeper than the stack. You might be over-optimizing
the problem is that I have a big that can be quite big, with lots of information from many different sources (worked by many different teams), so say I have around 500 keys or more in the response, one of then get me something that transit doens't understand, and that breaks the whole output
so what I need is a way to prevent that, and just get anything out for the parts it doesn't understand
the transit-cljs version works fine with the "default"
option, but I can't figure how to do the same on transit-clj
@kah0ona I'd try using a on-heap stack instead of trampolines. So whenever you hit a branch in your tree, push it onto the stack, and when you're done with a leaf, pop an item from the stack and continue on
@kah0ona zippers work a lot like this
@wilkerlucio what happens if you write a handler for Object in Java?
@tbaldridge I tried using the fn
value example, but setting a write handler for Object
didn;'t catch that, ending up in a error
CompilerException java.lang.RuntimeException: java.lang.Exception: Not supported:
well, seems to work with records at least, maybe fns are special in some way to this?
@wilkerlucio hm, you may need to write your own writer
constructor, because the one in transit-clj does not give a way to pass in defaultWriteHandler
, which is another argument it sounds like you need.
See this line in transit-clj https://github.com/cognitect/transit-clj/blob/master/src/cognitect/transit.clj#L157 which calls this method in the java: https://github.com/cognitect/transit-java/blob/master/src/main/java/com/cognitect/transit/TransitFactory.java#L91
@isak I see, seems like the default sends default handler as nil
, so maybe just changing that can make it work, I'll try it out, thanks!
I see they take a different approach in fressian, maybe this is smarter. See https://github.com/clojure/data.fressian/blob/master/src/main/clojure/clojure/data/fressian.clj#L58 and https://github.com/Datomic/fressian/blob/master/src/org/fressian/impl/InheritanceLookup.java
@isak thanks, the custom writer did the trick! but not without some friction... this is what I got:
(defn writer
"Creates a writer over the provided destination `out` using
the specified format, one of: :msgpack, :json or :json-verbose.
An optional opts map may be passed. Supported options are:
:handlers - a map of types to WriteHandler instances, they are merged
with the default-handlers and then with the default handlers
provided by transit-java.
:transform - a function of one argument that will transform values before
they are written."
([out type] (writer out type {}))
([^OutputStream out type {:keys [handlers transform default-handler]}]
(if (#{:json :json-verbose :msgpack} type)
(let [handler-map (merge transit/default-write-handlers handlers)]
(transit/->Writer
(TransitFactory/writer (#'transit/transit-format type) out handler-map default-handler
(when transform
(reify Function
(apply [_ x]
(transform x)))))))
(throw (ex-info "Type must be :json, :json-verbose or :msgpack" {:type type})))))
I removed a few things and add the default-handler
option, this can set the default handler
trully feels like it should be there already, you think would be ok to add this to transit @tbaldridge?
currently the writer from transit always sends nil
to the default-handler
, we could make it configuration with a key in the last argument (like in the code above)
Just a syntax question:
I know that there is a shorthand notation for making maps of namespaced keywords
to values (e.g. #:foo.bar {:baz 1 :blee 2}
), but I was wondering if there was
also some shortcut for making vectors of namespaced keywords? (i.e., something
akin to #:foo.bar[:baz :blee]
). I am trying to save on typing for making a
bunch of pull expressions in datomic.
I suppose a simple function can fix this, but I thought I had heard about
something like this already and wanted to double-check.
no, not currently
When using clojure.test/run-all-tests - is there somewhere all the aggregated results can be looked up? The problem I have is that I have 1000 or so tests, and they all run and then it says 1 failed so I have to look back through a lot of log files to see which one actually failed.
Quick question: is it a common / sensible pattern with Spec to conform against an or
spec to get a tag, then to use that tag to dispatch on a multimethod to process the data accordingly?
If you really want open dispatch, this is a good use for multi-specs. But yes, I’ve been using s/or
and core.match
together for places where I want tightly controlled behavior.
@U04V5T0V8 in this case it’s about modelling an AST and dispatching on the type of the nodes
@U04V5T0V8 strictness as in, s/or
?
@U04V5T0V8 thanks 🙂
@U04V5T0V8 can you give me an example or two of cases where you would favour open dispatch?
I don’t really have one I can communicate 🙃 I’ve been bitten in the past by the difficulty of debugging, documenting and iterating on open dispatch systems and I generally find formalized types / dispatch rules an aid to understanding. That said I literally wrote an open dispatch based API last night so 🤷
I guess if I had to explain, I’d say that open dispatch as a way to define extensible ASTs seems like a good way to undermine any properties you may be trying to provide within the AST - and I’d level that criticism in general against the Scheme towers of languages / nanopass compiler world.