Fork me on GitHub
#beginners
<
2018-03-22
>
brunobraga01:03:37

do you guys know if def supposed to return nil?

brunobraga01:03:20

I am defining a bunch of values inside a function, more especific a cond block and it returns nil right away

brunobraga01:03:34

is this because of the cond?

seancorfield01:03:43

@brnbraga95 You should not use def inside a function (assuming that's what you mean -- maybe show some code?).

brunobraga01:03:01

I got it, sorry..I forgot to wrap the whole else condition inside (), so my def right after was being treated as a function

brunobraga01:03:11

but why do you say that I should not?

seancorfield01:03:56

def always defines a top-level (global) var.

seancorfield01:03:08

Inside a function you want local bindings -- via let.

brunobraga01:03:00

thats very important to know

seancorfield01:03:35

@brnbraga95 It's a common mistake most people make when they first start learning Clojure. They see stuff like

(def answer 42)
and think it's equivalent to answer = 42; as a declaration in whatever language they're used to, so they naturally try to do
(defn my-fn []
  (def x 13)
  ...)
and it seems to work so they don't realize they've defined a new global x when they run their function!

seancorfield01:03:47

Both def and defn only define top-level globals so you "never" want to use them inside a function (well, almost never... there are times when you want a function to inject new top-level vars but...).

seancorfield01:03:32

The let-form of my-fn would be

(defn my-fn []
  (let [x 13]
    ...))

brunobraga01:03:25

refactoring right now

brunobraga01:03:28

but this is not very handy

brunobraga01:03:47

what if I declare a serious of variables? should I nest everything?

seancorfield01:03:58

let can have multiple bindings

seancorfield01:03:09

(let [x 13
      y 42]
  …)

seancorfield01:03:31

(and each one can refer to any previous one)

brunobraga01:03:08

can I return something from inside?

seancorfield01:03:05

Functions return the value of their last expression. A let also returns the value of its last expression.

brunobraga02:03:57

for some reason this refactor made my code workds

brunobraga02:03:19

cant imagine what kind of inconsistensies I was having working with so many global variables

seancorfield02:03:29

As an example, here's a function I wrote today:

(defn queue-skip
  "Skip a photo in the crop queue."
  [req]
  (let [app      (-> req req/config :application :worldsingles-application)
        db-spec  (-> app :database :pooled-db)
        admin-id (-> req :ws.web/admin :id)]
    (when-let [photo (jdbc/get-by-id db-spec :userPhoto
                                     (->long (get-in req [:params :photoid])))]
      (model/add-crop-lock db-spec 0 (:id photo))
      (log/write-log :loguserphoto
                     {...}
                     req))
    (admin-web/redirect-to-event req "newadmin.userphotoqueue")))
The queue-skip function has a single expression in the body -- the let. The let has two expressions in its body -- the when-let and the admin-web/redirect-to-event call. So the let bindings are evaluated first, in order, then the when-let is evaluated, then the admin-web/redirect-to-event call -- and the result of that call is the result of the let and of the queue-skip function.

brunobraga02:03:04

just out of curiosity the you added "Skip a photo in the crop queue." is a common thing?

brunobraga02:03:24

among clojure developers, is it just like a comment about the function?

seancorfield02:03:25

The when-let evaluates its binding and if it is truthy (not nil or false), it evaluates its body. So the model/add-crop-lock call is made (and the result thrown away because it is not the last expression), and then the log/write-log call is made and that is the value of the when-let -- although we through away that value because the when-let is not the last expression in the enclosing let.

seancorfield02:03:08

It's a docstring. It shows up in the REPL when you type (doc queue-skip) and in many editors it will appear as a hint when you type the function name, along with the arguments.

brunobraga02:03:45

ohh thats cool

brunobraga02:03:28

which editor is that?

brunobraga02:03:32

do you use emacs?

seancorfield02:03:45

Atom with ProtoREPL. I used Emacs for years before that.

brunobraga02:03:56

also, is there some sort of lint for clojure?

seancorfield02:03:05

But Emacs with CIDER should do this sort of hinting as well.

brunobraga02:03:08

like a script to ident my code following a pattern

brunobraga02:03:21

sorry for all the question haha

seancorfield02:03:40

I use a linter in Atom called Joker -- it's the red dot and wavy line because queu is not a defined name.

seancorfield02:03:31

@mfiano Long story... I was an Emacs user 20+ years ago, back in the 17.x through early 19.x days, then moved on to "IDEs" because I was working with languages that needed more "support" than Emacs could reasonably provide. When I learned Clojure (2010), I started with TextMate (OS X) but then tried all sorts of Clojure plugins for editors (including CCW for Eclipse, and Sublime Text 3, and others).

seancorfield02:03:05

Eventually I decided to give Emacs another try since something like 80-90% of Clojure devs used it back then... so that was in the prerelease for 24.x days.

seancorfield02:03:17

And it hadn't changed much really. Well, not on the surface.

seancorfield02:03:29

So over the next two years I tried maybe half a dozen different Emacs setups, some hand-built, some curated (Emacs Live for a while, then Prelude), and eventually I just got tired of it all being so primitive and having the weird key chords to do stuff (even tho' I'd gotten used to them).

Michael Fiano02:03:33

Emacs has some really nice support for structured code such as Lisp, for example safe deletes via clever-parens package, so you never have misbalanced parentheses or dangling parentheses on a line by themselves afterwards.

seancorfield02:03:27

Jason Gilman demo'd ProtoREPL at Clojure/conj a few years back and I really liked the inline display of results etc so I switched. At first I used a package to provide Emacs key bindings since I was so used to that... but I weaned myself off that last year 🙂

seancorfield02:03:43

Atom has paredit and parinfer and structural editing etc.

Michael Fiano02:03:49

I prefer vim myself, and spacemacs emacs distribution. Been doing lisp for over a decade with them both. I havent tried atom or vscode except very briefly, and they just seemed like a memory hungry chrome to me

seancorfield02:03:15

I mostly don't bother having the REPL panel even visible because I can see the results inline (and I never type in the REPL).

seancorfield02:03:46

@mfiano Yes, Atom is pretty RAM hungry... but I have 16GB so I don't much care 🙂

seancorfield02:03:46

@brnbraga95 I tend to rely on paredit/parinfer formatting my code, but I think we have a task in our build.boot file that does some standardized formatting...

Michael Fiano02:03:19

Fair enough. I have 24 and I'm always trying to tame usage with everything web browsers require these days, not to mention the JVM

brunobraga02:03:26

I use vscode for my javascript development, I am using it now since I am a beginner, not very used to repl and what it has to offer, wonder if it is worth to actually go through a whole learning process for an IDE, some folks online said that at least for beginners it is not good to add a new learning curve

seancorfield02:03:47

Ah, yeah, we use cljfmt in fact...

(deftask format-subproject
  [p subproject VAL str "Name of subproject to format"]
  (inject-subproject-deps! subproject)
  (when (.exists (io/file (str "../clojure/" subproject "/test/")))
    (merge-env! :resource-paths #{(str "../clojure/" subproject "/test/")}))
  (with-pass-thru fs
    (pod/with-eval-in (pod/make-pod (update-in (get-env)
                                               [:dependencies]
                                               conj
                                               '[lein-cljfmt "0.5.6"]
                                               '[leiningen-core "2.7.1"]))
      (require '[leiningen.cljfmt :refer [fix]])
      (fix {}
           ~(str "../clojure/" subproject "/src/")
           ~(str "../clojure/" subproject "/test/")))))

👍 4
seancorfield02:03:45

@brnbraga95 If you can learn Clojure while sticking with the editor/IDE you already know, that is probably easier.

seancorfield02:03:47

I will say that you don't really get the benefits of the REPL unless you have an editor/IDE that is tightly integrated. I type an expression, hit a hot key, and see the result inline immediately. So I often have

(comment
  ...)
forms containing code as I'm experimenting that I evaluate with hot keys so I keep a record of what I tried in the REPL as I work. Or examples of how to call functions or set up components for testing.

👍 4
Michael Fiano02:03:15

I asked before, but does anyone know any decent videos on concurrency with Clojure...something maybe like a tutorial or simple project walkthrough?

sundarj02:03:45

Rich Hickey also discusses concurrency a bunch in his talks, like Clojure Concurrency and Persistent Data Structures and Managed References

Michael Fiano02:03:21

Thanks I found the http://purelyfunctional.tv ones, but I don't have enough money to watch them, and I watched the 2 1/2 hour Rich Hickey talk, but the quality was extremely bad and the analog camera couldn't focus on the projected screen to see his usage of it

sundarj03:03:55

i see; sorry i couldn't be of more help!

Michael Fiano03:03:15

Those pivotshare videos look promising. Thanks a lot

4
seancorfield02:03:47

@brnbraga95 I would avoid list and type as argument names since they are built-in core functions but otherwise that looks OK.

👍 4
brunobraga02:03:02

@mfiano I was watching a video that "seemed" to be good, did not finish

brunobraga02:03:13

it like the first or second on youtube

seancorfield02:03:38

And using l for an argument sort of implies a list so maybe a better name for that.

Michael Fiano02:03:25

I see, it just seems like a big topic and I don't grasp everything I read in braveclojure. I am well versed in Lisp, just Clojure is pretty cloudy for me in that area still

seancorfield02:03:50

Since you're always walking into the job-or-agent with that first key, I'd probably use a let inside the reducing function:

(reduce (fn [m item]
          (let [payload (get item selector)]
            (assoc m (get payload "id") (dissoc payload "id")))) {} items)

seancorfield02:03:13

assuming (defn reduce-list [items selector] ...) as argument names

seancorfield02:03:40

If you were using keywords instead of strings for those keys, you could make that a bit cleaner:

(reduce (fn [m item]
          (let [payload (selector item)]
            (assoc m (:id payload) (dissoc payload :id)))) {} items)

seancorfield02:03:23

And at that point it might even be cleaner to map the selector over items first and then do the reduce

(->> items
     (map selector)
     (reduce (fn [m {:keys [id] :as item}]
               (assoc m id (dissoc item :id))) {}))

seancorfield02:03:43

(and the reduce there is almost group-by -- except it knows there's only one value for each grouped key and it removes the :id key)

seancorfield02:03:28

@mfiano I'm not sure what you're really looking for in terms of concurrency? To be honest, STM is rarely used in the wild, beyond atoms, and if you want fine-grained control over your concurrency, you need to go down to Java executors really.

seancorfield02:03:52

future and pmap are sledgehammers (esp. the latter!).

Michael Fiano02:03:25

I'm looking to leverage some of Clojure's excellent multi-threading constructs to port some old Common Lisp code that would benefit greatly from working on multiple cores.

seancorfield02:03:40

At work, we have a handful of agents -- and most of those should really be executors with more control over concurrency.

seancorfield03:03:34

The reducers namespace has a ForkJoin-powered parallel fold, as I recall. I don't know how widely used it is tho'.

seancorfield03:03:51

What do you mean by "excellent multi-threading constructs"?

Michael Fiano03:03:46

Everything in which braveclojure talks about that I didn't fully grasp. agents, atoms, futures, promises, delays, core.async, etc

seancorfield03:03:10

I will point out that https://clojure.org/about/concurrent_programming shows Java Executor usage (somewhat reinforcing my points above).

seancorfield03:03:00

I don't find video tutorials useful so I'm afraid I can't recommend anything there. I'm trying to think which books might be good reading for a treatment of concurrency...

Michael Fiano03:03:03

I don't know any Java at all. My experience is strictly Lisp.

seancorfield03:03:27

Search for timothy baldridge core.async and see if any of his videos/talks help you with that...?

Michael Fiano03:03:37

It's ok. I have been doing a lot of reading lately, and perhaps I'm old but some concepts are taking long to really sink in. I was just curious if anyone knew of a simple project walkthrough in video form.

Michael Fiano03:03:53

Understandable if there's not. The best I found is "Parens of the Dead"

seancorfield03:03:17

I'm old too -- which is why I tend to prefer print to video 🙂 🙂

sundarj03:03:34

Joy of Clojure has a concurrency chapter

Michael Fiano03:03:35

Thanks. I'm just going to keep studying some more. I started a project and got stuck pretty quick 🙂

seancorfield03:03:38

Searching for clojure concurrency videos turns up a number of talks from conferences... not sure how useful those would be?

Michael Fiano03:03:44

(just started Clojure last week)

seancorfield03:03:10

I see a two and a half hour YouTube video from Rich Hickey as the #1 result 👀

Michael Fiano03:03:16

That video is horrible

Michael Fiano03:03:34

Well it's a good talk, but the video quality is horrible, and the projected screen is completely out of focus

sundarj03:03:42

have you seen Clojure for Lisp Programmers?

Michael Fiano03:03:11

I'll check it out though 🙂

seancorfield03:03:23

@mfiano Have you tried this video? https://binged.it/2u8Ynse Seems like it might be more introductory...

sundarj03:03:30

may be helpful, since you are coming from Common Lisp

Michael Fiano03:03:26

Thanks for all these suggestions. I am really having fun reading and watching these talks.

seancorfield03:03:41

FWIW, this version of that 2 1/2 hour talk has great audio and crystal clear slides https://binged.it/2DIjLnH

Michael Fiano03:03:45

Oh excellent. The video I watched had Rich Hickey demo an "ant farm simulation", where there were like 2500 ants each with an agent, but I couldn't see any of his code

seancorfield03:03:04

There's so much to watch on ClojureTV on YouTube -- I have a long, long list of talks that I want to watch (or watch again in many cases).

brunobraga03:03:10

@seancorfield how do I use this kind of args ?

(defn -main
  [& args] ...

seancorfield03:03:21

(but they're not tutorials or walkthroughs for the most part)

brunobraga03:03:32

I am used to a list of args in my function, as if it was just an array

seancorfield03:03:04

@brnbraga95 The & args means that you get a single collection -- args -- which is all of the arguments passed to the -main function.

seancorfield03:03:56

Example:

(defn foo [a b & more] (println "a is" a "b is" b "more is" more))
try that out with two, three, four arguments.

seancorfield03:03:52

user=> (defn foo [a b & more] (println "a is" a "b is" b "more is" more))
#'user/foo
user=> (foo 1 2)
a is 1 b is 2 more is nil
nil
user=> (foo 1 2 3)
a is 1 b is 2 more is (3)
nil
user=> (foo 1 2 3 4)
a is 1 b is 2 more is (3 4)
nil
user=>
Does this help @brnbraga95?

brunobraga03:03:25

yes, very much

brunobraga03:03:28

thanks a lot

Gavin Ray03:03:33

This may be a ridiculous question, but I've been exploring Clojure and ClojureScript for the past few days. I've set up a development environment and managed to get an example app running with Chestnut + Rum, and set up Dirac DevTools in Chrome and figured out how to integrate the agent into Leiningen's setup and boot it from the app. After doing all of this, and exploring most of the popular frameworks available (Reagent/Reframe, Om.Next, Rum, Keechma, Fulcro, etc) it seems like the amount of actual code and work needed to write the UI in CLJS far exceeds what it would take in something like Vue + regular JS.

Gavin Ray03:03:10

Can anyone speak to whether they've been more or less productive with doing the DOM in CLJS?

justinlee03:03:09

I’ve never used vue but translating from react/redux to cljs/reagent results in much less code for me

Gavin Ray03:03:38

Would you say it's by a significant factor?

justinlee03:03:21

in some cases yes. particularly in simple components because there is much less boilerplate. when the code is super complicated, often it’s roughly one-to-one. in certain domains, like manipulating deeply nested structures, the specter library and the generally well thought out built-in collection operations are a huge win

justinlee03:03:24

i was doing a lot of fake immutable stuff to make redux happy and you just get all that for free in cljs

Gavin Ray03:03:20

I'll have to try to get my Clojure skills to some not-entirely-mediocre level and then attempt writing something.

Gavin Ray03:03:36

I've seen a lot of people recommending Rum over Reagent in posts from the past few months.

Gavin Ray03:03:48

I've looked at both and they seem pretty similar, what exactly are the differences between them?

justinlee03:03:17

there are quite a few nonobvious idioms that are super helpful and make code less clumsy (e.g. threading macros, tricks with doto/into, things of that nature)

justinlee03:03:30

Rum looks more like React. It uses macros. Reagent is a very subtle but elegant library that really works hard to make it possible to write pure functions as components. Reagent has more mindshare, though Rum is still well used and maintained.

brunobraga04:03:11

@seancorfield, do you know why when I concat [] to the return of the following function I get a lazySeq instead of a persitentVector?

(defn format-output
  [job-id agent-id]
  {"job_assigned" {"job_id" job-id, "agent_id" agent-id}}) 

justinlee04:03:49

@ray.gavin97 and both of them come with a mobx style update mechanism. both have frameworks that can go over them (reframe/citrus) that push the style you might call the event driven / pure functional / flux type architecture. I decided not to use either of them so I’m probably not characterizing them perfectly.

justinlee04:03:55

@brnbraga95 The slightly unsatisfying answer is because that’s just what concat does: it by definition returns a lazy sequence. You can wrap concat with vec and get a vector:

boot.user=> (vec (concat [:a] [:b]))
[:a :b]
boot.user=> (concat [:a] [:b])
(:a :b)

brunobraga04:03:08

thats handy, buut

brunobraga04:03:21

it gives me a 2 dimensions array

brunobraga04:03:28

my-stuff.core=> (vec (concat []  {"job_assigned" {"job_id" "job-id", "agent_id" "agent-id"}}))
[["job_assigned" {"job_id" "job-id", "agent_id" "agent-id"}]]
my-stuff.core=> 

brunobraga04:03:58

I can use first sure

justinlee04:03:22

what are you trying to do? you’ve called concat with a vector and a hash map. it isn’t clear to me what you expected that to do. keep in mind that when you do that, the map will be treated as a sequence of 2-item vectors:

boot.user=> (seq {:a :b :c :d})
([:a :b] [:c :d])
That’s why you’re getting weirdness

brunobraga04:03:24

pretty much I am reading from a json file, and I want to write back in the following format

brunobraga04:03:43

[
  {
    "job_assigned": {
      "job_id": "c0033410-981c-428a-954a-35dec05ef1d2",
      "agent_id": "8ab86c18-3fae-4804-bfd9-c3d6e8f66260",
    },
  },
  {
    "job_assigned": {
      "job_id": "f26e890b-df8e-422e-a39c-7762aa0bac36",
      "agent_id": "ed0e23ef-6c2b-430c-9b90-cd4f1ff74c88",
    }
  }
]

brunobraga04:03:29

when I read from the file I get a clojure.lang.PersistentVector as type, so after processing my data, I want to same type so that I can be able to write back in the file with the right formatting

justinlee04:03:53

so if you already have that stuff in a map, just return [my-data]

brunobraga04:03:56

but my format-output function returns a lazySeq so the file does not come out well formatted. Also each element from the read file has a tipe of clojure.lang.PersistentArrayMap and each element of my function has type clojure.lang.MapEntry..so yeah I am trying to format the output, both the outer wrapper as a persistentVector and each element as a persistentArrayMap

justinlee04:03:44

like, where ever you are passing the data to be written, just pass [my-data] instead of my-data

brunobraga04:03:52

thanks @lee.justin.m I actually had to combine something similar to what you said and also use into []

brunobraga04:03:38

(type (first (into [] (concat [] [{"job_assigned" {"job_id" "job-id", "agent_id" "agent-id"}}]))))

seancorfield04:03:13

@brnbraga95 You can simplify that by using into [] instead of the concat []

👍 4
seancorfield04:03:17

(into [some sequence] [another sequence]) -- no need for concat if you want eager sequences and vectors

seancorfield04:03:40

(sorry, I had to step away for dinner so I couldn't answer earlier)

seancorfield04:03:33

And, as @lee.justin.m pointed out, you're turning hash maps into sequences and getting a sequence of MapEntry elements -- effectively vectors with two elements, a key and a value.

brunobraga04:03:35

I got it now, I was confused why I was getting MapEntry since in my mind I was just pushing one data type into a vector, so it did not make sense to me why it was changing types

sundarj10:03:50

concat is for lazily combining two sequences together:

=> (concat [1 2 3] [4 5 6])
(1 2 3 4 5 6)
=> (concat [1 2 3] {:a 2})
(1 2 3 [:a 2])
into does the same, but non-lazily, preserving the type:
=> (into [1 2 3] [4 5 6])
[1 2 3 4 5 6]
=> (into [1 2 3] {:a 2})
[1 2 3 [:a 2]]

sundarj10:03:04

if all you want is to add an item to a collection, you use conj:

=> (conj [1 2 3] 4)
[1 2 3 4]
=> (conj [1 2 3] {:a 2})
[1 2 3 {:a 2}]
=> (conj {:a 2} {:b 6})
{:a 2, :b 6}
=> (conj {:a 2} [:b 6])
{:a 2, :b 6}
=> (conj (list 1) 2 3)
(3 2 1)

brunobraga04:03:37

thanks a lot

lepistane14:03:14

Why is something like mount and componenet needed for non-trivial clojure project? Are there any articles or resources or books that explain it like i am 5? Could anyone give me practical example?

joelsanchez14:03:37

if you want to do code reloading, you will probably use clojure.tools.namespace.repl/refresh if you use that, changed namespaces will be recompiled and their state will be lost (including defonce, atom...everything) to avoid breaking your development flow, you need those states to be kept between reloads hence mount will keep them for you: (defstate my-something :start (return-some-value-to-be-kept)) after (mount/start!), my-something will be whatever was returned as the result of that fn call, even after refreshing the containing namespace

joelsanchez14:03:21

think of db connections or any long-running process or global atom

manutter5115:03:45

@lepistane You might want to watch Stuart Sierra’s talk where he first introduced Component. https://www.youtube.com/watch?v=13cmHf_kt-Q

manutter5115:03:38

if I recall, he spends some time up front explaining the problem Component is intended to solve

gklijs15:03:11

Bur for small projects Component is a bit overkill, the problem is small projects might become big, and it might be hard to switch to something like Component later on. Also there are nice tools like https://github.com/walmartlabs/system-viz that work with Component.

cms15:03:43

hi everyone, I keep hearing about this idea that functions can just take maps as input, and return maps as output - can you tell me about specific examples in the core library (or anywhere else) where I can see this design principle in action?

donaldball15:03:36

I’m not super familiar with its internals, but alda strikes me as a plausibly accessible example, see e.g.: https://github.com/alda-lang/alda-core/blob/master/src/alda/lisp/events/chord.clj

donaldball15:03:14

where in this section the primary data structure seems to be a score, and most functions are just applying various changes to it

oVerde15:03:19

So am trying to migrate some vanilla JS to CLJS and I have this quill.on(Quill.events.EDITOR_CHANGE, function(eventType, range) { Is it right to go with:

(.on @this js/Quill.events.EDITOR_CHANGE
             (fn [eventType range]

manutter5115:03:24

@cmscalzo pretty much all of the ring middleware follows that pattern: request map comes in, modified request map gets passed to handler, handler returns response map, middleware returns modified map

manutter5115:03:59

Some middleware modifies only the request, or only the response, but that’s the general pattern.

cms15:03:35

thanks @donaldball @manutter51 - is this a commonly used pattern in Clojure?

donaldball15:03:50

it’s ubiquitous, I’d say

☝️ 12
cms16:03:15

so is it always one map in, one map out, or could you have more than one map in, and perhaps other (non-map) parameters too?

joelsanchez16:03:17

that's also common (as in most other languages) but doesn't scale to many arguments

joelsanchez16:03:09

(defn my-fn [channel data owner message table type value kitties]) you better remember the order of that....

donaldball16:03:24

As with all things, It Depends, but in my code, it’s fairly common to have business fns that operate on a data map that also take args that establish the context

cms16:03:24

I see - thank you!

jonrob18:03:20

trying to connect to figwheel on a remote server

jonrob18:03:25

dev tools says Firefox can’t establish a connection to the server at <ws://localhost:3449/figwheel-ws/dev>

jonrob18:03:50

but my figwheel section of cljsbuild in project.clj has:

jonrob18:03:50

:figwheel {:on-jsload "puzzle-helper-browser.core/on-js-reload" :websocket-url "ws://[[server-ip]]:[[server-port]]/figwheel-ws"}

jonrob18:03:20

i don't know why it's not being respected - have tried :websocket-host too to no avail

drewverlee18:03:34

I want to see if there are any open source clojure projects i can contribute to. I have a couple ideas already but i would like to do a survey of the landscape to see whats out there. How would I go about collecting information about open source projects? Some routes i see: * Search github * https://www.codetriage.com/?language=Clojure

jumar07:03:53

@U0DJ4T5U1 one list is here: http://open-source.braveclojure.com/ Not sure if it's outdated or not. Generally, it's best to contribute to something you really use so you have a real motivation to do that 🙂. Clojurians log app might be a good candidate too: https://github.com/clojureverse/clojurians-log-app

👍 4
jonrob18:03:27

ah, i don't know why, but i had to rm the entire resources/public/js/compiled/out/figwheel directory

jonrob18:03:39

seems like lein figwheel doesn't regenerate this when the configuration changes?

athomasoriginal18:03:52

Some tools like str are part of the core, but other tools like clojure.string/ have to be imported, but yet they are also part of the core, no? In everyday conversation, how does one distinguish between these?

athomasoriginal18:03:53

E.g. If I am talking to someone about tools provided by clojure, how do I refer to all the items already imported, like str and the other tools that you have to manually import?

alexmiller18:03:39

everything in clojure.core is automatically referred into every namespace (by ns)

alexmiller18:03:01

things like str are in clojure.core

alexmiller18:03:50

the namespaces included in the clojure artifact are collectively the Clojure standard library (although people often colloquially refer to it as “core”)

alexmiller18:03:41

the term “import” is usually reserved for Java classes and not for Clojure vars, where the term “refer” is the standard verb

alexmiller18:03:38

both “import” and “refer” are nothing more than mechanisms to use shorter (less than fully-qualified) symbols to refer to classes and vars

athomasoriginal19:03:26

Good point on "import" v "refer". Oh, so str and clojure.string are both provided, the key difference is that in order to use something like split, I have to use the fully qualified clojure.string/split

alexmiller19:03:09

to use any function from outside clojure.core, you need to load the namespace (either directly or more commonly via require or ns with require)

alexmiller19:03:20

once you do that, you can use it fully qualified

alexmiller19:03:54

or you can refer to use a shorter name in the context of a particular namespace (the current one)

athomasoriginal19:03:09

I just reviewed the Clojure API again, with the info that you just passed on, and it seems that there are the clojure namespaces. One is clojure.core and this, as you mentioned is automatically referred. However, I can also access other namespaces, like clojure.string, but I have to refer it into my file, or use the fully qualified namespace, yes?

athomasoriginal19:03:15

So this would account for all the namespaces included in the Clojure Standard Library - https://clojure.github.io/clojure/

alexmiller19:03:13

some namespaces (like clojure.string) may be loaded in the course of bootstrapping, but you should never rely on that being the case. in the future we may optimize startup performance by avoiding those loads for example.

alexmiller19:03:39

so always ensure a namespace is loaded before using it (typically by including a require clause in the ns in your source)

alexmiller19:03:30

and re refer or fully-qualified yes (after it’s loaded)

athomasoriginal19:03:06

Thanks! Very helpful

seancorfield19:03:38

Some of the lint tools will highlight uses of qualified namespaces without a load (`require`) which is useful. I'm guilty of using clojure.pprint and clojure.stacktrace at times without a require and I know I shouldn't do that 😐

alexmiller19:03:05

I abuse pprint that way all the time, but only for debugging :)

seancorfield19:03:32

When I first started doing Clojure (2010) I was very fast and loose with this sort of thing -- with use (and, later, :refer :all) -- until it started biting me, and then I got more and more careful about using :require .. :as .. and I only use :refer for names that look awkward with an alias (for example, when using the Expectations testing library, I find it more readable to :refer [defexpect expect more more-of] etc than to litter my test code with e/expect etc).

seancorfield19:03:15

In test code, I will deliberately :refer :all for the namespace under test but that's about the only place I ever do that now.

seancorfield19:03:38

Even in the REPL, it's good practice to (require .. :as ..) and use the alias.

johnj19:03:45

was wondering why was pprint working 😉

alexmiller19:03:07

the repl refers a couple extra things in the user namespace too (like pprint)

johnj19:03:59

Yeah, I was not in the user ns

dpsutton19:03:23

if you're using CIDER, hit , (comma) on the repl and you'll get an option to require the repl utils in your current namespace

dpsutton19:03:41

among other features like refresh, restart, etc

johnj19:03:52

cider is too much magic for me at this moment

seancorfield19:03:40

@dpsutton I am beginning to consider going back to Emacs and trying a stripped down configuration to see how I get along (after two years away from it).

dpsutton19:03:09

nice! i love the way the newer tools look but emacs is just so nice for me. I'm working with @bozhidar’s prelude https://github.com/bbatsov/prelude but he uses a stripped down https://github.com/bbatsov/emacs.d that is much simpler

dpsutton19:03:57

i'm not an init tinkerer. i just use it as is mostly

johnj20:03:40

how do I start pinpointing which library is causing a java.lang.NoClassDefFoundError ?

johnj20:03:27

looks like the exception is being catch by the datomic cloud client, but from there I don't know if its the client itself or one of its dependencies, I'm guessing a dependency

johnj20:03:26

is possible the client is throwing and ending the exception with an error before the stack trace finishes?

seancorfield20:03:50

@lockdown- What class does it say is not found?

seancorfield20:03:42

@dpsutton I was using Prelude before I quit Emacs. My colleague uses https://github.com/technomancy/better-defaults as a basis and has just a few packages installed on top of that. I used Emacs Live for a while before Prelude. Along the way I've also hand-crafted a couple of different configs. I'll probably try Phil's minimal setup first and maybe try Bozhidar's if I find the minimal setup too annoying.

seancorfield20:03:20

(and we should probably go to #emacs or #cider to follow-up on that I guess)

👍 4
johnj20:03:51

@seancorfield javax/xml/bind/DatatypeConverter - is fixable adding the java.xml.bind module but wanted to find out what libs is causing it

alexmiller20:03:29

using java -verbose:class will show you classes as they’re loaded which might tell you what was loaded right before

👍 4
johnj20:03:03

looks like it might be this aws sdk version

alexmiller20:03:02

seems logical. can’t escape the angle brackets…

Michael Thurmond21:03:26

I ran into an issue using reagent and was curious if anyone could help me out? Thanks! https://stackoverflow.com/questions/49419189/render-table-element-with-colspan-in-reagent

justinlee22:03:28

I think I answered your question. I may have misunderstood what you were trying to do.

Michael Thurmond21:03:14

thanks man! I need to rememebr to use reduce more often. Pretty slick. But I still dont understand why I can't use the for loop

justinlee21:03:29

oh i think you could have. but, generally speaking, reach for map first, reduce second, for third, and loop/recur fourth

justinlee21:03:14

the real trick to what I did was to use into to “append” your 2 elements into an accumulator

justinlee21:03:52

with for you could have had to use something to flatten those 2-element vectors in a second step

justinlee21:03:16

i answered on stackoverflow too

Michael Thurmond21:03:45

thanks, so building reagent components, you would recommend using reduce to build the ui?

justinlee21:03:48

you can and should feel free to use whatever sequence functions work for you. that’s really the goal of putting up with all of the horrible tooling and other BS: the pleasure of using the good parts of the language. the only thing you have to watch out for is that you need to wrap lazy things into a doall if they dereference a reagent/atom inside.

Michael Thurmond21:03:31

thanks again, I learned a lot from this

Michael Thurmond21:03:29

what do you mean by horrible tooling and other BS?

justinlee21:03:42

getting stuff up and running in cljs is not that smooth. error messages aren’t that smooth. there’s a great of analysis paralysis in the beginning to figure out what libraries you should use. and of course importing npm libraries is a nightmare. just stuff like that.

Michael Thurmond21:03:09

haha ok I see what you are saying

justinlee21:03:00

i’m guy who wants maximum developer power. javascript but better. cljs is almost there but still has a lot of friction.

justinlee21:03:11

one point on the reagent stuff: the thing that is continually confusing, particularly if you’ve used react in javascript, is that JSX and hiccup are not the same thing. hiccup is another layer of runtime indirection: it is data that is calculated at runtime and then passed to reagent, which then creates react components and elements. it’s helpful to remember this because it means you can do any data transformation your mind can come up with

Michael Thurmond22:03:12

My only dev experience is in the clojure space

Michael Thurmond22:03:34

still pretty green, but i really enjoy the language.