This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-05-16
Channels
- # architecture (12)
- # aws (8)
- # bangalore-clj (1)
- # beginners (172)
- # boot (25)
- # chestnut (3)
- # cider (15)
- # cljsrn (5)
- # clojure (170)
- # clojure-india (1)
- # clojure-italy (21)
- # clojure-nl (87)
- # clojure-romania (3)
- # clojure-sg (1)
- # clojure-spec (1)
- # clojure-uk (79)
- # clojurescript (79)
- # cursive (2)
- # datomic (29)
- # dirac (26)
- # emacs (7)
- # fulcro (13)
- # jobs (4)
- # juxt (22)
- # lein-figwheel (1)
- # leiningen (2)
- # lumo (39)
- # nrepl (1)
- # off-topic (54)
- # onyx (124)
- # pedestal (1)
- # planck (4)
- # portkey (1)
- # re-frame (36)
- # reagent (2)
- # ring-swagger (8)
- # shadow-cljs (107)
- # spacemacs (1)
- # specter (25)
- # sql (7)
- # tools-deps (5)
- # vim (10)
- # yada (25)
there's so many HTTP routing libraries it's hard to pick one
Bidi has nice featureset
Pedestal has nice terse syntax and performance optimizations
In which HTTP Server/stack are you planning to use bidi?
hello, i'm working on clj wrapper for a java lib. the java api has a couple methods like .addPath
that can be called multiple times to add more paths before finally executing some action. to make things a bit nicer for users the clj wrapper should accecpt a seq for those params and handle the rest internally. so i wrote a little generic helper function that takes some java object, a fn like #(.addPath %1 %2)
and a seq of paths to be added which calls the passed fn for each path before finally returning the passed java object so the helper can be easily used in threading macros. no issues there, however to avoid reflection warnings this approach requires return type hinting the helper function whenever it is used in a threading macro, which I'd like to avoid. turning the helper function into macro seems to be the obvious solution but after some tinkering i'm not sure this is doable, but then again my macro fu is fairly basic. any pointers if this feasable or not would be greatly appreciated.
@edannenberg can't you just put the type hint on the function itself (ie. the args list)?
@moxaj the return type depends on the passed java object, so kinda hard with a regular function unless they are created dynamically which i don't find very appealing
@edannenberg here's a way to do it: make the helper function a macro, pass an additional symbol (the name of the java class or a primitive type hint like int
)
@moxaj i think i can get the type symbol via (symbol (.getName (class somejavathing)
so hopeful i don't need pass that in, however wrapping the macro body with (vary-meta)
might just be the thing i missed, thanks!
while you can retrieve the type information at runtime, you need to apply the meta at compile time
ah bummer, not sure it's even worth it then, probably not. anyways thanks for the hint, gonna play with that a bit more later and see how it turns out
@huthayfa.ainqawi anything you can write an ordinary function for (a predicate), you can write a spec with. All you have to do is write an ordinary predicate on the inbound request (assuming it's ring)
with Java getting new features (java >8), does APIs that use stuff like functional interfaces/lambdas or APIs that use static/default interface methods make interop less smooth for Clojure or things just keep working the same?
clojure can still participate in that stuff @lockdown- through reify
we’re planning to move to a Java 8 baseline in Clojure 1.10 and that will allow us to patch a few things in more automatically too
like implementing java.util.Function or whatever
@alexmiller out of curiosity… I saw Toby Crawley’s talk on Java 9 last year, and my biggest takeaway was that Java modules are a catastrophe for Clojure. Has this situation improved?
I don’t think that’s the correct takeaway
you can use modules with Clojure and most stuff will do the same thing they would be in Java
more specifically, the way they break Clojure reflection unless you (at that time) passed some immediately-deprecated JVM startup flags
that breakage only happens if you are using Clojure that relies on reflection. it is pretty easy to introduce type hints to avoid that in most cases
lots of Clojure relies on reflection, whether you’re writing it or not. Turning on reflection warnings in almost any large project is a sobering moment, in my experience
that’s not my experience, but maybe I’m just better at avoiding it in the first place
For example, javax.xml.bind issue that people run into is easily fixed by adding that module
And the most common xml-related reflection issue (coming out of data.xml, but now fixed there) is easily solved with a single type hint
to force the use of the public interface rather than the non-visible implementation class
in other words, it’s not my code that’s triggering the warnings, but there are a lot of widely-used libraries out there that do
the vast majority of those warnings are also not an issue on Java 9+
there’s a pretty narrow set of cases that trigger the issue, and I expect we will have updates to the reflector in clojure 1.10 to address those too
it’s just a matter of altering the reflection search algorithm to find only the visible stuff
I remember that period of crazy drama last year when the module proposal got voted down at the last minute, which was a huge sense of relief, only to have it suddenly green-lit again a few weeks later (with no apparent significant changes)
the tooling-related issues related to the bootclasspath were a bigger impact to users than most of the stuff above
@bronsa isn't that a hard feat? Avoiding reflection, for example, just calling .toString causes it
improve what?
Adding the correct kind of type metadata to a Clojure program that is currently using reflection, can avoid its use of reflection after those changes, yes.
Is reflection often ignored until it becomes a performance issue or it's recommended to avoid it from the start?
both approaches are valid depending on the project and/or part of the project you are working on
if I am working on code I know will be performance sensitive, I often turn on reflection warnings in that namespace and make a proactive effort to avoid reflection
if I’m in something that’s called once or rarely, I might just ignore it
if I’m writing a lib for others to use, I might take more care in avoiding reflection
because the clojure compiler does type inference, often a single type hint on an arg or a return value can drastically reduce the reflection
for example:
(defn capitalize [s]
(if (.isEmpty s)
s
(let [up (.toUpperCase (.substring s 0 1))
down (.toLowerCase (.substring s 1))]
(.concat up down))))
uses a bunch of reflection, but you can just type-hint the s arg to ^String
and the compiler then figures out the rest
and similarly, if you type-hint the return here to ^String then all down-stream callers can leverage that automatically
(defn capitalize ^String [^String s] ...
in most cases, I am unable to help doing at least this as I write the initial code
some heavy interop code (that has no reflection) that I’ve written recently for example: https://github.com/clojure/tools.deps.alpha/blob/master/src/main/clojure/clojure/tools/deps/alpha/util/maven.clj
it’s bytecode that runs on the jvm, so same as Java and Scala and Groovy and …
that is, it just emits the proper bytecode for method invocation
the context of the question isn't clear to me. if you are asking how clojure does runtime dispatch in the context of the discussion about type hints, the anser is basically it doesn't, the type hints tell the compiler what types things are, the compiler generates bytecode with the types filled in, the jvm does any dispatch
if the question is a general, how would do polymorphism in clojure? the answer is by far the most common data passed around in clojure is some kind of map, so dispatch is usually something that chooses what do to based on a key in a map, and a common thing for that is a multimethod. clojure also has protocols and defrecord which give you something which is sort of between multimethods and java interfaces
the way the jvm does runtime dispatch is through a type hierarchy or interfaces, all of which still apply to type hints, you can type hint something with an interface, and it will compile to a non-reflective method call where the jvm machinery figures out which method to call based on which implementation of the interface is passed in (just like interfaces work in java)
About multimethods thing, i guess clojure really does its own stuff here and pays a penalty correct?
I am not sure it is meaningfully comparable, you can only represent a small subset of multimethods usage as java type dispatch
and if you want to do java type dispatch, you can, so to say clojure pays a penalty for it, doesn't really track
(defmacro parsefn [sym]
`(fn [is#]
(. is# ~(eval `(symbol ~sym)))))
(defn- ->parsefn [type]
(let [name (-> (str "cis->" type)
symbol)
foo (str "read" "Enum")
f (parsefn foo)]
(intern *ns* name f)))
but anything involving a variable blows up (at compile time, but works fine in the REPL)
(defmacro parsefn [sym]
`(fn [is#]
(. is# ~(eval `(symbol ~sym)))))
=> #'user/parsefn
(macroexpand-1 '(parsefn (str "to" t)))
=> (clojure.core/fn [is__9937__auto__] (. is__9937__auto__ toString))
a macro is a transform from X to Y, so you need to know what your X looks like and what your Y looks like
i need to basically dynamically compose a symbol at compile time and get it to the dot special form
(def foo (str "a" "b"))
(macroexpand-1 '(parsefn foo))
=> #'user/foo
=> (clojure.core/fn [is__9937__auto__] (. is__9937__auto__ ab))
also . doesn't evaluate that method name arg and that auto generated method name is surely wrong
ah, right, the method is the second arg when . is used that way, my misunderstanding
you get
(defmacro parsefn [sym]
`(fn [is#]
(. is# ~`(symbol ~sym))))
=> #'user/parsefn
(macroexpand-1 '(parsefn (str "to" t)))
=> (clojure.core/fn [is__9971__auto__] (. is__9971__auto__ (clojure.core/symbol (str "to" t))))
there are two ways to do the reflection, either use the java reflection api, or call eval and let clojure do it for you
basically im trying to do a bunch of interop that has the same pattern against a class like this: https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/CodedInputStream
given something like that, instead of using reflection when invoking methods, I would use reflection to examine the class to get a list of accessors I want to generate, then have a macro use that to generate the accessors
Id be curious to hear your thoughts here. I cant claim to fully understand what you are suggesting but I suspect its a different approach than the (eval `(fn ..)) one you already suggested
something like
(defmacro something []
(cons 'do
(for [method (.getDeclaredMethods com.google.protobuf.CodedInputStream)
:let [argc (count (.getParameterTypes method))
args (repeatedly argc gensym)]]
`(defn ~(symbol (.getName method)) [obj# ~@args]
(. obj# (~(symbol (.getName method)) ~@args))))))
there is also clojure.reflect which attempts to expose the java reflection stuff as clojure datastructures, which might be nicer to work with
So i've been looking over clojure/core/server.clj, and I have a few questions in regard to implementation
: clojure/src/clj/clojure/core/server.clj
- ~line 26 - Why does it use a var to store servers? It's also using a locking mechanism to ensure there are no concurrency issues. Why not just use a ref
in this situation?
- ~line 38 - Why does it use a Thread directly? Why isn't it using an agent
?
I only ask because i'm trying to get familiar with the code so I can write my own socket repl for a pet project, and I was going to use ref
and agent
over the implementation presented here. Is there a particular reason why this would be a bad idea?
re 26 - refs are good for data, locks are better for thread coordination
re 38 - wanted a separate and identifiable thread pool for this
I think @benzap is asking why the lock is needed at all @alexmiller
i think the socket manipulation (open/close etc.) necessitates it, but not necessarily the data accounting
My guess is to prevent any possible headaches down the road, they chose to using a lock to ensure there isn't any potentially hard to debug code in the future
you don't want to create a stateful resource in any operation that might retry
which means some kind of lock somewhere, or no concurrency (and even no concurrency is enforced with ... a lock)