This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-28
Channels
- # aws (5)
- # aws-lambda (1)
- # beginners (133)
- # boot (1)
- # cljsrn (1)
- # clojure (28)
- # clojure-austin (3)
- # clojure-italy (2)
- # clojure-spec (17)
- # clojure-uk (18)
- # clojurescript (38)
- # cursive (6)
- # datomic (6)
- # figwheel (1)
- # graphql (1)
- # klipse (1)
- # leiningen (1)
- # off-topic (13)
- # onyx (30)
- # re-frame (44)
- # reagent (7)
- # shadow-cljs (77)
- # spacemacs (7)
Is there any place that I can find more about using Java IO channels in Clojure? Every time I search something related to Channel or Async or Non-blocking, I get something related to core.async and that’s not what I want ;(
I want to do async non-blocking IO in Clojure using the Java methods for that (unless there’s a better way built into Clojure itself)
@lvbarbosa why would any of the info be clojure specific?
other than interop, which is the same for any class you use
my typical approach is to use google to figure out how to do the thing in java, then translate
I am specifically thinking about this method: https://docs.oracle.com/javase/9/docs/api/java/nio/channels/AsynchronousSocketChannel.html#read-java.nio.ByteBuffer-long-java.util.concurrent.TimeUnit-A-java.nio.channels.CompletionHandler- I am not sure how to pass a callback function there. Do I need to implement that interface in a custom type?
you can use reify or proxy or defrecord or deftype to make something implementing that interface
if it's one off, probably reify
(reify CompletionHandler (failed [this exc att] (log/error "completion handler failed" (pr-str exc) att)) (completed [this result att] ...))
got it
@ashnur
(rand-nth (clojure.string/split (slurp "words.txt") #"\n"))
(assuming words.txt in root dir of project)
Here's one you can save to your local dir: https://raw.githubusercontent.com/dwyl/english-words/master/words.txt
Or you can slurp it from the web.
(rand-nth (clojure.string/split (slurp "") #"\n"))
the docs for helpshift/faker seem straightforward https://github.com/helpshift/faker
yeah, i can't require it, it just says No such namespace: helpshift/faker.generate, could not locate helpshift_SLASH_faker/generate.cljs, helpshift_SLASH_faker/generate.cljc, or JavaScript source providing "faker.generate"
oh, if you are using cljs that's different yeah
i am sorry, when i was learning javascript in 2012, substack wrote a tool called browserify that reads the nodejs specific stuff and replaces with with browser modules that provide the same api, so i was expecting something similar to be in place here too
the ones that work on both use cljc files https://github.com/clojure/clojurescript/wiki/Using-cljc
https://github.com/bahmutov/express-service/blob/master/src/patch-sw-environment-for-express.js
https://glebbahmutov.com/blog/run-express-server-in-your-browser/#express-inside-serviceworker
although in any case, it's not actually express running in the browser, just an express-like thing 😛
i've got a map with strings as keys and vectors of strings as values. i'm using the elements of the vectors as keys again for the map. would it make sense to use keywords as keys and vectors of keywords as values instead?
I don't see why that would be useful
fair enough. guess i'm not 100% when to use the keyword data type - i often see it used as map keys
it makes sense when the value is a literal, or if you have a single key that you want to use as a function and look up in various maps
if what you have is a map from strings to vectors of strings, I don't see how converting them all to keywords would help - it seems like it would just introduce a bunch of needless conversions
conversions between?...
strings to keywords then back to strings
or is it arbitrary whether they are keywords or strings?
i think so far it is arbitrary. i can't think of any reasons why i need them as strings. but i can't think of any reason why i'd want them as keywords, either.
so maybe i'm just making a mountain out of a molehill
+user=> (take 100 (iterate (comp rand-nth {"foo" ["bar"] "bar" ["baz" "quux"] "baz" ["foo" "bar"] "quux" ["foo"]}) "foo"))
("foo" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "baz" "bar" "baz" "bar" "baz" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "baz" "bar" "baz" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "baz" "bar" "baz" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "baz" "foo" "bar" "baz" "foo" "bar" "quux" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "quux" "foo" "bar" "baz" "bar" "quux" "foo" "bar" "quux" "foo")
that's what my map looks like now... the elements of the vectors are again themselves keys. i want to represent a graph but have all the nodes as top level keys.
that's called an adjacency-list
what does the (take 100 (iterate...
example illustrate?
I'd decide what the type of the identifiers should be based on the use case - all else being equal why not numbers?
hmm, yeah. why not.
it illustrates that you can do arbitrary navigation elegantly with clojure built ins
without the (take 100 ...) wrapper, it would be infinite
so printing it would never finish
ah - because it's 'lazy'?
because it's lazy and also has no stop condition
this is a common situation with iterate - it needs a consumer that knows when to stop
makes sense.
hey, can i ask another question? in python we append an underscore to avoid collision/(shadowing?). is that an idiom in clojure or do namespaces make it unnecessary?
typically we avoid shadowing, but no, we don't tend to use underscores
if you have two things that are related, you'll sometimes see pairs like foo*
followed by foo
, or foo
followed by foo'
then foo''
etc.
but if i just want a local variable that happens to share a name with a clojure built-in, i should think of a synonym?
since scope is very explicit, you can shadow as long as it's in a small scope and you know you don't need the original
it's good to avoid naming data with the same name as a commonly used function (eg. name
or count
) because that can lead to subtle bugs that are hard for readers to see
i see. thank you!
It is my understanding that in clojure we do not technically assign a value to a variable
we are actually binding a value to a variable
. Would this statement be correct?
Piggybacking off the above, I notice that the word variable and symbol are used interchangeably. I believe in this case it would be correct, but would it be more accurate to say that there is a hierarchy that would look like this:
symbols
|
|
variables
As in, all variables are symbols, but not all symbols are variablessymbols are mapped to vars in namespaces
when unquoted, they are resolved when used
they are also mapped to bindings in local contexts (let, fn, loop, etc.) which doesn't involve mutable vars
a var in a namespace is not a binding, it's a mutable container holding a value inside a mutable hash
by default, a symbol is resolved into a var, which is resolved into whatever that var holds:
map
#object[clojure.core$map 0x7d7658b5 "clojure.core$map@7d7658b5"]
but you can also refer to the symbol itself:
'map
map
(type 'map)
clojure.lang.Symbol
it's used to access a local binding, if applicable, after that it's used to look up a var
locals take precedence, and are not vars
@tkjone also, just to be clear, symbols are never automatically resolved, but there are specific contexts where resolution happens
for example ('+ 1 2) returns 2, because the symbol is not resolved
Okay, so using this as an example:
(def name "Greg")
We would say that
* 'name
is a symbol
* name
is a variable (or a resolved symbol)
But is the example above not a binding?hmm - it is a namespaced global binding actually, right
Because, and this could be the wrong way to put it, there is no way to re-assign name
. I would have to call (def name "James")
to change it
that reassigns name!
correct
it mutates the var holding "James"
(which shadows clojure.core/name which is a function)
I guess, I am wondering, and this is the weeds, what clojure is doing under the hood - does it redeclare the whole thing?
it mutates a var
literally there's a mutable container of type clojure.lang.Var, the namespace owns a mutable hash-map from symbols to vars
okay, so the container name
is not reassigned a new spot in memory, I am just replacing it's value
right
unless you destroy and recreate the ns first, or remove the var from the ns first (clojure.tools.namespace does things like this)
hmmm, perhaps some of my confusion also comes from the fact that when I do this:
(def name "Greg")
We would say that the root binding
of name
is "Greg"
- correct? But at the same time, the above is assigning and not binding? Sorry guys, just want to make this clear for myself 😞. And to give some background, I notice that some article like to draw a distinction between assigning as one would do in JS but in Clojure we are binding.root bindings only matter for dynamic vars
and cljs doesn't use vars does it? - it's a whole other thing going on there
Sorry, ClojureScript does not use vars? This is article I am referring to: http://clojurebridge-berlin.org/community-docs/docs/clojure/def/ in which they call the above var binding
sorry, it does use vars now, my info was out of date
So a root binding
only matters for dynamic vars
but non-dynamic var
do have a root binding
correct? https://clojure.org/reference/vars
yes - in practice you don't usually see root bindings mentioned unless you are dealing with dynamic vars, but both dynamic and static vars have root bindings
so when a value is looked up, you either find it in a local scope (not reified as an object, not mutable) or it's found via the namespace (mutable, reified via ns and var objects)
Nice, so that makes sense now and with that in mind, why is there a distinction drawn between assigning
and binding
in clojure? I am not sure what the difference is 😞
an assignment can be changed later
(via different args to a function or recur)
but it can't be mutated mid usage - it's just a value
in a repl, if you are changing code and don't want to restart, you need to be able to redefine things at namespace scope
for local scopes (let blocks, functions, etc.) there's no simple repl driven workflow that would need to do that, and there's a lot of things that are simpler by lacking that feature
Okay, I think I get it now. assignment could be understood as this:
temp = 0
function incTemp () {
temp = 5
}
We are re-assigning in this case, but unless you were using a dynamic-var
and the binding form
you would not be able to do the above - hence assignment operators
eh, you can use intern
anywhere
it's a bad idea, but you can do it
or def anywhere to replace the value, if you know the var name at compile time (intern is more flexible) - but we understand as a community that things like this are typically signs that you are doing it wrong
but that only works for namespace level stuff - for locals there's no object to mutate - there's values and their value already propagated to the usage sites which are not accessible without doing not portable hacks
So is the idea of assigning
vs. binding
more of an ephemeral thing? By this I mean, there are ways to mutate the vars values, but in Clojure its just a frowned upon practice.
yeah - if that's the distinction you are making - but I've also seen fn args or let bindings use both terms assigning / binding so that terminology is a bit imprecise
Exactly, yes, I just see a distinction being made, but I never see any examples of assignment vs binding that would suggest it is a structurally different thing
(unless I've been misunderstanding that stuff, which is also possible)
Is there an idiomatic way to handle errors in Clojure? It seems like most of the suggestions involve exceptions. I just ran across the cats library as well which looks very neat.
there are many alternatives, none are common, and no matter what you use you will also have to deal with exceptions
Looking over the relationship between a symbol and a var, I am wondering if this is correct: * symbols are mapped to vars in the namespace So if I do something like this:
(def my-name "Jay')
and then I ran (ns-map 'current-ns)
I would get all the mappings including the one I did above which would look like this:
name #'user/my-name
Which means that my-name
is the symbol and it is mapped to the var user/name
. Yes?@tkjone yeah, that matches my understanding (although grain of salt; it's not something that comes up much for me).
Thanks all, his has been a huge help!
You've probably already seen it, but https://clojure.org/reference/vars gets into some of this stuff.