beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
phronmophobic 2020-12-03T00:03:30.362700Z

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)

st3fan 2020-12-03T00:25:25.363600Z

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

st3fan 2020-12-03T00:26:11.364100Z

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 ..

st3fan 2020-12-03T00:26:35.364700Z

In my Go code I heavily avoid it .. start your data/tree/state from main and pass it around basically

2020-12-03T00:28:25.365200Z

right, that's what I do in nontrivial clojure apps (and all libraries) as well

2020-12-03T00:28:46.365700Z

perhaps for dev tooling purposes putting the running state in a def

2020-12-03T00:29:14.366100Z

but using globals for app data in cljs is pretty common

dpsutton 2020-12-03T00:30:39.366900Z

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.

โ˜๏ธ 1
Jack Arrington 2020-12-03T01:09:52.369200Z

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)?

dpsutton 2020-12-03T01:17:54.369900Z

check out (doc =) and the docstring of (doc defrecord)

dpsutton 2020-12-03T01:18:17.370400Z

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.

dpsutton 2020-12-03T01:21:53.370900Z

and a lovely bit of documentation by andy fingerhut with tons of information, caveats, examples, etc. https://clojure.org/guides/equality

dpsutton 2020-12-03T01:27:59.374200Z

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.

dpsutton 2020-12-03T01:29:14.375300Z

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

Jack Arrington 2020-12-03T02:00:02.375700Z

good info @dpsutton, thanks

st3fan 2020-12-03T02:03:56.376800Z

Me a month ago: threading macros look dumb iโ€™ll avoid them. Me today: THREAD ALL THE THINGS.

๐Ÿ‘ 3
alexmiller 2020-12-03T02:35:04.378600Z

this is the way

3
practicalli-john 2020-12-03T10:16:16.383700Z

Slack needs a Mandalorian emoji :)

seancorfield 2020-12-03T03:02:53.378700Z

Someone's been watching the Mandalorian ๐Ÿ™‚

alexmiller 2020-12-03T03:08:04.378900Z

;)

yubrshen 2020-12-03T04:21:18.379400Z

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!

solf 2020-12-03T04:32:21.380500Z

You answered it yourself. You need root permissions to open any port < 1024

๐Ÿ™ 1
yubrshen 2020-12-03T04:33:29.381100Z

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"*

solf 2020-12-03T04:33:33.381300Z

https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html

๐Ÿ™ 1
yubrshen 2020-12-03T04:35:40.381500Z

@dromar56 Thanks!

solf 2020-12-03T04:37:20.382200Z

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

Fredrik Holmqvist 2020-12-03T12:28:54.390900Z

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 -&gt; Bool) -&gt; List Device -&gt; 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.

2020-12-03T12:42:42.393Z

(fn [predicates]
     (let [matches-every (apply every-pred predicates)]
       (fn [devices]
         (filter matches-every devices))))

Fredrik Holmqvist 2020-12-03T12:44:47.393300Z

That makes a lot of sense. Thank you for your time Chris, appreciated ๐Ÿ™‚

2020-12-03T12:46:37.393600Z

with every-pred it does "anding", you can use some-fn for "oring"

โœ… 1
borkdude 2020-12-03T15:50:43.394600Z

https://twitter.com/asamonek/status/1334497845752324098

๐Ÿ‘ 1
2020-12-03T17:50:22.396800Z

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... ๐Ÿ˜‰

๐Ÿ‘ 1
dilzeem 2020-12-03T18:44:21.399200Z

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
  (-&gt; d3
      (.csv "timeseries.csv" )
      (.then #(js/console.log %))
      (.catch #(js/console.log "Error loading file"))))

2020-12-03T18:48:04.400100Z

store for how long, and for who to access it?

mjw 2020-12-03T18:48:38.401100Z

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.

2020-12-03T18:49:26.401900Z

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

2020-12-03T18:50:09.402800Z

@matt.wistrand what console.log returns doesn't even matter for "data-local", it just gets the return value of .then

dilzeem 2020-12-03T18:50:50.403800Z

data-local is a promise and wanted it to be the data itself

dilzeem 2020-12-03T18:51:41.405300Z

I believe I am not really understanding how promises work. but I think this will help. https://clojurescript.org/guides/promise-interop

2020-12-03T18:51:42.405400Z

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

mjw 2020-12-03T18:52:44.405800Z

In this case, the return value of .then is the result of calling console.log, which is undefined.

2020-12-03T18:53:11.406100Z

I thought .then returned immediately...

dilzeem 2020-12-03T18:54:46.406800Z

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.

2020-12-03T18:55:01.406900Z

eg. how would chaining .then calls work if .then returned the value that the callback returns?

mjw 2020-12-03T18:55:17.407100Z

Iโ€™m not being precise; it returns a promise to the result of executing its callback.

2020-12-03T18:55:26.407300Z

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

2020-12-03T18:56:07.407600Z

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

2020-12-03T18:56:34.408100Z

that's one way to do it, but then how does your other code decide when to try to use that def?

mjw 2020-12-03T18:57:31.408300Z

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).

2020-12-03T18:58:22.408800Z

returning the data from the promise callback is still only punting the root issue - it's still in a promise that way

dilzeem 2020-12-03T18:58:47.409300Z

hmm is there a way for me to have data-local contain the actual data?

mjw 2020-12-03T18:59:02.409400Z

True

2020-12-03T18:59:10.409600Z

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

2020-12-03T19:01:33.411700Z

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)

dilzeem 2020-12-03T19:01:46.411800Z

I don't really need the console.log I was just having it there to see if it was getting the csv file.

2020-12-03T19:02:21.412400Z

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

2020-12-03T19:04:24.412900Z

right, that was never the real issue

dilzeem 2020-12-03T19:04:43.413400Z

Hmm interesting. Thanks for the explanation. I think I have clearer understanding now.

dilzeem 2020-12-03T19:57:08.414300Z

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

daboone72 2020-12-03T22:41:43.415400Z

I'm struggling to get a remote repl working between Linux running the remote and IntelliJ connecting. Anyone got any pointers?

daboone72 2020-12-03T22:42:49.415900Z

apt-get install leiningen; export LEIN_REPL_HOST=172.16.16.34; lein repl :headless :port 7888.

sova-soars-the-sora 2020-12-03T23:00:25.416400Z

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

sova-soars-the-sora 2020-12-03T23:00:50.416700Z

maybe better for off-topic x]

2020-12-03T23:21:25.417300Z

Okay, silly question, does -&gt; mean anything special when attached to the front of a deftype?

2020-12-03T23:21:39.417700Z

(In the same way that a . at the end means new)

dpsutton 2020-12-03T23:22:13.418200Z

> Given (deftype TypeName ...), a factory function called ->TypeName will be defined, taking positional parameters for the fields

๐Ÿ˜ฎ 1
dpsutton 2020-12-03T23:22:32.419Z

(from (doc deftype))

2020-12-03T23:22:32.419100Z

Like, if I do:

(deftype Foo [])
(-&gt;Foo)

bronsa 2020-12-03T23:22:42.419400Z

nothing special, but defrecord autogenerates a function called -&gt;Ctor for a defrecord called Ctor

2020-12-03T23:22:50.419700Z

Ah, okay, thanks.

bronsa 2020-12-03T23:22:53.420Z

which is a convenience for Ctor.

bronsa 2020-12-03T23:23:07.420300Z

it also creates a function called map-&gt;Ctor which allows you to create a Ctor by using a named map

2020-12-03T23:23:08.420400Z

(I was only finding stuff on the threading macro from google. Sorry about the silly-ness. ๐Ÿ™‚ )

dpsutton 2020-12-03T23:23:20.420600Z

no worries at all ๐Ÿ™‚ its the entire point of the channel

bronsa 2020-12-03T23:23:43.421200Z

deftype only does -&gt;Ctor, but not map-&gt;Ctor

2020-12-03T23:24:02.421300Z

lol, fair. ๐Ÿ™‚

2020-12-03T23:24:30.421900Z

Okay, thanks @bronsa & @dpsutton

dpsutton 2020-12-03T23:25:46.422100Z

you can check out (source deftype) and then (source clojure.core/build-positional-factory) if you want to see it

dpsutton 2020-12-03T23:26:12.422300Z

(let [fn-name (symbol (str '-&gt; nom)) and then later (defn ~fn-name`

2020-12-03T23:26:53.422900Z

Oh odd, I'm actually not seeing in the docs what the difference between Ctor. and -&gt;Ctor is.

bronsa 2020-12-03T23:27:19.423100Z

-&gt;Ctor is a function

bronsa 2020-12-03T23:27:38.423500Z

Ctor. is a syntax sugar for new Ctor

2020-12-03T23:27:46.423700Z

OOOHH..>That makes sense.

2020-12-03T23:27:47.423900Z

Thanks.

bronsa 2020-12-03T23:27:59.424200Z

(so the first one is a value, the other one isn't)

bronsa 2020-12-03T23:28:22.424600Z

to be precise, Ctor. isn't a thing, only (Ctor. ..)

2020-12-03T23:28:35.424900Z

RIght, because its a macro

2020-12-03T23:28:43.425200Z

reader macro*

bronsa 2020-12-03T23:28:45.425400Z

ish

2020-12-03T23:28:52.425600Z

Oh, its not a reader macro?

2020-12-03T23:29:01.426Z

That's interesting.

bronsa 2020-12-03T23:29:20.426300Z

it's... syntax sugar that's applied by the macroexpander

bronsa 2020-12-03T23:29:48.426800Z

it's a bit of its own thing, similar to how Foo/bar can expand to . Foo bar

bronsa 2020-12-03T23:29:56.427Z

definitely not a reader macro

bronsa 2020-12-03T23:29:59.427200Z

it's not applied at read time

2020-12-03T23:30:21.427600Z

Ah, okay.

2020-12-03T23:30:37.428Z

So it's more like format-id in the racket world.

2020-12-03T23:31:01.428600Z

(Except that users don't have access to making new ones...probably...)

2020-12-03T23:31:14.428800Z

Still, cool, thanks. ๐Ÿ™‚

bronsa 2020-12-03T23:34:03.429200Z

i'm not familiar with format-id to confirm

2020-12-03T23:36:10.430300Z

Ah, yes, I was curious, thanks for sharing.

2020-12-03T23:36:51.431100Z

That looks a lot like if format-id was baked into the racket macro system, rather than being user programmable. ๐Ÿ™‚

bronsa 2020-12-03T23:36:52.431200Z

and yes, you're right in assuming that the user doesn't have access to this

2020-12-03T23:38:13.432300Z

Ya...programs with user defined datam-&gt;syntax would be awfully confusing without some kind of hygiene system.

2020-12-03T23:38:28.432700Z

It'd be pretty hard to predict what identifiers did what. ๐Ÿ™‚

2020-12-03T23:39:10.433400Z

(IIRC, the clojure macro system doesn't have a hygiene system per se, more just sugar for using namespaced qualified identifiers.)

bronsa 2020-12-03T23:39:22.433700Z

indeed

bronsa 2020-12-03T23:39:30.434Z

and autogensym

2020-12-03T23:39:56.434200Z

That to.

2020-12-03T23:40:35.434900Z

Anyway, thanks again for the feedback.