This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-20
Channels
- # announcements (42)
- # babashka (70)
- # beginners (152)
- # chlorine-clover (19)
- # cider (14)
- # clj-kondo (23)
- # clojars (15)
- # clojure (86)
- # clojure-denmark (1)
- # clojure-dev (5)
- # clojure-europe (57)
- # clojure-france (145)
- # clojure-hungary (2)
- # clojure-italy (5)
- # clojure-nl (7)
- # clojure-spec (35)
- # clojure-sweden (2)
- # clojure-uk (58)
- # clojurebridge (1)
- # clojured (1)
- # clojurescript (50)
- # core-typed (9)
- # cursive (10)
- # data-science (11)
- # datascript (4)
- # datomic (25)
- # emacs (8)
- # fulcro (49)
- # graalvm (7)
- # graphql (6)
- # joker (1)
- # juxt (2)
- # kaocha (1)
- # off-topic (22)
- # other-lisps (1)
- # pathom (20)
- # re-frame (3)
- # reagent (11)
- # reitit (2)
- # remote-jobs (1)
- # shadow-cljs (44)
- # spacemacs (2)
- # sql (17)
- # tree-sitter (2)
- # vim (8)
- # vrac (2)
[:app] Configuring build. [:app] Compiling ... To quit, type: :cljs/quit [:selected :app][:app] Build completed. (551 files, 1 compiled, 0 warnings, 6,73s) No application has connected to the REPL server. Make sure your JS environment has loaded your compiled ClojureScript code. Happens right after starting emacs and issuing cider-jack-in on a project that works fine and just fidling around in a .cljs file. So weird.
That’s a cljs repl starting up. It’s basically a jvm program that evaluates your cljs output in a JavaScript engine. It’s saying all is ready but you need to connect to a JavaScript engine. Usually by loading your app in a browser or running node on your generated cljs script
this is a silly question but back in java-land, i'm used to writing objects with methods that refer to some state that object was originally initialized with. an example might be a client that requires some broad configuration and then exposes a few methods. is there a comparable pattern in clojure?
you can close over state when you construct a function or reify an interface
like this?
(defn f1 [a b c d] ...)
(defn f2 [a b c d e] ...)
(defn make-client [a b c]
{:f1 (partial f1 a b c)
:f2 (partial f2 a b c)})
that's just a naive guess - would something like that be idiomatic?
(defn make-client [option1 opt2 opt3 ...]
{:option1 option1
:option2 opt2
...})
(defn get-items [client-map some-other-arg ...]
...)
So say you had the Java class:
public class Client {
private int x;
private int y;
public Client(int x, int y) {
this.x = x;
this.y = y;
}
public method1() {...}
public method2() {...}
}
the "client" here is just a hash-map that groups the common args, looks like
So the above class would become:
(defn make-client [x y]
{:x x
:y y})
(defn method1 [client] ...)
(defn method2 [client] ...)
that's too simple
i love it. thank you!
And the difference will be that, the map is immutable. So your defns are not really methods anymore, because methods are assumed to mutate the fields. In our case, if you only need to read from the fields, you just read what you need from the map. But if you need to modify the fields, you would instead return a new map which is the given client map with whatever changes applied to it.
i feel like another important difference is that we've mostly eliminated the abstraction that is a stateful "client"
the fact that it's still called a 'client' notwithstanding
Ya, it depends. If the things in your client map allow you to make a remote call to a mutable database, there's still some state in that sense, but it's moved away from your "client" object, and is now where it should be, in your DB for example
And what's nice with this, is you can now call it like so:
(-> (make-client 10 20) (method1) (method2))
Which is often the case. Like everything that would be void in java, in Clojure would instead return the client-map
And if you want to group the client and all its methods into one logical place, then just create a namespace for them and shove it all there 😛
This pattern can extend quite far, if you ever need some polymorphism, you can make the map a record, and put the functions inside a protocol. Or keep it a map, but modify some of the methods into multi-methods, etc. Lots of options for handling all possible scenarios
If people find they are confused about what a client contains, you can create a spec for it. And on and on...
thank you again, this is great
No problem. It can be hard in the beginning to peel the onion. I came from OOP as well, and I think your question is just normal, everyone who does has it, we're almost too used to complexity 😛, that we find it hard to think without it
really, for me, the worst part is that the concept of a "client", as an object with state and behavior, is accomplishing nothing. the pattern of simply grouping together the data that happens to be shared gets you all the practicality and none of the useless abstraction
@U0K064KQV I was going through this thread as I am in general interested in patterns. About treating a namespace as a poor man's class, do you actually use it in production code? I think the aspect of multiple instances of client class with independent states is lost with this approach. All you have is a global shared state.
@UJRDALZA5, if I understand the thread, I think that would be true if there were defs in the namespace containing the state. But I don't think he's suggesting that. Rather a map contains the state and is passed to each fn. So there can be any number of maps (OO instances).
Ya, @UBRMX7MT7 is correct. The pattern here is that "make-client" acts as a constructor for instances of your data.
This is really interesting to me. Not really seeing the difference between getting values (“state”) from a function vs. from a variable of some kind. In both cases it’s a symbol that evaluates to values. Help? 😳
But, some use cases in OOP make use of static fields. And in clojure, those would just be global defs
@UCW3QKWKT Hum... imagine you have a Contacts app where the user can create new contacts.
Because, the user will be adding contact dynamically, at runtime. They could add from 0 to n of them, who knows
And you can't predict what name or phone the contacts are going to have. So what you need instead is a way to both parameterize your contact map, but also possibly create many of them, all with different names and phones
So now when the user press "Add contact" and enters a name and phone on the form and clicks submit, you can use make-client to dynamically create a new instance of a contact
With a def, you need to know the values ahead of time, and how many unique contact you'll have.
But with a defn, you don't, you can wait till runtime and then use it to create as many of them with whatever values as you want.
But we can have a (def contacts (atom []))
. For any non-trivial apps, I think there will always be a giant state map anchored to some namespace somewhere.
A lot of apps will store the states straight into a DB of some sort. And some others can just carry around state through from start to finish, including long lived apps by using recursion
DB is just an extension of what I said. The data has to be anchored to something. But I am very curious about the other thing you said.
And some others can just carry around state through from start to finish, including long lived apps by using recursion Please expand on it if you have the time.
For example:
(def contacts (atom []))
(defn on-new-contact [name phone]
(swap! contacts conj (make-contact name phone)))
I recently answered something similar here: https://clojureverse.org/t/functional-thinking-managing-state-boardgame/5478/5?u=didibus
Sorry, my example in slack was for: "But yes, some will. But that would be in the containing component."
With the functional approach, there are even some DBs that are implemented like that. If you ever heard of a log store, or an append only store. Basically, you keep carrying last state and making new states out of it, never mutating, and once in a while you just delete the history you no longer need to save on memory/space.
Nice explanation there in the linked article! You can encapsulate even more by passing a make-board
fn in there instead of the init-board
. But you might already be doing that, since you only shared the loop/recur
part.
Yup, definitly. If your initial board needs to be parameterized that be a good idea. Like say on "New Game" you took some options, type of game, size of board, who knows
is there a naming convention to indicate that a given var might be nil or absent?
This might be related: https://stackoverflow.com/questions/5839697/why-is-the-use-of-maybe-option-not-so-pervasive-in-clojure
A point of terminology, a var is something created by a def, a global definition, those are pretty much never nil
A name bound by let or a function in clojure is called a local, and those are indeed sometimes nil
in scala we're always so explicit about values we expect to always be present and values we might reasonably expect to be missing - does lisp/clojure have a similar approach?
So, the way its done in Clojure, is that absence is represented by the key being missing from the map
So you have two concepts. First is the data is missing, that would be represented as the key isn't even there. The next one is, the data is there, but its value is nil. That would be represented with the key being there but having a value of nil
So say you had person maps, and sometimes those have a name and an address, sometimes only an address.
You would have:
{:name "Joe" :address "123 bla"}
And if its a person without an address:
{:name "Joe"}
And if its a person where an address was given, but it was garbage, or it was submitted as blank, or the user ticked the box saying "rather not say" you'd have:
{:name "Joe" :address nil}
Oh, and to specify the semantics of a particular map, Spec would be used. You can say which key are mandatory, which are optional, and which are allowed to be nil or not
Though sometimes, simply doc or comments are used, or even its just not specified if its kind of obvious from context
@michael740, I have not seen any such convention in Clojure code.
I have a failing test inside a cljc
file, when I run lein test
it does not catch the error. But in the console I see that the file was tested. I should do something different in the setup of clojure.test
for this situation?
@iagwanderson Not sure I'm following you -- but it seemed to work when I tried it
(! 779)-> lein new app bartuka
Generating a project called bartuka based on the 'app' template.
(! 780)-> cd bartuka/
(! 781)-> mv src/bartuka/core.clj src/bartuka/core.cljc
(! 782)-> mv test/bartuka/core_test.clj test/bartuka/core_test.cljc
(! 783)-> lein test
lein test bartuka.core-test
lein test :only bartuka.core-test/a-test
FAIL in (a-test) (core_test.cljc:7)
FIXME, I fail.
expected: (= 0 1)
actual: (not (= 0 1))
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
Tests failed.
(! 784)-> echo $?
1
(! 785)->
that's exactly the problem. But, if yours is working fine, it should be a problem with my current setup
I have added :test-paths ["test/cljc", "test/clj"]
to my project.clj and nothing else 😕
how do you know it is failing? Is it possible only a cljs branch fails and you aren't running tests in that environment?
found it! Look at the next example, when I use the use-fixtures
it passes with 0 failures.
(ns mamulengo.bartuka
#?@(:clj
[(:require [clojure.test :refer [deftest is use-fixtures]])]
:cljs
[(:require [cljs.test :refer-macros [deftest is use-fixtures]])]))
(use-fixtures
:each
{:before (fn [] "ok")
:after (fn [] "go")})
(deftest please-work!
(is (= 0 1)))
the api of use-fixtures
is different for both environments. I would expect some error.
actually, it seems like the test was not even recognized, which makes sense because it breaks before. Only hard to catch
Ah, yes, the Clojure code -- run by lein test
-- would try to invoke that hash map as a function, passing in the test to be executed.
so it would run ({:before,,,} please-work!)
which will "run" but not call please-work!
because that's (get {:before,,,} please-work!)
which just returns nil
I'm surprised use-fixtures
differs between Clojure and cljs like that...
You can use the same API https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/test.cljs#L199-L211
If you write a function that accepts a test function as an argument (and calls it), that will work for both clj and cljs.
Supporting that :before
/`:after` format would be a nice enhancement for clojure.test
.

I'll go ahead and implement this in expectations.clojure.test
tho'...
also, just minor thing but [clojure.test :refer [deftest is use-fixtures]
should work in both environments. don't need to reader conditional that one
when the ns requires the macros you don't need to do that downstream https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/test.cljs#L245 https://clojurescript.org/guides/ns-forms#_implicit_sugar
Hello there, What do you guys use to set up a rest api? I have seen people use Compojure and Ring but would like to know if it is the best option
Okay, maybe best options is a little too much to ask, my bad hehe I'll give this one a look, thanks!
For what it's worth, I've put up a little twitter bot that tweets a random clojure function of the day. You can find it here: https://twitter.com/rcfotd. It's new, doesn't do anything clever, but it's kinda cute 🙂 Enjoy!
What a co-incidence, I just wrote this today: https://github.com/borkdude/babashka#print-random-docstring
I did see the idea here before: https://github.com/tomekw/cotd
In the definition for comp there’s a block for composing two functions. I’m wondering why it handles 1, 2, 3, and n arguments differently. Couldn’t it just use apply for any length?
@tylertracey09 If you look at the source of several core functions, you'll see a similar "unrolling" of the first few arities -- as a performance optimization.
Can anyone recommend me a clojure book for learning purposes? I do best when I have some exercises to do as well
@tylertracey09 There's Clojure for the Brave and True (available for free online as well), Getting Clojure, Living Clojure -- those are the three that come to mind. Not sure which of those actually have exercises in them.
For exercises, 1) Clojure Koans and Exercism for basic staff, 2) 4clojure for slightly harder puzzles.
Might be just me, but as I know another language already (Java), the 1) Guides and 2) References section on http://Clojure.org were excellent resources for me. Books were too slow.
has anyone had a problem with downloading tools.deps in IntelliJ IDEA settings? I keep getting the following error Cannot execute, please download tools.deps in Settings: Cannot execute, please download tools.deps in Settings
Hi Behrokh, not sure if you already solved the issue, but it's a problem with Cursive and it's fixed in EAP only. If you don't want to download that, you can fix like this: Go to Build Tools -> Clojure Deps: Use private repo: ID: Central / URL: https://repo1.maven.org/maven2/ Then refresh and download.
thanks @U7JCZJR0W I was suffering the same.
thanks @U7JCZJR0W it’s working now.
Hello Clojurians, I'm having a problems getting access to a zero-token through a POST so that I can use it in my buffer to perform an authentication request. Now the URL here's the link ; following along a video 'Microservices with CLojure'. I'm lost on how to use this site to create a way to well, access to a zero-token through a POST so that I can use it in my buffer to perform an authentication request. Here is the relevant functions that calls the outdated api: (defn auth0-token []
(let [ret
(client/post ""
{:debug false
:content-type :json
:form-params {:client_id (System/getenv "AUTH0_CLIENT_ID")
:client_secret (System/getenv "AUTH0_SECRET")
:grant_type "client_credentials"}})]
(json/parse-string (ret :body))))
People might be able to help more if you describe what is and isn't working. When you run your code what does it do that you didn't expect? What do you want it to do?
Can someone help me with this? Thank you in advance 🙂
if you already know emacs yes. if you're just learning clojure you probably don't want to start learning both emacs and clojure. in which case I personally recommend Cursive for IntelliJ. Some others like VSCode with Calva and Atom
@tylertracey09 If the editor/IDE you are already using supports Clojure, I'd stick with that while you are learning Clojure. What are you using now?
I guess that’s what folks use the REPL for, but I saw a screencast where the guy was using emacs and he had a command that would evaluate the expression under the cursor or something
#calva-dev
Out of curiosity if you use emacs were you using it before clojure? I remember reading something about how emacs was implemented with a LISP and so you can write extensions using LISP as well. Is that what got you folks into it or did you migrate because of clojure tooling at the time?
I used Emacs decades ago, back in the 17.x/18.x days. I moved away from it round about 19.x I think. I started using C++ IDEs then Java IDEs. Eventually, after a bunch of languages, I ended up in Clojure and went back to Emacs because it was the "best" / "most popular" -- and was shocked that it hadn't changed much in... twenty years?
I went back and forth between Emacs and other editors for a while, when learning Clojure, then settled on Emacs... until I saw Atom/ProtoREPL at Conj one year! I switched to Atom and never looked back. ProtoREPL is no longer maintained (and I think it's actually broken in recent Atom releases?) but I switched to Chlorine over a year ago and I love that combination (Atom/Chlorine, plus Cognitect's REBL data browser, with a simple Socket REPL -- no nREPL etc).
@U4R5K5M0A I think Chlorine starts a prepl once it has a plain socket connection.
The socket REPL is nice because you can a) telnet/netcat to it from your phone b) connect to it via unrepl/unravel c) connect from Chlorine ...