Fork me on GitHub
#beginners
<
2018-03-13
>
nakiya01:03:35

Perhaps a stupid question. But, I’ve been reading about spec and wondering why (if it’s such a good idea) libraries don’t seem to support it. Any of the libraries I’ve used so far didn’t mention anything about spec. Am I missing something?

noisesmith01:03:19

most libraries haven't had big rewrites since spec came out, spec is very new

nakiya01:03:57

But wouldn’t spec be a great feature to add to existing libraries? And can’t you partially add specs (For example, at the interfaces)?

noisesmith01:03:07

I'm not saying it's neccessarily a bad idea, I'm saying this is why it hasn't happened

noisesmith01:03:16

most clojure libraries don't need to be updated very often

nakiya01:03:22

most clojure libraries don't need to be updated very often This is something that I’ve noticed also. Some of the recommended libraries were last updated 3/4/5 years ago. Makes me pause a bit before I use them. What is the reason for that really?

noisesmith01:03:37

because they operate on immutable data or stable java interfaces

noisesmith01:03:06

if the world doesn't change underneath them (even for security updates you would just update the java lib yourself, no need to change the clojure lib)

noisesmith01:03:38

so unlike many ecosystems, in clojure you really do see code that is seemingly "done"

nakiya01:03:10

Wow, makes sense when you explain like that. That’s a huuuuge +++ isn’t it?

noisesmith01:03:36

indeed, it's a big payoff of good decisions in the design of clojure (and java and the jvm)

noisesmith01:03:48

(and you'll notice cljs is less stable and has more deployment churn, because it's built on shakier ground)

noisesmith01:03:26

most of clojure.core isn't covered by spec

Michael Fiano01:03:04

Well I've been using Common Lisp exclusively for over a decade, and I don't have any other experience with any other languages for the most part. I have never used Java or even the JVM. I am interested in learning Clojure if only for the JVM platform to expose my code to more people and to interoperate with more code (Java), but I was just wondering how hard of a time I am going to have learning everything all at once. I'm a game developer, with over a decade of Common Lisp libraries for writing raw OpenGL games (no frameworks or engines used) and it doesn't really look like Clojure has raw bindings for OpenGL or SDL2, so that's one problem already outside of learning the JVM, Java, Clojure, etc

mfikes01:03:55

@duminda Spec is also still in alpha

noisesmith01:03:08

@mfiano: yeah, clojure won't have raw bindings to just about anything - the closest will be a java lib which we use via interop, and that lib might have individual implementations for various platforms but most of the code is going to be jvm specific, not platform direct bindings to libs

noisesmith01:03:24

it's the tradeoff of a platform that emphasises portability - you get something that is easy to deploy in a self contained way, on many targets, but direct low level access to any of those is going to be rare

mfikes01:03:43

Also, worth mentioning, if you learn Clojure, you essentially know ClojureScript, which implies another whole slew of targets that are available to you

Michael Fiano02:03:26

Ok, thanks. I'm not sure if I'm ready to give up Common Lisp for game development yet if working with the GPU and the inherent windowing toolkits at a low level is going to be difficult

noisesmith02:03:26

it's possible - there's just more abstraction layers - and clojure isn't as oriented to that kind of low level programming as common lisp either

noisesmith02:03:47

@mfiano: on the other hand, if you want to make a service that stays running for a long time, performs well, and can directly use libs for the web/ services ecosystem (REST apis, kafka, zookeeper, cassandra, etc. etc.) - clojure is a great fit for that world

Michael Fiano02:03:06

Ok, it's still an interesting language I'd like to get familiar with - Clojure that is.

noisesmith02:03:45

I think it's great and being able to work with it professionally has been awesome - but it's definitely better at some niches than others 😄

Michael Fiano02:03:13

By the way, I'm new here and I haven't mentioned this yet. I coordinate the annual Lisp Game Jam, and I haven't really announced it anywhere yet, but this year it's April 20-30th. I hope to see some Clojurians there next month 🙂 https://itch.io/jam/lisp-game-jam-2018

noisesmith02:03:09

cool - you might want to mention that on #announcements

nakiya02:03:36

What’s the best way to read last n lines from a file in clojure?

nakiya02:03:42

File is quite big

nakiya02:03:08

Use a java lib?

arrdem02:03:33

@duminda the easy answer is (take-last n (line-seq (io/reader (io/file "my-file.txt")))) which will scan the entire file returning the last n lines same as tail -n n would.

noisesmith02:03:48

if the file is long enough you could try to do something clever with .available and .skip on a FileInputStream, which avoids reading the data you aren't using - that depends on how big the file is and what assumptions you can make about file length and what your performance concerns are though https://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html

arrdem02:03:52

You could try to be smarter and manually use a RandomAccessFile, and try to find the last n lines by manually scanning chunks starting from the end of the file and working backwards.

noisesmith02:03:15

yeah, that too

arrdem02:03:46

There's also probably a way to use an NIO mmap file of some sort... lots of ways to skin that cat.

noisesmith02:03:06

oh yeah - that's actually the best one if performance is an issue

noisesmith02:03:24

bit line-seq and take-last is the simplest code

arrdem02:03:56

So it looks like using FileInputStream actually won't work unless you manually do the ring buffer dance yourself and then you still have to scan the entire file for correctness since readers are unidirectional.

arrdem02:03:40

and the NIO mmap buffer thing is definitely possible but looks very involved

noisesmith02:03:57

@arrdem: the FileInputStream wouldn't work, right, unless you open, skip to all but N bytes, and count newlines

noisesmith02:03:32

being able to translate java SO answers into interop is a killer skill as a clojure dev :P

rahulr9203:03:40

Hi, can someone help me understand the difference between spec/and and spec/merge? The example of merge given in the Clojure Spec guide https://clojure.org/guides/spec (using :animal/common and :animal/dog) seems to work even if we use and instead of merge.

rahulr9204:03:56

@anantpaatra Thanks. I’m trying there now.

nakiya05:03:35

I have a compojure api, I get a request from a device to the endpoint. The log is something like this:

2018-03-13 05:27:11,846 [XNIO-1 task-6] INFO  ring.logger.tools-logging - Starting :post /api/comms/new_packet for 115.42.250.66 {"connection" "close", "accept" "application/json", "keep-alive" "timeout=30", "from" "xxxxx", "content-type" "application/json", "content-length" "217", "user-agent" "curl/7.54.0", "host" "xxxxx"}
2018-03-13 05:27:11,847 [XNIO-1 task-6] DEBUG ring.logger.tools-logging - Request details: {:remote-addr "xxxxx", :server-port 8000, :content-length 217, :content-type "application/json", :character-encoding "ISO-8859-1", :uri "/api/comms/new_packet", :server-name "xxxxx", :query-string nil, :scheme :http, :request-method :post}
2018-03-13 05:27:11,847 [XNIO-1 task-6] INFO  ring.logger.tools-logging -   \ - - - -  Params: {}
After this, there’s nothing. No response, and my handler is not invoked. If I send a request from swagger ui to this endpoint, I see the response in the logs after that last line. I am sure that this is a bug in the device’s request. I only want to know how to get details on server side why the request is not reaching the handler. Any logging/debugging methods to find this out?

Drew Verlee17:03:16

Your using CompjureApi the lib? or you built an api using compjure?

Drew Verlee17:03:58

I would debug this by running the compjure client with the request: something like: https://github.com/drewverlee/plum/blob/master/src/plum/handler.clj#L22

Drew Verlee17:03:26

In general, with clojure, you have to reach for a step through debugger less often because a) your writing smaller pure functions b) the repl gives you the feedback you would want from the debugger. This isn’t always true, for good reasons. In that case, i would start with print and pull in more techniques as you have time.

Drew Verlee17:03:35

also, a good place to ask more questions is probably ring-swagger

nakiya01:03:37

@U0DJ4T5U1: Using compojureAPI the lib. My question was about my handler not being invoked when a request is sent from a client. (Turned out that the request was buggy - content-length was wrong). I had no idea how to figure out why the request is not reaching until my handler invocation. And how to see where it gets stopped.

Drew Verlee02:03:26

Hmm. Yes, in that case a debugger might help.

Sushan08:03:24

Hi all …I am getting this error

Exception in thread "main" java.lang.RuntimeException: No such var: clojure.core/cheshire.core,
Could some one help me to get into this:pray:

dima09:03:12

error message seems self-descriptive enough, there is no such var clojure.core/cheshire.core. Where do you use it?

john13:03:46

And it's doubtful clojure.core/cheshire.core is a real thing. Probably a typo.

john13:03:09

perhaps in the ns definition

Sushan04:03:52

@U050PJ2EU yes it is!Confused with bracket in lisp way of coding..

Sushan05:03:26

Now installed plugin in atom which automatically deals with the bracket which i not supposed to care..

sb09:03:17

Did you see similar solution like io.pedestal.log just for http-kit?

timo09:03:53

does anyone have a good resource on form-3 components in reagent? I am struggling with the update mechanism

Michael Fiano15:03:41

is there an env var for controlling where ~/.lein is like boot's BOOT_HOME?

Russ Olsen16:03:08

I think it's LEIN_HOME

rgm17:03:01

I'm having a bit of head-scratching around providing separate dev-build environments for a ring/postgres backend and re-frame front-end, and hoping there's just a semi-normal way to deal with it.

rgm17:03:07

I started with environ because that's in chestnut.

rgm17:03:25

The current pieces of config data that differ are the db connection url, the web address against which the cljs makes its xhr/fetch requests, and now an asset path for the webserver to use to collate PDFs together on the fly from a set of a few thousand.

rgm17:03:38

so environ is fine for the first and third (clj concerns), but I haven't been able to use it for the front-end XHR url, since (obviously) the browser doesn't have an environ.

rgm17:03:46

I tried the trick of making up a macro that does use environ and burning it in at the time I build my uberjar ... couldn't get that working but adzerk/env seems to have done the trick (and I understand it's doing roughly the same idea on the cljs side).

rgm17:03:48

anyway now juxt/aero has caught my eye ... I have broad philosophical agreement that config should mostly just be a file instead of a dozen env vars (not including secrets, of course).

rgm17:03:45

and generally tools like direnv and using profiles.clj seems to take care of that.

rgm17:03:24

but the thing that seems to make this all a bit weird is my possibly-misguided way of configuring the XHR endpoint on the client side

rgm17:03:48

Anyway, long story. Hoping there's a more intelligent way to deal with separate envs for back- and front-end.

mikerod19:03:27

@U08BW7V1V there are a good number of config libs out now for clj/cljs

mikerod19:03:37

Some of them have goals of reaching both the server and client side

mikerod19:03:57

So far, I’ve used environ in a simpler project, and juxt/aero in a more involved config project

mikerod19:03:17

I’ve just loaded config on server and let the client get some of that config via a REST request. That may not be appropriate for you though

rgm19:03:19

thanks ... the chicken-and-egg thing I'm not seeing clearly enough is, how can I pull down config from an endpoint if the endpoint is part of the config?

mikerod19:03:35

Yeah, I detected you may have that concern 😛

mikerod19:03:02

There are ways to do it ad hoc, like building the URL into the initial document (html generated on server side can use config)

mikerod19:03:06

that may not be suitable for you either

rgm19:03:31

well, that'd probably work ... I was close to breaking out sed as a part of jar construction.

mikerod19:03:45

but you can do some server-side rendering of your page that loads your js and all that too

rgm19:03:48

just seemed like I was reinventing something that probably exists.

rgm19:03:04

that might work

mikerod19:03:11

I’ve used server-side rendering of the “index.html” page to splice in some simple config values before

mikerod19:03:33

it is a real minimal approach. The libs that exist that transport the config from server-to-client, probably build it into the js somehow (haven’t looked)

mikerod19:03:02

trying to find one of those more recent libs for config, but can’t find it immediately. I know I’ve came across like 2-3 config libraries recently that may do some stuff for you

rgm19:03:10

yeah, adzerk/env seems to burn it in using a macro.

mikerod19:03:02

yeah, I’m sure there are tricks to doing it

mikerod19:03:23

I haven’t dove into these server+client config libs yet. Still using juxt/aero and I’ve used the server-side rendering trick the few times I’ve needed it

mikerod19:03:39

maybe if you can get your URI out to the client, then the client can just http for the bigger config stuff hah

mikerod19:03:49

It really all depends on the situation I think

rgm19:03:00

oh neat... that looks aero-esque but with the cljs side.

mikerod19:03:01

I believe that nomad is a pretty popular config lib out there right now

mikerod19:03:43

I’ve considered trying it out before long. I like some things with juxt/aero design-wise better I think. However, they aren’t necessarily taht different from one another I don’t think. And nomad may give you smooth clj + cljs side config sharing

rgm19:03:47

<immediately rips out all current config code and stall feature progress>

rgm19:03:52

cool ... the crux for seems to be swapping out the XHR endpoint so I was hoping there was a well-trodden path there.

rgm19:03:04

everything else seems do-able with straight-up environ.

mikerod19:03:20

sure, you could do the server-sider rendering trick then for tha tif you wanted

mikerod19:03:41

like you could put a <script>var myUrl=<url-from-config>

mikerod19:03:17

hiccup makes generating the server-side html pretty smooth on the clj side

mikerod19:03:27

if you aren’t needing anything too fancy.

mikerod19:03:21

Ends up looking like:

(require '[hiccup.page :as hicc]
         [hiccup.element :as elem])

(defn app-index
  [config]
  (hicc/html5 {:lang "en"}

              [:head
               [:meta {:charset "UTF-8"}]
               [:meta {:name "viewport" :content "width=device-width, initial-scale=1"}]
               [:title "My App"]
               ;; Whatever CSS
               (hicc/include-css "css/style.css")]

              [:body
               ;; Where yo you are hooking on your React rendering presumably
               [:div {:id "app"}
                [:h2 "Loading..."]]

               (elem/javascript-tag (str "var myUrl=" (:my-url config)))
               (hicc/include-js "js/compiled/app.js")

               (elem/javascript-tag "my.client.app.init();")]))

mikerod19:03:07

You could pass config then from environ since this is on the clj/server side

mikerod19:03:37

Just have to make sure whatever you splice in is in the appropriate format, such as a valid JS string for the myURL above

mikerod19:03:51

Your client-side could then access this via js/myUrl

rgm19:03:37

Oh cool. It also just occurred to me I could also string replace on the initial js bundle going outbound, instead of a straight-up static file response.

rgm19:03:06

Or do string replace on the index.html to do the trick above, instead of necessarily generating hiccup.

mikerod19:03:09

yes, I think I understand what you mean and that is a possibility

mikerod19:03:52

It also just occurred to me that nomad may not be the lib that shares clj to cljs config. I think I confused it with another. Just FYI since I may have been misleading there. I’d have to do some config lib research again to see what’s out there at this point hah.

sam18:03:39

Could someone explain why the following doesn't work for #39 on 4clojure?

#(flatten (into [] (zipmap %1 %2)))
It just says that the unit test failed, but running it locally works just fine:
user=> (= (#(flatten (into [] (zipmap %1 %2))) [1 2 3] [:a :b :c]) '(1 :a 2 :b 3 :c))
true
http://www.4clojure.com/problem/39#prob-title

noisesmith18:03:15

don't know why it fails, but that into call isn't doing anything

sam18:03:23

user=> (= (#(flatten (zipmap %1 %2)) [1 2 3] [:a :b :c]) '(1 :a 2 :b 3 :c))
false

noisesmith18:03:21

oh right, flatten ignores hash-maps

sam18:03:36

could you elaborate?

madstap18:03:55

Note that maps aren't ordered

sam18:03:03

so, there's no guarantee of the order... is that why it could be failing on 4clojure?

madstap18:03:17

Maybe, IIRC 4clojure uses an ancient version of clojure, so you're probably on a different version than they are.

sam18:03:51

hm, ok. I guess the only way to really find out what's going on is to run it on my own box

john18:03:13

you don't need the flatten

john18:03:50

ah my bad. read the question wrong. You just need to change the vector to a list

john18:03:55

#(flatten (into '() (zipmap %1 %2)))

john18:03:38

well, hmm... some of the require results aren't lists... but it passes

sam19:03:11

hmm... so why does that work but [] does not?

john19:03:52

mmm. afaict, the problem is not constructed right

john19:03:13

(#(flatten (into `() (zipmap %1 %2))) 
  [1 2 3] [:a :b :c])
;=> (3 :c 2 :b 1 :a)

john19:03:24

That passes, but they're clearly not in the right order

noisesmith19:03:02

Zipmap returns an unordered type, you can eg map list over two collections instead

john19:03:17

I figured. The problem is broken though, right? It should fail on that.

noisesmith20:03:46

it’s allowed to have an order, it’s not guaranteed to scramble the order

mathpunk19:03:20

@manutter51 thank you!!!!! i knew it had to be something tiny but I've been stumped for days

athomasoriginal23:03:28

This is my project structure

├── resources
│   ├── css
│   ├── index.html
│   └── sounds
└── src
    └── drumkit
└── deps.edn
My deps.edn looks like this:
{:paths ["src" "resources"] 
 :deps  {org.clojure/clojure {:mvn/version "1.9.0"}
             org.clojure/clojurescript {:mvn/version "1.10.126"}}}

When I run the project using clj --main cljs.main --watch src --compile drumkit.core --repl It does not pickup my index.html in the resources dir. Is there a way to tell the CLI where to look for my index.html file?

noisesmith23:03:50

are you referencing it as resources/index.html ?

athomasoriginal23:03:54

Sorry, do you mean in my deps.edn?

noisesmith23:03:31

I mean whatever code is looking for index.html - what path are you using to access it?

athomasoriginal23:03:31

I am not referencing it at all. clj --main cljs.main finds the index.html file if I move it to the root, like this:

├── resources
│   ├── css
│   └── sounds
└── src
    └── drumkit
└── deps.edn
├── index.html

noisesmith23:03:59

what do you mean by finds? why would it care if your code does nothing with that file?

athomasoriginal23:03:03

Well, clj --main cljs.main --watch src --compile drumkit.core --repl is going to run a browser repl and launch the site, yes?

noisesmith23:03:26

this is a brand new feature

noisesmith23:03:50

so you mean clj should be picking index.html as the document to open in a browser for you

noisesmith23:03:24

sorry I'm dense, I forgot this feature came out the other day

athomasoriginal23:03:20

haha no worries.

athomasoriginal23:03:17

But yes, it seems that it will use a default index.html if we do not provide one. However, I want to provide one, but not in the root of my project. So I am hoping I can specify a path