This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-25
Channels
- # 100-days-of-code (6)
- # announcements (4)
- # aws (2)
- # beginners (151)
- # boot (1)
- # calva (1)
- # cider (19)
- # clara (47)
- # cljdoc (9)
- # cljs-dev (25)
- # clojars (18)
- # clojure (151)
- # clojure-canada (1)
- # clojure-conj (1)
- # clojure-dev (17)
- # clojure-italy (42)
- # clojure-nl (34)
- # clojure-spec (67)
- # clojure-uk (125)
- # clojurescript (163)
- # core-async (106)
- # cursive (19)
- # data-science (11)
- # datomic (9)
- # duct (2)
- # figwheel (1)
- # figwheel-main (6)
- # fulcro (97)
- # graphql (9)
- # instaparse (4)
- # jobs (6)
- # jobs-discuss (21)
- # leiningen (62)
- # mount (23)
- # off-topic (16)
- # re-frame (15)
- # reagent (16)
- # reitit (5)
- # remote-jobs (1)
- # ring-swagger (9)
- # shadow-cljs (176)
- # tools-deps (102)
- # unrepl (3)
Hi all, I'm working through Clojure for the Brave and True ch. 6, and I'm seeing behavior I don't understand when I run the final code for the-divine-cheese-code exercise. When I lein run
the app it does its work pretty quickly, but then my bash prompt hangs for about a minute before the java process shuts down. If I remove the call to clojure.java.browse/browse-url
then the java process closes right away when the app's work is done. Is there a reason browse-url
is supposed to keep the java process alive after it's done?
Here's the code that is running. If I run this I get "All done!" in the console promptly, but the java process stays alive for a minute afterwards.
Maps = preferable over passing several parameters around? I like maps. like.. [game-info] vs [owner-id owner-token player-id player-token game-identifier] Personally, yes
@ben.grabow Add a call to (shutdown-agents)
at the end of your -main
function.
Adding (shutdown-agents)
does the trick. What's going on behind the scenes?
Certain Clojure construct fire up thread pools in the background and some of them tend to stay "busy" for up to 60 seconds at the end of the JVM shutting down. But if you call (shutdown-agents)
explicitly, it shuts those thread pools down quickly.
(as far as I understand it -- I pretty much have to add (shutdown-agents)
at the end of every non-trivial -main
function these days!)
I'll have to remember that, thank you @seancorfield!
guys, how would you test a function, that the input is too big for unit tests, and using spec to generate your input have a problem, because the input is a nested map, and you're extracting some nested value, and this can be either one item from a set of specific values or a empty map. so you can't possible know if you extracted the right one, using a 'random' generated data from spec. Should i create a function that generates the value that i want on the specific key, and test it against my original function that extracts it?
or i could generate the data from the spec and change the key/value that i want, and use it to unit test my function...
i guess the latter is less complicated
because i already have the spec for the data
@cybersapiens97 My initial reaction is that maybe your function is too complicated and/or has too much knowledge of the whole data structure... could you refactor the code to have a function that only operates on part of the data structure? i.e., you pass it just a portion of the whole map instead.
[{:line-number 1 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}
{:line-number 2 :line-columns {:a {} :b {} :c "Something" :d {} :e {} :f {} :g {} :h {}}}
{:line-number 3 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}
{:line-number 4 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}
{:line-number 5 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}
{:line-number 6 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}
{:line-number 7 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}
{:line-number 8 :line-columns {:a {} :b {} :c {} :d {} :e {} :f {} :g {} :h {}}}]
hmm i think it's easy if i break it into more functions, but i don't see how this would make the test easier
for example, you would receive [vector-above line-number line-column], in this case [vector-above 2 :c] => "Something"
doing the function is easy, testing without passing the entire structure for checking if it's the right thing is the difficult part for me now
it's ugly to use this entire structure on a unit testing, but will be enough for now...
So the function only operates on "Something"
?
and something else (the caller?) does (get-in vector-above [1 :line-columns :c])
to navigate to that (line number 2 is the 1th entry, line number 1 is the 0th entry)
the function simply extracts any given line-number and column and whatever is inside of it, didn't designed yet but the data will be either an empty map or something else
btw this is me trying to do a chessboard lol
and i'm realizing that :line-number key isn't needed because i'm using a sorted vector...
and spec'ing data before it's final shape seems too much time consuming
get-in
is all you need to navigate that -- you don't need a custom function.
Simplify. Rely on built-in functions.
Operate on the smallest piece of data possible and separate navigation from transformation.
nice advice, thanks. i tend to make things complex without need
Anything that calls clojure.core/future
causes this. Several of them are listed here: http://clojuredocs.org/clojure.core/future
It doesn't look like browse-url uses clojure.core/future
. Maybe I am misunderstanding?
https://github.com/clojure/clojure/blob/master/src/clj/clojure/java/browse.clj#L42
https://docs.oracle.com/javase/7/docs/api/java/awt/Desktop.html#browse(java.net.URI)
Probably this line in browse-url, used to do the opening of the URL on Mac and Linux. clojure.java.shell/sh does use future internally, here: https://github.com/clojure/clojure/blob/4ef4b1ed7a2e8bb0aaaacfb0942729252c2c3091/src/clj/clojure/java/shell.clj#L119
Missed a link. The line in browse-url is this one: https://github.com/clojure/clojure/blob/master/src/clj/clojure/java/browse.clj#L74
geez, call it a brainfart, took me a day to realize that (is (every? true? (map = [1 2 3] some-seq)))
could be rewritten as (is (= [1 2 3] some-seq))
And actually the second version is more restrictive than the first.
The first one, if some-seq contains 4 or more elements, will pass if the first 3 elements are 1 2 3
The second will fail if some-seq contains anything other than 3 elements.
because when you call map
with 2 or more sequences, it stops when it reaches the end of the shortest sequence.
right, didn't even think of that (even though I'm pretty sure I used this attribute of map
in the past)
I still sometimes forget that Clojure defaults to value comparison on =
; too much time spent with Java and Common Lisp :<
Both of your examples rely on =
. Do you mean you are unused to being able to compare arbitrarily nested collections?
yes, I'm mostly used to reference comparisons for anything other than primitive values
Yes, =
and many other Clojure operations working on arbitrarily nested immutable data structures is an awesomely nice thing. You can even use them as set elements or keys in maps.
what do you mean by "them" in: > You can even use them as set elements or keys in maps. ?
You can use a vector, or a map, or a set, as a key inside of a map, as well as a value in a map.
e.g. { [1 2] :alive [7 4] :dead}
is a map that has vectors as keys
It isn't always useful to do so, but if you can think of a use for it, it works.
One use case would be in representing a 2-D or 3-D sparse structure, where the vectors represent positions
and the values represent objects located at those positions.
Yes, Clojure has a built-in memoize
function that can take any pure function that takes 1 or more immutable values as arguments, and memoize it.
and it is implemented just as you describe
i.e. I may have a map that's mapping a "person" to some "stuff" and not care what that "person" actually is, beyond that it can compare with =
You need to be cautious not to use any mutable stuff inside of such a collection if you want to use it as a set element or map key, because then the hashing and =
can break down, but Clojure's default immutable data structures makes it easy to avoid that, unless you are doing Java interop or things like that.
yeah, I'm actually doing Java interop a bit in a project I'm working on (that made me use clojure in the first place), and I'm generally isolating it as much as I can
In some cases I think that people write conversion code to convert Java mutable structures to Clojure immutable ones at the boundaries.
where it makes sense to do so.
Inverse of transients, so to speak.
hmm, in Common Lisp, there's a difference between (apply 'foo bar)
and (apply #'foo bar)
- the former will always call the function currently named foo
, and the latter will call the function that was the value of #'foo
when that expression was evaluated
I understand that (apply func data)
in Clojure is the equivalent of CL's (apply #'func data)
For the other, you could probably use @#’func (deref the var to get the function at a point in time), but I’m not sure why I would ever do that
@alexmiller I’ve done that with routes in the past, when I want them reloadable in dev mode.
yup, in CL you'd do that in places where you store functions that you want redefinable at runtime - say hooks
Just make a dynamic var?
@alexmiller let me give you an example from current Clojure project I'm working on - we have a key -> handler map that's floating around in a long-lived application
say I add a some-key -> some-fun entry there, because the handler I want to use is a named function
depending on the design, I might want for that map to pick up that the definition of some-fun has changed; however, if I naively pass some-fun to that map, it'll store the ref to a particular function definition at particular point in time
in CL, the usual way this is handled is by using the fact that apply
and funcall
accept both a function and a symbol (together known as "function designator")
if you apply
a function, you'll call that particular function; if you apply
a symbol, the call will go to the function currently defined under the name represented by that symbol
@temporal.pl sounds like a use-case for an atom
you can pass the atom to your function and deref it on each call to get the possibly updated value
sorry but isn't this just prepending #'
?
user=> (defn a [] :a)
#'user/a
user=> (def m {:a #'a})
#'user/m
user=> ((get m :a))
:a
user=> (defn a [] :b)
#'user/a
user=> ((get m :a))
:b
you don't need atom for this...
Hi everyone. I need a help
I converted a string to a JSON object, but now and I need get a value by the key. I have tried it using [cheshire.core :as json]
and [clojure.data.json :as jsons]
but whitout success.
for example, {"language":"Clojure", "paradigm":"functional"}
anyone knows how I can get the value by the key language
?
Or you can use the map directly as a function and pass the key as an arugment.
({"language":"Clojure", "paradigm":"functional"} "language")
above works great! even more idiomatic:
(:language (cheshire.core/parse-string some-json true))
true
being an optional param to cheshire that will change string keys to keyword keys
thanks!!! all options works fine. today is my third day working with Clojure. And my sixth months with Elixir. sometimes I`m get confused with two syntax .
Is there an empty?
that works on non-seq please? Using (or (nil? i) (and (coll? i) (empty? i)))
atm
Yes, but (coll? nil)
returns false so he needs the (or (nil? i) ..
test too.
for example I can run (:key map)
on a map, but why can i not run (0 array)
on clojure.lang.ArraySeq
?
0
is a java.lang.Number
java.lang.Number
cant implement clojure.lang.IFn
because java.lang.Number
is defined before IFn
You can see how keyword lookups work here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Keyword.java#L142
the cool thing about this is clojure is less "magic" than (:x m)
makes it look - that's really the same syntax as a standard function call, the trickery is in a keyword being a function
Well, there are some integers, floating point numbers, characters, strings, namespaces, and symbols down there, too (not a complete list of non-function things) 🙂
eh, those are all ultimately just binary functions 🙂
any idea why most of my files would work fine, but one loads without errors, but exports nothing?
I just get "no such var" for all of its symbols.
Clojure on Java? If so, what method are you using to load your files?
a mix of clj and cljc files. some of each type are working fine.
Also, the Eastwood lint tool can find some kinds of problems, e.g. mismatches between file names and the namespace defined within them that can cause problems for some tools.
Do you have any namespace or file name that is the same between two files, but one has a .clj suffix, and the other has .cljc? In such a case, Clojure/Java will ignore the .cljc file.
I can (use '[zm.core :as c] :reload-all)
at the repl and it works fine, but there's nothing loaded.
ah, there we go.
I think there is a :verbose keyword option for that, IIRC, that shows what is actually loaded.
empty template-created core.clj
file getting in the way T_T
thanks, that was a baffling error.
Given that stack traces show the file name core.clj
for functions in Clojure core, I would recommend considering avoiding the use of the file name core.clj
in your own projects, to make it easier for you to figure out which file the functions in the stack trace come from.
yeah, I've moved it to something more meaningful. I've still got a core.cljs
but that's used in a bunch of places so I'm not going to touch it.
a fun thing, is if you run lein new foo.bar/baz
it will create foo/bar/baz.clj
instead of a core.clj
user=> (isa? (try (assert false) (catch Error e (class e))) Error)
true
- isa? knows that the class of an AssertionError is a descendent of ErrorExceptions are different though
user=> (isa? (try (/ 1 0) (catch Exception e (class e))) Error)
false
user=> (isa? (try (/ 1 0) (catch Exception e (class e))) Exception)
true
what's the class of *e
it might be an Exception, for example
I know what *e is, I mean in your specific context
you could check them individually, or check for Throwable
which is superclass to both
yeah, that doesn't derive from Error so isa? won't recognize the relationship, but checking both or checking Throwable would
maybe this helps
user=> (isa? Exception Error)
false
user=> (isa? Exception Throwable)
true
user=> (isa? Error Exception)
false
user=> (isa? Error Throwable)
true