This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-04
Channels
- # beginners (149)
- # cider (1)
- # clara (12)
- # cljs-dev (226)
- # cljsrn (2)
- # clojure (275)
- # clojure-russia (5)
- # clojure-uk (14)
- # clojurescript (57)
- # cursive (23)
- # data-science (15)
- # datomic (1)
- # fulcro (8)
- # hoplon (9)
- # onyx (5)
- # portkey (15)
- # protorepl (1)
- # re-frame (8)
- # reagent (17)
- # shadow-cljs (22)
- # uncomplicate (13)
- # vim (36)
macros don't add namespaces to things, but does, to avoid namespacing of unresolved symbols inside
you can use ~'ProductGenerators
but that's often a sign you are doing something error prone
its either A. that im in a macro B. In a do C. Its an ide issue and its not at the clojure level or D. Im doing something else wrong
there’s at least one thing wrong with the macro: the _
is not quoted so it will expand to (get [your-ns.core/_] ...)
@emccue in that code where does "Supllier" come from?
again, since the Supplier
symbol is not quoted it it will be resolved in the current namespace, ie your-ns/Supplier
@schmee no it gets filled with the fully qualified thing in scope
@noisesmith ahh, my bad
+user=> (import (java.util.function Supplier))
java.util.function.Supplier
+user=> `Supplier
java.util.function.Supplier
@emccue one thing that would simplify that code is that you can use interface# as the interface name - every instance of foo# in one backtick is replaced by the same gensym with that base string foo
also _# works just fine :P
@emccue I recommend using interface# instead of gensym, but if you do use gensym (symbol x) for gensym x is redundant, it's always already a symbol
(im editing the most recent snippet with changes as I go instead of flooding the chat)
also another fun thing is that defining a method impl for defrecord inside a macro is common enough that defrecord actually accepts namespace qualified method names - it is smart enough to just use the name part and ignore the ns part
so
(~'generate ...
on line 10 can just be (generate ...
also if you change ~'this
in both places to this#
and avoid the question of capture / shadowing
if you can't tell, I'm fond of eliminating ~'
from code - it improves readability and long term correctness
@emccue I was trying to replicate to help with that but there were too many references to undefined functions
I can stub them, it doesn't matter what they really do
or if it does, then I narrowed that down
@emccue I have it stubbed enough to not find Product - where would that have been defined?
and it actually exists in that scope before running that code?
because the Product symbol passed to the macro is resolved in expansion
OK - so that exists and is visible when the macro is run?
if so your error is in one of those functions I stubbed
could justify a bug report on Cursive? the dev hangs out here
there's the #cursive channel
tag is "cfleming" but he should reply in that channel
@emccue Unfortunately Cursive has problems with macro forms like that. You can tell it to treat your macro as one that it already understands, but from what I can tell yours doesn’t look like anything that currently exists.
hmm, well my entire team uses intelliJ, and I was trying to sneak some clojure as part of a project
1. My clojure code isnt building in step with the java code 2. Records I define through my macro dont become visible to java
Ok. So #1 will probably have to be @talios, or someone with more experience of clojure-maven-plugin, sorry.
For #2, can you get away without using the macro, or make your macro look more like an existing one?
The whole point was to write a macro to define a way to feed test data that isnt parsing through json files
Then from my the java code for e2e tests I can get a list of all the possible matchups of those things
Noone else on my team uses clojure so I would have to be able to get away without having them make the investment in Cursive up front
@emccue Could you make a simple repo with a self-contained example and I’ll take a look at it?
I don’t fully understand what those are doing - is the idea that it will generate a class for each of the :name elements?
Why does each instance of the class require its own interface? Is that used in generate-examples?
(but if you are curious the idea is to have a list of functions (list #(assoc % key val) ...)
or optionally another sublist of functions that I would flatten [somehow] to produce a list of lists of functions that i can apply to the map to build it)
List<Thing> doesn't directly exist in bytecode (yes, there's some reflectable data that some tools use but that's not the same as having the typeper se)
Right, but @emccue is looking to provide a typed return for Java clients using IntelliJ, which will use it.
but I still want to somehow let java programmers use my code and get normal type hints
ahh, so intellij is one of those tools that would pick up that metadata
I don’t think there’s any way to create a class which does what you want in Clojure.
In terms of Cursive support, I can’t think of a good way to achieve what you want. I think the best compromise would be to just use raw defrecords. I don’t think the interface in your example adds any value, so you’ll just end up with a more verbose solution.
Something like:
(defrecord UserGenerator []
Supplier
(get [_] (generate-examples <your data>)))
I think the real problem here is they need to implement specific method names, and that can't be done in clojure without defining an interface
Which isn’t quite as nice as a DSL, but isn’t terrible, and anyone can look at it and immediately see what it does.
What are you actually returning to Java? An array of UserGenerators, or an array of Users?
Ok, I still can’t see a way to have UserGenerator implement Supplier<T> - it’ll only ever implement Supplier.
I think to do what you want, you’ll need to have UserGenerator defined in Java, and then in its generate method you can call into Clojure using Clojure.var(), and then your generation functions can just be functions and everyone will be happy 🙂
If your class only implements Supplier, your for loop above won’t work, your u will have type Object.
I might be wrong (this is getting a little esoteric) but I don’t think that even returning a typed array will help, because Java won’t see the type of the object statically.
Unfortunately I can’t think of a good way to make Cursive understand what you’re doing.
Additionally, even if you can get it to work, your teammates will still need Cursive for this to work, unless you’re building an artifact that they depend on.
but if there isnt a way to make intelliJ see the generated classes then its kinda bunk
public interface Supplier<T> {
T[] generate();
}
public class User {
public String name;
}
And:
(ns test
(:import (test Supplier)))
(definterface Foo
(get ^"[Ltest.User" []))
(defrecord FooGenerator []
Foo
(get [_])
Supplier
(generate [_]))
I now have:
(definterface Foo
(get ^"[Ltest.User;" []))
(defrecord FooGenerator []
Foo
(get [_]))
so… I still can’t see a good way to make Cursive understand this, at least until I have an API for adding macro support.
IMO your best option is still to define UserGenerator in Java, where you can have your types easily without jumping through hoops.
That can call Clojure.var(“test-ns”, “generate-users”) and do a dirty cast as required.
Your Clojure code can just look like:
(defn generate-users []
(generate-from {<all your data>})
yeah but this is all about giving people who dont want to learn clojure a pretty interface
The pitch should be "heres this pretty syntax" followed by "heres the steps to use it" and optionally install this one plugin.
at the very least, you have at least one bug report and one use case for better macro interpreting support
(im totally fine making the java side a bit more complicated than a for loop : thats a tar pit anyways)
Is there any proposals for/information about/rejection of supporting multiple versions of a namespace / multiple classloaders for a namespace in Clojure? I've tried searching google groups, jira & confluence. I haven't turned up anything of interest.
how to hotfix html page by nrepl? It’s good when I evaluate clj file in local and it worked in remote server, but how to let local html page updated to remote server?
the floating point spec requires that NaN is not equal to NaN
It’s not a number, but it may not be equal to my thing that is also not a number 😀
there's actually multiple NaN values in the spec - but in practice hardly cares which one you have and they are not even equal to themselves
fp is weird
Is there an organized way to view the available lein templates? I need to decide what to use for a new project, and they’ve grown tremendously.
and there doesn't appear to be any clojure.core function to test against NaN, is this a grave undersight, or am I going crazy?
(Double/isNaN ...)
it's different in cljs
(js/isNaN x)
well, that's the only way to do it that I know of
it might be possible to use (and (not (pos? x)) (not (neg? x)) (not (zero? x)) (number? x))
portably?
+cljs.user=> (js/isNaN 1)
false
+cljs.user=> (defn nany [x] (and (number? x) (not (neg? x)) (not (pos? x)) (not (zero? x))))
#'cljs.user/nany
+cljs.user=> (nany 1)
false
+cljs.user=> (nany (/ 0.0 0.0))
true
but Double/isNaN and js/isNaN are more efficient
In Java, positive and negative infinity are special values too (##Inf, ##-Inf)
not sure if nany might catch those too, but not sure in cljs/js
oh, I'll have to try
yeah, those are not detected by those checks, but Double/isNaN returns false for them too
you could detect an inf by asking if (= x (dec x)) maybe
with interop that's Double/isInfinite
also less a problem because in the fp spec ##Inf and ##Inf are in fact considered equal
i think (= x (dec x)) will fail on large numbers in js, as the floating point grid delta is larger than 1 there
oh, good point
Could somebody please sanity check me? I could have sworn that I have seen a core api function that will return a function that just returns it's first argument, the equivalent to (fn [x & _] x), but now I am thinking that I might have dreamt it.
constantly
Yes, I think maybe constantly is what I am thinking of, but that does something slightly different of course, returning a fixed value and ignoring all arguments. Maybe this is what my tired brain is referencing. It's not really a problem, the above form is simple enough, for some reason I just thought it was already there.
Oh you said a function that returns a function etc. But that would just be a function that returns constantly
, no?
(fn [x & _] (partial constantly x))
? 🙂
Nope, that won't work
(fn [x & _] x)
works OK, it was just for some reason I thought there was a core function that generated this function for you. Happy to write it like this (it's often the dispatch function for my multimethods). Luckily my laptop memory is more reliable they my own 🙂. Thanks forlks.
you can compose it point free as (comp first list)
perhaps there's a more clever version that also avoids forcing the arg list for indefinite arg count
hi! any chance to do type upcasting in clojure?
(defprotocol P (p [_]))
(defrecord R [x]
P (p [_] "Hello from R"))
(extend-type Object
P (p [_] "Hello from Object"))
(p (R. 1)) ;; => "Hello from R"
(p (Object.)) ;; => "Hello from Object"
(p ^Object (R. 1)) ;; => "Hello from R"
I need to call protocol method on R instance upcasted to ObjectThese dispatches are dynamic, so no.
Your best bet is to call the object specific function manually via a normal function call.
There’s that Java benchmarking framework you might want to look at, I think there is a clojure helper with it
Covers a lot of the important issues (I assume you’re already familiar with Criterium)
yes, Criterium is what I’m using now. I’ve seen JMH mentioned a lot so I guess it’s time to double down and learn it, thanks 🙂
any easy way to do the following:
(map vector [1 2 3] [6 7 8 9 10])
=> ([1 6] [2 7] [3 8])
but get [nil 9] [nil 10]
as extra elements at the end of the result?(map-indexed (fn [i x] [(nth v1 i nil) x]) v2)
?
@noisesmith nice! I had a nasty reduce, figured there was a better way
it gets a big uglier when you need to flip it for the other one to be the shorter coll, you could make a multimethod that dispatches based on (> (count a) (count b))
or you can just map on (range (max-key count colls)) and use nth for both
err, make that (apply max (map count colls))
IFn eval = Clojure.var("clojure.core", "eval");
eval.invoke(Clojure.read("(defrecord R [a b])"));
will kind of work but the default namespace is clojure.core so you’ll create clojure.core.R
if you already have the constructor, then that’s just a function you invoke named ->R
or whatever
IFn newR = Clojure.var("my.ns", "->R");
newR.invoke(1, 2);
or the record is itself just a class with a positional constructor so simply:
my.ns.R(1, 2);
should work too
@alexmiller That ended up working out in the end
another thing I want to do with my current code is just allow raw json, but I cannot for the life of me figure out macros to that extent
this task might not be in scope for clojure macros
but if you need to translate symbols in a macro, you can call name on the symbol to get the string, then edit it, then call symbol again
this gets messy fast though
is it a bad idea to use repeatedly
or any of the infinite sequence functions for io? say I wanted to read a file line by line, forever, for example… could I quite simply do something like the following:
(defn get-file [path]
;; make the file available as a lazy-seq of strings
(repeatedly
#(let [rdr (io/reader (io/resource path))]
(letfn [(read-next []
(lazy-seq
(if-let [line (.readLine rdr)]
(cons line (read-next))
(do (.close rdr) nil))))]
(read-next)))
)
)
Or am I going to wind up with some un-collected resources?that code is basically line-seq btw
but yes, io and laziness are a bad fit
also that comment is incorrect - the get-file gives you a lazy-seq of lazy-seqs of strings
I might recommend a Stuart Sierra component to manage your side effects. If anybody has a better alternative feel free to weigh in
Although the downside is you would really have to buy into the component system to see the best results. You have to weigh the tradeoffs