clojure as a language and as a community has lots of opinions about how programs should be written. especially if you're bringing ideas and practices from another language/ecosystem, I could see how it might be hard to tell if an idea is bad practice, uncommon, or good practice (and it's simply unclear how to implement it because it's a new language)
I have not completely figured out how to structure apps yet .. I have a thing now that is partially using integrant and another using mount .. both are interesting
The thing I have not figured out yet, or at least not have an opinion about, is whether an app should have global state or not ..
In my Go code I heavily avoid it .. start your data/tree/state from main and pass it around basically
right, that's what I do in nontrivial clojure apps (and all libraries) as well
perhaps for dev tooling purposes putting the running state in a def
but using globals for app data in cljs is pretty common
especially as a beginner, i think some of those state management apps can really hinder making cool things as people stress about the best way to inject something they never are gonna fake either way.
Why is it that (= [1 2 3] (seq [1 2 3]))
evals to true
despite the differing types of the arguments but
(defrecord Foo [a b])
(= (Foo. 1 2) {:a 1, :b 2})
evals to false
(which from my understanding, is only because the types are different)?check out (doc =)
and the docstring of (doc defrecord)
that second one is quite long with some technical bits but the relevant bits are > In addition, defrecord will define type-and-value-based =, and will defined Java .hashCode and .equals consistent with the contract for java.util.Map.
and a lovely bit of documentation by andy fingerhut with tons of information, caveats, examples, etc. https://clojure.org/guides/equality
all of that kind of just describes the conundrum that you're talking about. Clojure is coded around a few core abstractions and the types of collections is not emphasized. depending on operations, you can end up with very different types. and when checking for equality its just the same elements in the same order. records produced from defrecord
is an explicit step that imbues values with a type and that type is consequently honored when checking for equality.
records is a way to add add protocol implementations to values. because these values could behave in drastically different ways under the same function, they include the type information in the equality check
good info @dpsutton, thanks
Me a month ago: threading macros look dumb iโll avoid them. Me today: THREAD ALL THE THINGS.
this is the way
Slack needs a Mandalorian emoji :)
Someone's been watching the Mandalorian ๐
;)
When running
(run-jetty (wrap-defaults app site-defaults) {:port (:port env)})
where the :port has value 80.
I got the following error:
1. Unhandled java.net.SocketException
Permission denied
Net.java: -2 <http://sun.nio.ch.Net/bind0|sun.nio.ch.Net/bind0>
Net.java: 455 <http://sun.nio.ch.Net/bind|sun.nio.ch.Net/bind>
Net.java: 447 <http://sun.nio.ch.Net/bind|sun.nio.ch.Net/bind>
ServerSocketChannelImpl.java: 227 sun.nio.ch.ServerSocketChannelImpl/bind
ServerSocketAdaptor.java: 80 sun.nio.ch.ServerSocketAdaptor/bind
ServerConnector.java: 345 org.eclipse.jetty.server.ServerConnector/openAcceptChannel
ServerConnector.java: 310 org.eclipse.jetty.server.ServerConnector/open
AbstractNetworkConnector.java: 80 org.eclipse.jetty.server.AbstractNetworkConnector/doStart
ServerConnector.java: 234 org.eclipse.jetty.server.ServerConnector/doStart
AbstractLifeCycle.java: 72 org.eclipse.jetty.util.component.AbstractLifeCycle/start
Server.java: 386 org.eclipse.jetty.server.Server/doStart
AbstractLifeCycle.java: 72 org.eclipse.jetty.util.component.AbstractLifeCycle/start
jetty.clj: 172 ring.adapter.jetty/run-jetty
I tried if I run the app with sudo then there is no problem. It looks like that I need some privilege to start the web server at the port 80? How?
Thanks for your help!You answered it yourself. You need root permissions to open any port < 1024
My problem is solved by change the port to 8443 then it works.
The solution was found at https://stackoverflow.com/questions/42014227/permission-denied-errors-when-listening-on-https-ports-with-ring-on-heroku
"You are getting permission denied because it is trying to bind to the default SSL portย *443*ย which you needย *sudo*ย access for ports less thanย *1024"*
https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html
@dromar56 Thanks!
On the web, you'll often find that people use 8000 or 8080 as default ports for non-production web servers, pretty much because they look like 80, but are non-privileged
Quering logic How would I turn a list of predicates into a filter function, reducing the list of predicates with and/or?
runQuery :: List (Device -> Bool) -> List Device -> List Device
I've tried every-pred
but I don't know how to convert my list into just arguments (I see the irony of having this problem in a Lisp). Either way, I need to be able to discern between "anding" and "oring" these predicates.
Example desired use:
"Give me all devices whose name are 'Example' OR whose serial number starts with '123'".
(run-query partially-applied-predicate-functions list-of-devices)
EDIT: I'm primarily looking for an idiomatic way of performing such logic, however that looks in Clojure.(fn [predicates]
(let [matches-every (apply every-pred predicates)]
(fn [devices]
(filter matches-every devices))))
That makes a lot of sense. Thank you for your time Chris, appreciated ๐
with every-pred
it does "anding", you can use some-fn
for "oring"
Hi everybody! I just update my todo backend repo on dedicated branch with the Juxt Clip library (Component/Integrant alternative): https://github.com/PrestanceDesign/todo-backend-clojure-reitit/tree/clip If some are interested to see how it is configured, how it works... ๐
Hi all, this is a clojurescript questions. I am able to run the following code successfully with the data being read and logging to the console. However I want to be able to use the data and eventually plot it. What is the best way to store this data so that I can use it?
(def data-local
(-> d3
(.csv "timeseries.csv" )
(.then #(js/console.log %))
(.catch #(js/console.log "Error loading file"))))
store for how long, and for who to access it?
console.log
returns undefined
, so data-local
is a promise to undefined
. You can log as a side-effect, but your .then
still needs to return the data being logged in order to assign it to data-local
.
if you just mean inside the app until the user exits, you can replace the console.log with something that stores the data, or provides it to some callback / channel
@matt.wistrand what console.log returns doesn't even matter for "data-local", it just gets the return value of .then
data-local
is a promise and wanted it to be the data itself
I believe I am not really understanding how promises work. but I think this will help. https://clojurescript.org/guides/promise-interop
that's just not how using promises works - you need to call the code that wants to use the data inside the .then
callback, or store the value for later, or put it on a channel
In this case, the return value of .then
is the result of calling console.log
, which is undefined
.
I thought .then returned immediately...
okay thanks. I think I get it. I need to have a def somewhere inside the then block that will store the value for me to use later.
eg. how would chaining .then
calls work if .then
returned the value that the callback returns?
Iโm not being precise; it returns a promise to the result of executing its callback.
I'm reading the docs to double check, and they are saying .then
returns a new promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
right, what I'm saying that even that doesn't get what @dilzeem wants - he wants the value to end up in the data-local def, and you need something more complicated to make that happen
that's one way to do it, but then how does your other code decide when to try to use that def?
Right. The .then
would either need to be removed and console.log
not called as part of the def
(preferable), or the .then
would have to call console.log
and then return the data (less preferable).
returning the data from the promise callback is still only punting the root issue - it's still in a promise that way
hmm is there a way for me to have data-local
contain the actual data?
True
there needs to be some explicit handing of the data out of "promise world" into other code, or lifting of the other code to be called in the promise callback
this is a common problem with async execution mechanisms (not just with js), the common choice is to either "lift" all code that wants data produced async into async calls (put it in the function arg to .then
in this case), or to use some global data store (in cljs an atom perhaps?) so that other code initiated by some timeout or user action can see it (if it's ready)
I don't really need the console.log
I was just having it there to see if it was getting the csv file.
consider that all it takes to do that lift is to have a function that takes the data as an argument, that's a totally normal way to write clojure code already
right, that was never the real issue
Hmm interesting. Thanks for the explanation. I think I have clearer understanding now.
For anyone else who wants to solidify what was discussed above, this was useful: https://martinklepsch.org/posts/working-with-promises-in-clojurescript-repls.html
I'm struggling to get a remote repl working between Linux running the remote and IntelliJ connecting. Anyone got any pointers?
apt-get install leiningen; export LEIN_REPL_HOST=172.16.16.34; lein repl :headless :port 7888.
I found out the random dude trying to access my box was from Russia so I returned an image of a bear on a bicycle xD
maybe better for off-topic x]
Okay, silly question, does ->
mean anything special when attached to the front of a deftype
?
(In the same way that a .
at the end means new
)
> Given (deftype TypeName ...), a factory function called ->TypeName will be defined, taking positional parameters for the fields
(from (doc deftype)
)
Like, if I do:
(deftype Foo [])
(->Foo)
nothing special, but defrecord
autogenerates a function called ->Ctor
for a defrecord called Ctor
Ah, okay, thanks.
which is a convenience for Ctor.
it also creates a function called map->Ctor
which allows you to create a Ctor
by using a named map
(I was only finding stuff on the threading macro from google. Sorry about the silly-ness. ๐ )
no worries at all ๐ its the entire point of the channel
deftype
only does ->Ctor
, but not map->Ctor
lol, fair. ๐
you can check out (source deftype)
and then (source clojure.core/build-positional-factory)
if you want to see it
(let [fn-name (symbol (str '-> nom))
and then later
(defn ~fn-name`
Oh odd, I'm actually not seeing in the docs what the difference between Ctor.
and ->Ctor
is.
->Ctor
is a function
Ctor.
is a syntax sugar for new Ctor
OOOHH..>That makes sense.
Thanks.
(so the first one is a value, the other one isn't)
to be precise, Ctor.
isn't a thing, only (Ctor. ..)
RIght, because its a macro
reader macro*
ish
Oh, its not a reader macro?
That's interesting.
it's... syntax sugar that's applied by the macroexpander
it's a bit of its own thing, similar to how Foo/bar
can expand to . Foo bar
definitely not a reader macro
it's not applied at read time
Ah, okay.
So it's more like format-id
in the racket world.
(Except that users don't have access to making new ones...probably...)
Still, cool, thanks. ๐
i'm not familiar with format-id
to confirm
if you're curious, this is how it's implemented in the macroexpander (this is a clojure version) https://github.com/clojure/tools.analyzer.jvm/blob/master/src/main/clojure/clojure/tools/analyzer/jvm.clj#L124-L165 invoked from https://github.com/clojure/tools.analyzer.jvm/blob/master/src/main/clojure/clojure/tools/analyzer/jvm.clj#L209-L212
Ah, yes, I was curious, thanks for sharing.
That looks a lot like if format-id
was baked into the racket macro system, rather than being user programmable. ๐
and yes, you're right in assuming that the user doesn't have access to this
Ya...programs with user defined datam->syntax
would be awfully confusing without some kind of hygiene system.
It'd be pretty hard to predict what identifiers did what. ๐
(IIRC, the clojure macro system doesn't have a hygiene system per se, more just sugar for using namespaced qualified identifiers.)
indeed
and autogensym
That to.
Anyway, thanks again for the feedback.