Fork me on GitHub
#beginners
<
2019-08-06
>
Godwin Ko01:08:03

clojure compiler error message almost never point me to the real issue, the only useful info just the line number, and the runtime exception even worst, most of the time just throw a null pointer exception, any practical workflow you guys are using when developing clojure project?

noisesmith01:08:41

some of the common ones are weird at first but make sense when you learn them "* cannot be cast to ifn" -> you put something in parens that isn't a function you can call "end of form during reading" - > missing a closing paren

noisesmith01:08:44

in fact the compiler messages contain a lot of interesting data that regular runtime errors don' t with newer versions (but it's in a relatively raw form that doesn't make a lot of sense to a newcomer)

seancorfield01:08:13

@godwin.ko First off, I'd recommend you try Clojure 1.10.1 so you get the most up-to-date error reporting (it was improved a lot in 1.10). Also, not all of the tooling out there supports the changes in 1.10 around error reporting so you can still get a lot of "noise" from tooling, unless you're using the CLI / deps.edn stuff.

seancorfield01:08:59

Second, as @noisesmith says, the errors provide exactly the information you need, once you get used to a few specific "mappings" you need to do in your head.

seancorfield01:08:20

If you are getting NPEs, you are probably trying to perform numeric or string operations on things that are nil, or you're trying to call a symbol/expression whose value is nil. Getting used to idiomatic nil-punning will help here (I almost never get NPEs these days but I did when I started out).

GC01:08:28

Hi, I am trying to call a function inside a let statement, but it is saying "unable to resolve symbol in this context"

(defn addd [arg]
  (let [
     arg  (some-func arg)
     ]
     (println "arg is " arg)
     arg
     ))

GC01:08:46

some-func is the function that I am trying ton call

seancorfield01:08:50

That indentation / layout is non-idiomatic and very hard to read.

seancorfield02:08:26

(defn addd [arg]
  (let [arg (some-func arg)]
    (println "arg is " arg)
    arg))

seancorfield02:08:04

@gagan.chohan I assume some-func is the symbol it says it cannot resolve here?

seancorfield02:08:27

Where is some-func defined?

GC02:08:11

It is defined in same file

seancorfield02:08:18

Where in the same file?

seancorfield02:08:42

Clojure requires that symbols are defined (or at least declared) before their first use.

GC02:08:05

It's a function some-func

seancorfield02:08:11

So the (defn some-func ...) needs to come before the (defn addd ...)

GC02:08:11

So order of functions matters??

noisesmith02:08:33

yes - in fact the clojure compiler doesn't really care much about files per se

seancorfield02:08:35

Clojure is compiled one form at a time, not one file at a time.

noisesmith02:08:49

it reads forms in order, they can come from various places

GC02:08:11

So, order of functions matters??

GC02:08:15

You mean that

noisesmith02:08:17

the nice thing about this is the repl works exactly like any other scenario

noisesmith02:08:36

the order of definitions matters, nothing is available before it's declared or defined

GC02:08:40

Yea, this thing seems to work on repl

GC02:08:50

But fails in actual program

noisesmith02:08:03

because likely in the repl you defined the function first

noisesmith02:08:09

do the same thing in the file

GC02:08:13

Many languages doesn't consider the order, I thought clojure might be the same

GC02:08:50

Thanks for helping out

GC02:08:54

πŸ‘

Godwin Ko02:08:23

thx @noisesmith & @seancorfield for pointing me some directions πŸ™‡:skin-tone-2:

armonge06:08:51

Hello everybody! I just started my journey on the clojure world and was wondering if someone could recommend some good resource to follow. I just finished this https://github.com/functional-koans/clojure-koans and found it really cool, anything interactive like that would be really appreciated

Crispin06:08:13

checkout 4clojure http://www.4clojure.com/

πŸ’― 4
dharrigan12:08:15

Within the repl, is there a way to load all of my project's namespaces in, say starting from my "core.clj" and getting it to pull in everything that it depends upon, so that I have access to the "dependent" namespaces?

Jivago Alves12:08:30

hey @U11EL3P9U , I just looked at the description of https://github.com/clojure/tools.namespace . Perhaps it can help you.

conan12:08:53

I usually create a user namespace, add it as a source-path in development, and set the repl to start in that namespace (using :repl-options > :init-ns in leiningen, for example). Then I require all my namespaces in there so it's all ready to go when the repl starts. I realise this isn't exactly what you were asking (tools.namespace is the answer), but it is how i achieve the same thing on a day-to-day basis.

Jivago Alves14:08:35

@U11EL3P9U Now that I'm reading your question again, what @U053032QC says makes more sense if you just want to have all you need in the repl like the most common namespaces / functions. I do the same. You can see an example where I make the cli alias and all public functions in core available in the repl for quick usage https://github.com/jivagoalves/codebreaker/blob/master/dev/user.clj#L4-L5 There's also a helper fn to run the tests https://github.com/jivagoalves/codebreaker/blob/master/dev/user.clj#L7-L12

Crispin15:08:11

if it applies to you, in emacs using cider, open the core.clj buffer and do the keypress c-c c-k

Crispin15:08:42

(cider-eval-buffer)

dharrigan16:08:03

Thanks all! πŸ™‚

noisesmith17:08:37

NB require is already recursive: if a namespace requires another namespace, require already loads both

Chris13:08:40

hello guys, I recently started using clojure (is awesome so far!). I’m creating a simple compojure application. The whole code is visible here: https://github.com/bakku/clj-rest-web-app I’m currently trying to have a session that stores the currently logged in user ID. I’ve configured the ring-session middleware to use a cookie store, however after restarting my server the session is somehow refreshed as if it is actually not using any cookie store. The important bits are probably: - Here I am configuring the cookie-store: https://github.com/bakku/clj-rest-web-app/blob/master/src/clj_rest_web_app/core.clj#L24 - Here I am setting the session after a successful login: https://github.com/bakku/clj-rest-web-app/blob/master/src/clj_rest_web_app/controllers/sessions.clj#L6 - I’m running the application in docker, here I am setting the cookie secret: https://github.com/bakku/clj-rest-web-app/blob/master/docker-compose.yml#L15 Does anybody have some idea what might be the problem?

schmee13:08:44

@christian.paling by default Ring uses an in-memory session store. you can change it to store data in a cookie or something persistent like Redis, see https://github.com/ring-clojure/ring/wiki/Sessions#session-stores

Chris13:08:05

yes, however I have configured it to store the data in a cookie

Chris14:08:12

I got it to work ! I was using the site-defaults from ring which already wrapped my routes using the session middleware but the site-defaults are using the in-memory session. I had to update the session configuration of the site-defaults according to my needs to get it to work πŸ™‚

alpox17:08:46

Hi all! I am trying to use Reagent with react-beautiful-dnd and I run into an error when trying to convert one of the datastructures they pass to me for usage (`provider` - a parameter to the react child function) from a js value to a cljs value with (js->clj provider :keywordize-keys true). The reason seems to be that the datastructure contains javascript symbols. A simple reproduction is to type in the cljs repl: (str (js/Symbol "foo")) which leads to the same error. Is there a (simple) way around this error - a way with which clojurescript can deal with the javascript symbol?

alpox17:08:09

I found I can extend the writer protocol to understand js symbols - I wonder though why this is not part of the clojurescript implementation

noisesmith17:08:46

symbols intentionally aren't "stringy"

alpox17:08:01

@noisesmith thanks for pointing that out. My issue is that the string conversion is done implicitly by js->clj somewhere deep in the datastructure though - not something that is under my control.

noisesmith17:08:56

js->clj is kind of a sloppy tool - if you use the transit library it allows arbitrary functions to handle data types as you like, and it also performs much better

alpox17:08:59

A solution I found is to:

(extend-protocol IPrintWithWriter
  js/Symbol
  (-pr-writer [sym writer _]
    (-write writer (str "\"" (.toString sym) "\""))))
But I'm not sure if extending the protocol generally for symbols is a good idea

alpox17:08:39

@noisesmith Ah I heard a lot about transit but didn't yet check it out. May be the time πŸ™‚ Thanks, I'll look into it!

alpox17:08:40

@noisesmith I'm a bit confused about what I see about transit. I see that it can read/write from/to strings for the purpose of data-transport. What I fail to see is how transit applies to the transformation of js values to clojurescript values. Is the general way to go to marshal js values to a string and then read it into cljs? This seems like one step too much

sova-soars-the-sora17:08:13

"failed: Error during WebSocket handshake: Unexpected response code: 200"

sova-soars-the-sora17:08:38

it's expecting 101

sova-soars-the-sora17:08:42

but i'm not sure why it's connecting too quick too early

sova-soars-the-sora17:08:47

oh sorry to just hijack your convo

sova-soars-the-sora17:08:23

@alpox you know about cljs reader right?

alpox17:08:44

@sova the namespace?

sova-soars-the-sora18:08:30

i was thinking cljs-reader / read-string, but what are you trying to do ? (what's your end-goal )

alpox18:08:10

I just want to transform a javascript datastructure (deep) to a cljs datastructure. The pickle: Somewhere in the datastructure, there is a javascript Symbol which js->clj cannot handle

alpox18:08:40

(js->clj {:foo (js/Symbol "bar")}) Fails

noisesmith18:08:36

@alpox had something to attend to at $JOB

alpox18:08:49

@noisesmith no problem πŸ™‚

noisesmith18:08:27

I agree that transit isn't for your precise problem, but it does a common task: a deep walk of a structure to turn it into "simple" values

noisesmith18:08:36

where clearly a js Symbol isn't simple

noisesmith18:08:44

> Note that js->clj is not optimized for speed and the transit.cljs library is recommended for parsing large amounts of JSON data. https://cljs.github.io/api/cljs.core/js-GTclj

noisesmith18:08:07

also you can simply copy/paste the function on that page, and add a clause for Symbol

noisesmith18:08:32

(if only js->clj was built on a multimethod or protocol you could extend it...)

alpox18:08:45

Well. I can extend it so it works with Symbols πŸ˜„

noisesmith18:08:48

oh! you could extend IEncodeClojure

alpox18:08:03

(extend-protocol IPrintWithWriter
    js/Symbol
    (-pr-writer [sym writer _]
      (-write writer (str "\"" (.toString sym) "\""))))

alpox18:08:04

I mean this works

noisesmith18:08:07

@alpox by extend I mean make it understand a new input without editing the code

alpox18:08:10

But I'm not sure its a good method πŸ˜„

noisesmith18:08:28

it doesn't use IPrintWithWriter though?

alpox18:08:34

Kinda does though

noisesmith18:08:35

it does use IEncodeClojure

alpox18:08:38

Thats where it failed

noisesmith18:08:58

OK - via the else clause I guess

alpox18:08:15

encoding of result failed TypeError: Cannot convert a Symbol value to a string
    at Array.join (<anonymous>)
    at Function.cljs$core$IFn$_invoke$arity$1 (core.cljs:2963)
    at Object.cljs$core$pr_writer_impl [as pr_writer_impl] (core.cljs:10174)
    at cljs$core$pr_writer (core.cljs:10183)
    at core.cljs:10306
    at Object.cljs$core$pr_sequential_writer [as pr_sequential_writer] (core.cljs:10037)
    at Object.cljs$core$print_prefix_map [as print_prefix_map] (core.cljs:10303)
    at Object.cljs$core$print_map [as print_map] (core.cljs:10315)
    at Object.cljs$core$IPrintWithWriter$_pr_writer$arity$3 (core.cljs:10390)
    at Object.cljs$core$_pr_writer [as _pr_writer] (core.cljs:763) 

alpox18:08:21

This would be the error - IPrintWithWriter is used there

noisesmith18:08:45

I still think extending IEcondeClojure is more directly addressing the need

alpox18:08:09

Ok thanks, I'll see how its used - i'm still kinda new to all this so it may take me a while to figure it out πŸ˜„

alpox18:08:20

Oh that was actually straight forward. Thanks a lot @noisesmith! This solution seems to fit well πŸ˜„

alpox18:08:35

(extend-protocol IEncodeClojure
  js/Symbol
  (-js->clj [sym options]
    (str "\"" (.toString sym) "\"")))

alpox18:08:38

Hope thats alright

noisesmith18:08:07

that looks right to me (though the MDN page seemed to suggest using the String constructor instead)

πŸ‘ 4
alpox18:08:20

Okay thanks, I'll go ahead and use the constructor then

sova-soars-the-sora18:08:18

hey check out my simple clojurescript website http://www.nonforum.com and give me feedbacks pls

sova-soars-the-sora18:08:50

You know that there's a line in the Sente starter package that has a line to assign the channel socket randomly as EITHER ajax or websockt

sova-soars-the-sora18:08:01

that shit was ruining my life until about an hour ago

sova-soars-the-sora18:08:14

why does my site render approximately half the time

sova-soars-the-sora18:08:30

i was doing stats on it last night ROFL "okay 2/8 times it just doesn't render the page and gets a weird websocket error"

sova-soars-the-sora18:08:46

πŸ˜­πŸ˜­πŸ˜‚

sova-soars-the-sora18:08:04

know every line of the libraries you bring in

sova-soars-the-sora18:08:14

(when not inconvenient and mission critical)

sova-soars-the-sora18:08:22

Peace y'all have a great day Wisdom Bless

alpox18:08:52

Sente (starter pack) seems to be fun πŸ˜„

alpox18:08:25

For some reason (js/String sym) throws but (.toString sym) does not

noisesmith18:08:39

that's the wrong syntax

noisesmith18:08:42

it's a constructor

alpox18:08:01

>The "safer" String(sym) conversion works like a call to Symbol.prototype.toString() with symbols, but note that new String(sym) will throw.

noisesmith18:08:07

it's (String. sym)

alpox18:08:17

Quote from MDN

noisesmith18:08:45

never mind, looks like toString is actually working for you

alpox18:08:05

I still wonder why js/String does not though πŸ˜„

alpox18:08:25

Hmm ok doesn't matter, it works with toString

Ian Fernandez19:08:18

guys, I want some help with project.clj of leiningen... I want to have many folders under src but only open repl for each one subfolder by profile and generate a jar file with this profile only

Ian Fernandez19:08:30

like, src/a src/b

Ian Fernandez19:08:28

(defproject backend "0.1.1"
  :dependencies [[org.clojure/clojure "1.10.1"]
                 [org.clojure/data.xml "0.2.0-alpha6"]]
  :plugins [[lein-environ "1.1.0"]]
  :resource-paths ["resources"]
  :source-paths ["src"]
  :profiles {:a {:main backend.a.core
                       :source-paths ["src/a"]
                       :resource-paths ["resources/a"]
                       :aot [backend.a.core]
                       :pedestal       {:server-ns "backend.a.core"}}})

Ian Fernandez19:08:16

but this aot is giving me error to initiate the repl

Ian Fernandez19:08:12

lein with-profile a update-in :dependencies conj \[nrepl\ \"0.6.0\"\] -- repl

Ian Fernandez19:08:24

Error encountered performing task 'update-in' with profile(s): 'a'

Ian Fernandez19:08:32

some tip about this?

andy.fingerhut20:08:54

I am not sure about this, but I suspect it might be a bad idea to have two source paths where one is a prefix of the other in your project, like "src" and "src/a" are in your example.

andy.fingerhut20:08:24

If you have a source file named "src/a/foo.clj" for example, it could be found if you require namespace a.foo, but also foo

andy.fingerhut20:08:23

I have not used update-in with Leiningen before, so am not helpful there. I have successfully used lein with-profile +a ... commands before to add a profile, but am not familiar with Leiningen's capabilities without the + there.

andy.fingerhut20:08:41

There is a #leiningen channel that you may get more answers from.

csd19:08:18

Anyone have any clue why I'm getting

Unexpected error macroexpanding s/def
[...]
Caused by: java.lang.AssertionError: Assert failed: (map? env)
for the offending snippet:
(s/def ::generated-date #(instance? Date %))

Ian Fernandez19:08:41

maybe you have to import Date ?

csd19:08:59

Date is imported

csd21:08:03

The alias was indeed the issue, thanks

csd20:08:47

Cursive had auto-imported cljs.spec.alpha facepalm

Noah Bogart21:08:48

is there a way to step through the execution of something? line-by-line, the way ruby has binding.pry or python had pdb

noisesmith21:08:44

lines aren't really a meaningful thing to the compiler, but you can use a debugger to step through the method calls that the clojure compiler emits, and a good editor can follow along in your source - intellij/cursive and emacs/cider have this set up

noisesmith21:08:13

the big gotcha is for it to be useful you usually need to turn off locals clearing, which causes memory problems that don't exist in normally compiled code

Noah Bogart21:08:13

sure, lines aren't meaningful to the compiler, but java can still have breakpoints and step-wise execution

noisesmith21:08:40

I'm just saying the steps aren't lines, they are method calls, which mostly map to forms but not quite

noisesmith21:08:13

and when you run into things like laziness, I'm not sure how accurate the mapping will be

Alex Miller (Clojure team)21:08:19

you can do it with cursive

Alex Miller (Clojure team)21:08:28

it often "steps" multiple times per line (once per expression)

Noah Bogart21:08:40

cool, i'll look into that

Alex Miller (Clojure team)21:08:07

I find it useful with working with interop as you can step through a mix of clojure and java

Alex Miller (Clojure team)21:08:30

I think the emacs cider debugger also has this, but the ergonomics are probably a little different, and not sure if it works with java

Noah Bogart21:08:05

yeah, that makes sense. thanks!

Ashley Smith22:08:53

Can you use case with keywords? Or do you have to use a multimethod?

noisesmith22:08:20

case works with keywords, the difference is that if it's a multimethod third party code can add a new condition without changing the upstream code

Ashley Smith22:08:59

gotcha πŸ™‚

noisesmith22:08:43

case doesn't work for things that don't have a read syntax, but of course keywords have a read syntax

bartuka23:08:14

hi, there is a library to read XLSX files lazily?

noisesmith23:08:58

@iagwanderson I can't vouch for this lib, but it looks like it has the right pieces to attempt what you want https://github.com/mjul/docjure

bartuka23:08:42

I'm currently using this library, but seems not to do lazy-load (line-by-line) of a xlsx file

bartuka23:08:50

I'm getting out of memory from jvm

noisesmith23:08:57

isn't that what row-seq is for?

noisesmith23:08:25

as long as you don't hold the head, of course

noisesmith23:08:09

unless there's something that holds onto the memory on the underlying lib I guess but one would hope they support streaming properly

bartuka23:08:58

I'm performing some tests, one sec o/

noisesmith23:08:42

if you have an example or minimal repro I can help check for a stray head reference that prevents the laziness from minimizing memory usage

noisesmith23:08:38

simplest example, if you are not familiar: if you have (def rows (row-seq ...)) the entire realized seq is held in memory, because the def holds the head

bartuka23:08:04

oh, I see. I think everything is fine with their implementation

bartuka23:08:29

I did an example with a 100k xlsx file and memory did not went up or event the cpu process

bartuka23:08:45

(defn row-size [row]
  (println (.getRowNum row)))

(->> (xlsx/load-workbook filename)
     (xlsx/select-sheet "Plan1")
     xlsx/row-seq
     (map row-size))

bartuka23:08:06

I was passing the filename to the function and printing the row number

noisesmith23:08:36

OK, so the issue is likely somewhere in your code holding onto the head

noisesmith23:08:48

(in your real code, not this example, of course)

bartuka23:08:10

yes, definitely. I tried to model records and protocols to handle different files

bartuka23:08:29

I might have messed around

bartuka23:08:33

I will track it down

bartuka23:08:54

I was already trying to use this library in Java: https://github.com/monitorjbl/excel-streaming-reader

bartuka23:08:07

sounds good too.. but the error is probably on my side