This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-07-23
Channels
- # announcements (2)
- # beginners (165)
- # boot (11)
- # cider (11)
- # clj-kondo (7)
- # cljdoc (1)
- # cljsrn (5)
- # clojure (120)
- # clojure-dev (21)
- # clojure-europe (3)
- # clojure-france (1)
- # clojure-italy (62)
- # clojure-nl (8)
- # clojure-spec (26)
- # clojure-uk (40)
- # clojuredesign-podcast (1)
- # clojurescript (3)
- # cursive (2)
- # data-science (2)
- # datomic (10)
- # emacs (2)
- # figwheel-main (1)
- # fulcro (17)
- # graphql (5)
- # hoplon (5)
- # jackdaw (15)
- # jobs (2)
- # juxt (1)
- # luminus (5)
- # off-topic (1)
- # onyx (11)
- # pathom (4)
- # pedestal (1)
- # re-frame (4)
- # reagent (11)
- # reitit (1)
- # remote-jobs (5)
- # shadow-cljs (48)
- # spacemacs (2)
- # specter (4)
- # sql (24)
- # tools-deps (25)
- # vim (82)
i think i already know the answer to this, but are there any conventions or mechanisms for organizing clojure code in the same file?
like, there's no way to define multiple namespaces in the same file, i assume
Hi everyone!
What is the idiomatic use of loop
? I mean, where would you use this instead of just calling the function recursively itself?
Every time you call a function you allocate a new frame to the stack and might run into StackOverflowError but loop-recur mechanism uses tail call optimization which creates only one frame during the whole recursion
Typically you prefer loop
because it doesn't consume the stack. Clojure does not have tail call optimization, so to compensate it includes the loop/recur macros that convert recursive looking forms into loops. Now, the target of recur
can be the 'current' function, but often it's inconvenient to have to write a whole function form to create a possible recur context. The loop
is useful for this.
Aaah, I see—so does that mean the preferred way of writing recursive functions in Clojure in general is to use loop/recur? I’m playing with the language for some time now and have mostly seen calling the function itself by name or using recur, that’s why I’m surprised
Depends on the problem. In some cases, it's cleanest to recur to the function callsite, in other cases it's cleaner to recur to a loop target. In general, it's best to avoid recursive calls unless you're returning a lazy sequence, which will produce values without consuming stack.
there's a nice, short talk on loop/recur here, which covers some of it's details, as well as its weaknesses. Hopefully some of these problems will be addressed in a future clojure release: https://www.youtube.com/watch?v=SJmK1R0ADnc
I am using reagent/re-frame to build some FE. After a while of development my browsers starts to eat up all the memory. What is usual the issue here?
Use your memory profile dev tools to capture a memory profile and see where the RAM is being used
One problem I keep running into is not being able to decide what the best way of writing a piece of code. For instance, I have a date that I need to get into the YYYY-MM-DD
format from a regular UTC time stamp. I came up with 3 different ways to do this with each IMO having their pros and cons.
The first one is more descriptive and I believe tells you exactly what I am doing.
(->> (-> decision :updated_at tco/from-string)
(tf/unparse (tf/formatters :date)))
(the nested threading I am not too fond of tho)The second and third one seem straight forward
(first (clojure.string/split updated-at #"T"))
I am pretty sure you can avoid nesting thread in this case
(->> decision
:updated_at
tco/from-string
(tf/unparse (tf/formatters :date)))
I didn't test it but I think it should workpersonally I find it most readable
Yea I agree. Plus if the format of date changes then I have to remember to come inside this function and change the regex. Whereas in this case it should handle most changes.
I think the first one is the best solutino for "parse", but maybe put (tf/unparse (tf/formatters :date)) in it's own function to remove the nesting
After some thinking I think the first one is the better solution. Its less brittle IMO
so I'm making a program that is going to have a server and a client and some sort of database for the server to communicate to. I want to use vagrant and ansible to develop locally for now. Is having two programs under one project as simple as dividing the code base between server and client, or do I have to do special things in deps.edn to build server code and client code?
deps.edn doesn't even build - in this case do you mean constructing separate classpaths or a separate build tool?
I would assume you'd have one deps file for the client process, and another for the server
This is kind of what I was getting at, I'm very new to all this so I'm trying to get the 'hello world' of setups with ansible and deps.edn, but struggling to figure it all out you know?
deps.edn is a tool for constructing a classpath, so I assume it would be useful for the ansible build for that specific usage. Often when packaging people want to set up a persistent cache of external artifacts on CI, and point the dep resolution to that cache
can I ask, what is a classpath?
in the jvm, the classpath is the list of locations used for finding resources, code, or class files
okay, and deps.edn is a way of saying 'here's a package, heres a list of files it brings to the table so use these
and stuff like that?
what deps.edn (or lein, or boot) do is take a list of dependencies, resolve their tree of transitive deps, download all the ones you don't have already to a cache, then point your java classpath to all those artifacts
I get it
thank you
it's not unusual in my experience for a clojure program in production to have ~20 explicit deps that are used directly, and hundreds of deps total once they are transitively resolved
in a running clojure program you can see your starting classpath with
> (System/getProperty "java.class.path")
Yeah my haskell programs had lots of dependencies
the reason I'm a little confused is because I've never done server/client applications in any language so I'm learning the theory and the practice slowly
right - so in theory your server and client could be 100% independent codebases and share nothing but an implicit agreement to use the same resource paths on some protocol
in practice, with clojure, one advantage is we can share the same data functions and configs between front end and back end code, to simplify that distributed interaction
(of course you can do this in any language if the server and client use the same runtime environment, but with clj / cljs we can do this with java backend and javascript browser client)
I don't mind having a server
and client
folder to seperate the codebases, but it would be nice to keep it all under the same project I guess?
at least until the client gets too big it should split off
are they server and client both jvm clojure? is it clj / cljs?
well, I haven't made anything yet. Right now I have a hello world reagent app
those were two different options
oh, clj / cljs OK
The client will be cljs
and the server clj I presume
The goal today is to just have some data on the server, just a string, and simply get it sent to the client to be displayed. Then stage two would be storing that in a database and learning how to get info out the db to the server, then serve it to the client
I don't want to do much, I just want the basic knack down and go from there
in my experience this structure was good: src/clj/foo/bar
- everything under this path is server code, src/cljs/foo/bar
- everything under this path is client src/cljc/foo/bar
- everything under this path is code used by both client and server (custom data logic that both ends want, in particular)
for example a data validator would go in src/cljc so that client and server would implicitly agree on data format
with deps.edn I'd use one deps file to build deps for the jvm process that compiles the cljs to js, and another to build the deps for the server process
with leiningen it's easier to put all of this in one project file
I'd probably write server / client to make it easier for me but I take your point
Where would the location of these edn files go?
there's a strong convention to using clj / cljs / cljc as directory names
ooh okay
consider that you could also end up with java / js dirs
I did some work on braid.chat and server/client is how they were
that's fair, but breaking it up by file suffix simplifies things in the case where cljc can be loaded by both cljs and clj
I was wondering about this article: https://semaphoreci.com/community/tutorials/how-to-set-up-a-clojure-environment-with-ansible
It talks about setting up two roles, java
and lein
. how exactly do the two differ other than one is using a REPL and the other is just the program?
Or will they mostly do the ssame things? (I'm just thinking, how I'm going to do this when I'm not using leiningen so)
lein is a build tool - it constructs a class path, runs dev tasks, builds artifacts, etc.
java is the vm that actually runs clj code (even lein uses java to carry out the task you ask it for)
so in your case, you are trying to replace lein with deps.edn
you'll need to find some replacement for the lein uberjar task (which constructs an artifact to deploy), but otherwise deps.edn can construct a classpath and run a repl
okay thats great, so while the building the artifact isn't something I can do, I can still replace lein (I know I can do a repl so hopefully I can hook this into that?)
well lein is doing multiple roles, and the premise of deps.edn was to specialize away from that - so you've replaced some lein usecases but not all the lein usecases in that blogpost
okay gotcha
oh wait - that blog post is doing a bad thing - using lein to run a server process :/
which is good news for you because deps.edn is actually OK for running a server, lein isn;t :D
ahaha woohoo 😛
I assumed they would be using lein to build an uberjar - that's the sensible way to do ops with lein, but they are instead using the build tool to run the process in prod
it's the equivalent of shipping source + Makefile to your server, then running gcc before startup :P
im still trying to get my head around roles.. so, a role can do tasks, and sometimes you can have a common role to do common tasks. But in this post, the lein
role just installs leiningen.. I don't really see where the magic happens
it isn't used to run leiningen?
its tough because this tutorial is working with code thats already written
---
# config/roles/lein/tasks/main.yml
# Install leiningen
- name: Copy lein script
copy: src=lein dest=/usr/bin/lein owner=root group=root mode=755
They store a copy in the configuration and just copy it over, so I'm not really sure where in this post it starts the server? Like that's what I'm looking for at least
by the way thank you for talking about this with me I should have asked rather than bombard you with questions like I have 😞
nothing here looks specific to that codebase though: no matter how you code your app, you will end up running -main
in some namespace to start a service
oh, I accidentally answered your question above: the convention is for program entry points to be named -main
, so that is what starts the service
you can pass an argument to clojure.main to start the -main in a specific ns instead of a repl, and this is how one runs a clojure service if they aren't crazy like whoever put together this blogpost
there's a few reasons not to use lein to run on a server: lack of concrete redeployable artifact, useless parent process that starts up only to create your classpath, the wrong jvm settings for running a server
using deps.edn is luckily better behaved (but I'd still recommend making an uberjar or similar that allows recreating a specific deploy)
okay.. I'm trying to connect the dots as there's a lot of buzzwords but not much connection, or at least, its not so clear to me.
Vagrant fires up some virtual machines. You give it a file name as a playbook which is a set of tasks given to a set of roles.
Why is there a need for the leiningen
role if it is just a single task. I assume when you switch from local to a server, you would edit your playbook and change the role from lein
to java
, but I'm trying to connect the playbook to the tasks
NB: often you'll get a much better deploy setup with clojure itself by finding the instructions for setting up a java project, then using an uberjar using clojure.main + your source where they would use a java fat jar
I know nothing about ansible roles - based on how they cargo cult the clojure stuff I wouldn't be surprised if they were using ansible weirdly too
So in his example, common
role has a task called Install motd
. I can see it, it places some data somewhere I assume for the program to grab.
However, the playbook is also a list of things. What are these things? So, the only one I have is named Apply common configuration
and looks like this:
---
# ansible/provision.yml
# Provision development environment
- name: Apply common configuration
hosts: all
sudo: yes
roles:
- common
So, to all the hosts in the vagrant the common role is.. applied? And in doing so all of common's tasks are completed automatically?I might actually go and write my own tutorial after I crack this as without a background in networking it's not so easy to get into this
maybe someone else here knows - or maybe someone on an Ansible forum
Yeah. Unfortunately there's no ansible channel as its not a clojure thing
but I'm going to need to ask further
thank you for your time though ❤️
I mean - maybe they have their own slack or IRC or whatever - big parts of what you need to figure out are not clojure related
yeah thats the struggle
it should be possible to break this up into domain specific parts: a generic ansible setup with a spot for "construct the artifacts your program needs on deploy" - an ansible expert could help there
then a clojure expert can tell you what goes in that spot
Finding itweird that it's going to require an expert to show me these things, I'm going through the ansible docs for a bit I think
I think one systemic issue is that at most one person needs to sort this out for a given project in most cases, and the task is done once per project and rarely needs to be updated
so there's a lot of "barely familiar" people, and few who really know it well
I get that.. Hopefully I can get the hang of it too so I can help others
A role isn't what I thought it was. A Role is a self-contained playbook, so a playbook can contain tasks as well as the roles, and the reason I didn't see the tasks get called before is purely because they're called not by the playbook but by the role
The role isn't a category but an active thing
Hi, i'm using the clj-http
library to perform a POST request and I'm receiving this error
the payload is no that big in order to reach some kind of overflow, however I imagine that this is the case
i googled this error and it seems to be related to teh default tls tranpsort on java 1.8
@iagwanderson there have been a few issues with the TLS1.3 stack on 11 -- some fixed in 11.0.4
I would look into either disabling TLS1.3: SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setExcludeProtocols("TLSv1.3"); or bumping to 11.0.4
@ghadi do you have any idea of how to disable the protocol on the clj-http
library? I've beein searching for this
setProperty ?
but I still don't get how this is associated with the size of my payload. If I send less items in the request, I get no errors
I' getting a really strange error running my starter project here, from lein new compojure to tryna throw in HTTP-KIT...
xception in thread "main" Syntax error macroexpanding clojure.core/ns at (clojure/tools/namespace.clj:15:1). Call to clojure.core/ns did not conform to spec.
sounds like your template used an old version of clojure.tools.namespace
(or pulled one in transitively)
@sova check the output of $ lein deps :why org.clojure/tools.namespace
` [ring/ring-devel 1.1.8] [ns-tracker 0.2.1] [org.clojure/tools.namespace 0.1.3]`
yeah, that's way old - if you explicitly ask for 0.2.11 before ring-devel in the deps list that error will go away
(there might be a newer version still, but I have proof locally that 0.2.11 does not have that error)
@noisesmith i love you
thank you
how do you do the voodoo that you do
XD tell me more about :WHY
it's a subset of lein deps :tree
focusing on a specific dep
you can check out lein help deps
to see more
neato. lein deps 🌴
lol :tree
there's also :plugin-tree
and :tree-data
Who are you, who are so wise in the ways of science? Arthur, King of the Britons! /holygrail
thanks for your lein help
haha - just a person who'se been on various clojure channels for a long time