Fork me on GitHub

@john What would you recommend for managing resources that have a start/stop lifecycle then, given that you need to be able to retain a live REPL experience (with some level of code reloading).


@seancorfield some component like thing, sure. But do all web services really have such complex runtime life cycle interdependent resources? I guess it depends on how you archetect your services. defonce is often good enough for simple things imo.


There is also "reloaded.repl" to go with Component, looks very labor-saving


Database connections, caching layer, environment/configuration setup, tons of other stuff benefits from the start/stop lifecycle


If you have all those things, and you have complex runtime dependencies between them, sure. And it's nice that there's a common abstraction for that.


I haven't found I need to actually refresh namespaces and there are enough gotchas with full reloading that I avoid it.


Also if you use Component as dependency injection then it looks like it would let you have several alternative setups or build a mini-system somewhat a la carte


uh oh gotchas?


Component's DI allows you to easily swap in "mocks" for testing, yes.


@seancorfield You encountered glitches with full reloading?


I see a lot of people running into problems with it, yes. I've also seen a lot of people who've set up ProtoREPL for Atom using Jason's opinionated guide run into refreshing problems -- and I recommend they uncheck those three options in ProtoREPL.


It seems like it often blows away things in namespaces that they don't expect and they run into errors relating to that which they don't understand (and have to restart their REPL anyway).


hm yes everything you've done in the 'user ns is gone.. but as long as the reload-all is preceded by component/stop and followed by component/start, the big picture should be ok!


OTOH it reloads from disk. So if you draft work in namespaces and do not save it, I guess it's lost


@phill I tend to work a lot against the REPL by evaluating top-level s-expr's without saving files. I use comment blocks for code that I'm using for exploration and tests -- also evaluated directly as s-expr's into the REPL without saving. I have component start/stop calls in comments too, but mostly I start the system and eval code live into it for hours as I develop.


I don't tend to have a workflow these days where I need to do full reloads -- and even when I need a bit more brute force that just loading a single file into the REPL, a (require … :reload-all) is sufficient.


(not to interject, but what are the pro/cons of component vs the defstate stuff in mount)


@emccue My feeling is that defstate in mount is still global state and should be avoided. I like component's ability to have multiple distinct instances live in my REPL at the same time.


what I like about mount is that it allows me to write my code mostly like I would expect if I wasn’t use mount, e.g. vars referring to other vars in namespaces


it’s more on the easy side of the simple vs. easy continuum


but you do lose some power, like @seancorfield said


I like my functions to rely solely on their parameters (and other functions) -- so if they're doing DB stuff, they should be passed the db-spec (or something that contains it).

❤️ 5

When we got started with Clojure at work back in 2011, we didn't start with Component... and we're still regretting that...


We've worked very hard to adopt Component and to refactor code to remove the global state that we had to start with.


sure. and you can still do that in mount. mount states are just vars


So I'm very strongly against global shared state these days because of that experience.


Vars are global shared state.


right. I see what you’re saying


maybe a tangent for offtopic, but what were the kinds of issues you ran into?


typically the way I end up writing my applications, is that different namespaces might declare different states. those states get introduced into my application at various entrypoints, and are passed around from that point on. I find that mount pretty much solves the reloading part of my issues, e.g. being in a dirty REPL and wanted to start/stop some resource that things are referring to. it doesn’t really help you at all with architecting your application, since it allows you to be as strict or loose with how you reference those global states as you want


the upside is much less ceremony. but I haven’t been burned too badly yet, so I’m willing to pay that cost for now 😉


There's no "One True Way" in Clojure so you can use whatever approach suits you best -- but that also means there's not much guidance and nothing very opinionated, which can be hard when you're getting started. And no frameworks adds to that.


We've changed our approach a lot over the years -- and in our suite of apps, some of them are built very differently to other, based on who built the core of it and at what point in our usage it got started. We have about seven and a half years of code now, and over 86K lines of Clojure so there's quite a bit of variety in there.


Installed Atom + Chlorine. No idea how to use it. Tried "chlorine connect clojure socket repl" command, put in the port number, it said it worked. But


how do I evaluate a form?


@phill Unless you have key bindings, you'll have to do everything through the command palette.


Happy to share my config in the #chlorine channel


The console pane is output-only at the moment. The expectation is that you will eval code from your editor pane into the REPL.


Is there a port of to Clojure anywhere?


Not that I'm aware of. But if you find or start a project like that, I'd be happy to contribute!


Since I love writing templates in Hiccup, I got around to creating a template for clojure built sites on netlify: Hiccup, cljs, garden for css.

👏 10

Thanks for that! I've used it before to learn 🙂


no problem, just a basic thing you can build on.


And since I also love to write templates in Hiccup, it really saddens me that there seems to be very little effort from the community to attract simple front end developers. I've struggled a lot to find good material to ease entrance, both for me and for friends I would like to experience Hiccup/Garden.


What's a good way to provide context/metadata to my transducers? My transformation relies on some collection specific config data. - Lexical scoped variable would mean I only need to provide it once however I would need to pass it to all the inner function calls. - I could merge it into each element however then I would be duplicating this config data. This might be inefficient as this config data contains a collection itself and I would be repeating that collection for each element in my data. - I could also do something with metadata too? - Maybe I could provide a function to each element which when called returns the config data?


merge it in


in memory it is a pointer to the same data, not separate copies of the data


@hiredman Ah right. That would work great then as the merge is the simplest to implement. Thanks 🙂


anyone got a tip how I can get highlighted clojure code in keynote?


as an option copy somewhere online with syntax highlight and copy back - keynote might use the colors.


I use with the Clojure option and copy back the code which comes with the colors. Supports multiple highlight styles too

Lennart Buit09:01:51

yeah, I copy code of GitHub, and manually fix newlines


if you use emacs you can just emit html for it via htmlize-region (it will generate all the css that matches your theme/colors) and paste it there somehow (I did that with google presentations not keynote but I guess html might be supported) ->


@mpenet cool, that works for me

👍 5

@todo I've never heard of that library, how does it function?


(if it's cool enough I need a side project regardless)

Noah Bogart14:01:15

looks like it's a gui toolkit/framework: "McCLIM is a FOSS implementation of the Common Lisp Interface Manager specification, a powerful toolkit for writing GUIs in Common Lisp."


I’m guessing that compiles down to machine code, as opposed to something like seesaw, that hooks into Java Swing


I used to be very interested in native GUIs, but lately, you know, the web app is just right there…


I think for customer facing stuff that makes sense, but I've had acquaintances whose job it was to make a tiny internal tool that needed to have a gui


god rest their souls


they chose swing


so seesaw looks cool


@emccue: not sure, never used McClim. The manual looked impressive, so I was hoping someone had ported it over to Clojure so I could test it.

Alex Miller (Clojure team)17:01:43

If you took the Clojure survey, and marked “Reference docs” as a priority for making improvements, I would be interested to learn more. 1) do you mean something other than the docs at*. 2) do you think existing docs should be improved or new things added. And then I’m interested in learning if there are specific things (if so, an issue at would be best) or if this is something else.


@alexmiller I think I marked this one too. For Clojure as a language the reference docs are pretty complete, as well as for it's core libraries (well done). However, what I think is missing is references on acknowledged Clojure design patterns. E.g. patterns like Component might not be unique to Clojure, but are very relevant for building Clojure applications. Without this knowledge and knowing who is authoritative, it is hard for someone new to know where to start and people will have to reinvent those patterns or wait to be pointed to them by their peers. If they are lucky they are coming from a language where similar patterns existed, if not, good luck. IMO the same is even more true for the Clojurescript environment, but there I wouldn't even know what the reference patterns are. Is it, something else? Is there even an acknowledged pattern?

Alex Miller (Clojure team)13:01:47

I hear ya. Doing this with a few web pages is generally hard. I sensed the same gap and spent two years co-writing Clojure Applied to try to fill it. It’s doubly hard in ClojureScript because things in contact with JS change at a much faster rate even.


I guess a book is a more appropriate format indeed. I see that your book is mentioned in this list So that's a start. An idea for improvement would be if this list is more prominent as a follow up resource and grouped by type of problem or level (your book would be under "patterns", "advanced")? Maybe even community votes. Just thinking out loud here


I would then also add links between topics on the website and the books (e.g. would have links to books that have a significant part about transducers)

Alex Miller (Clojure team)14:01:09

We would prefer on the main site to avoid “recommending” things, especially since those of us working on the site overlap with the authors of some of the books

Alex Miller (Clojure team)14:01:09

categorization would be ok, but I think it’s difficult to categorize things fairly (this has all the problems of categorizing stuff anywhere else)


I see what you mean. As a last suggestion, maybe the main site could only link to a separate site not controlled by the same people of the main site to avoid this potential conflict of interest. I'm guessing you have considered many options already

Alex Miller (Clojure team)15:01:22

if such a thing existed, would be happy to link to it :)

👍 5

What do you think about a site that mines review data on "clojure" books via Amazon? Would you consider that to be objective enough? The referral money for the links on the site could go back to the community (or for sponsoring the development of the site itself)

Alex Miller (Clojure team)21:01:50

sounds like a fun project :)


I am attempting to read a serialized function from an ObjectInputStream. This code is running in a Java Class and looks like this: IFn f = (IFn) in.readObject();. I am getting an exception pointing to that line:

Caused by: java.lang.ClassNotFoundException: compute.connector.serialize$myfn
I'm guessing this has to do with Clojure's classloader? Do I need to switch the classloader for the thread calling readObject?


Right before that line, I require the namespace: require.invoke(;.


don't IFn instances created via eg. fn get randomized automatic names that don't persist across restarts?


or are you using something like deftype to get something that implements IFn but has a predictable name?


defn results in a fn with the same classname


For this first cut I'm defining myfn as:

(defn myfn
    (inc x))
It's only run once so I think its name would be the same?


yes, you'll have to use the compiler's classloader


I would strongly recommend against that


why not serialize the var?


serializing fn objects is gross


if you serialize the var, you can still do the namespace require trick with the namespace for the var, then deref the var to get the value, no classloader stuff required


Hmm. I'm not sure. Ultimately it may need to serialize an anonymous function 😬


then you run into what I was saying


or don't even bother to deref the var, because vars implement ifn


the name is auto-generated gibberish that changes on reload


don't put yourself in a situation of needing to serialize anonymous functions


I'm not sure if it can be avoided. The anonymous function is calculated through an expensive ML-esque process.


I've seen this but that seems kinda gross to me. Perhaps less gross than serializing an anonymous function?


it's the only technique that will reliably work correctly across restarts / vms though


that docstring on that macro is so nice lol


(defmacro ^{:doc (str (:doc (meta #'clojure.core/fn))
                      "\n\n  Oh, but it also allows serialization!!!111eleven")}

😆 5

> it's the only technique that will reliably work correctly across restarts / vms though How come?


because anonymous function names are auto-generated


If you could get them to be statically generated, would it work?


hmm - actually, maybe having a predictable name isn't needed for object deserialization? honestly I don't know


the object is an instance of some class


and the class needs to be defined


I guess you could serialize the class itself with the instance...


just don't paint yourself in to the corner of serializing closures


and like, you are already shipping the clojure code around (otherwise you wouldn't be able to require the namespace)


so just get what you need from there instead of going through java object serialization


so you use some weird process to generate your code, instead of generating a code object and using java serialization, have it generate a form, stick that form in a file with a def, require the file, grab the var


Yeah that path seems to have less friction. Curious, have you gone down the serialization path before and hit problems?


not really, I can't tell you the last time I've used java serialization, I was present at the seajure meetup were serializable-fn was written, and I have spent a little bit of time thinking about shipping functions around in a distributed systems setting


I see. Is storing the form as a string still the best approach you've seen?


If you absolutely need it, I prefer to define objects so they print with enough info so that the object can be reconstructed on the other side, as defined by some object reader.


But that won't be easy for arbitrary closures


In an ideal world, storing the data to construct the function would be great. In our case, the data used to create these functions can have thousands of different complex properties. It would be a large undertaking to model that data, and we'd like to push that off for the time being.


I don't mean a string


I mean, like, generate a file that contains (def f (fn [...] ...))


then load that file


That’s not much different than a string, right?


if you have a namespace and load the file via require then multiple loads won't result in new code generation


the naive approach of sending a string around and evaling it will


What’s the downside to new code generation?


it won't be hot


Some fns also want to close over local state, which won't work very well when you've stringified your form, unless you're careful


any form of serialization has that problem


that's true


Doesn’t the serializable-fn handle locals?


it handles them as best it can


(which in my opinion is not very well)


the problem with serializing arbitrary object graphs from memory (which closure serialization is) is pointer identity is not preserved


vars are sort of like pointers where the identity is preserved


Not sure I totally understand. Is that a performance trade off or a different behavior than originally expected?


both in the case of mutable objects


the first in the case of immutable values


What if serializable-fn is closing over another closure?


May only work with data


or a ref, or an atom, or some random java object


lot's of gotchas


I suppose that’s the trade off I’d be making with taking approach. @hiredman you said you spend some time thinking of this. Was this the best solution you found?


there isn't a good general solution, so you should solve your specific problem


your specific problem is you have some clojure code you want to distribute


the best way to distribute clojure code is as code


(not serializing java objects from memory)


there is some tool that people use for deploying clojure functions as aws lambdas, you might check that out (I forget the name)


I have trouble believing it works well

Gang Liang20:01:22

Here is a naive question. I would like to refer a java enum member: java.awt.Desktop.Action.BROWSE. I tried various different forms, yet none works.



👍 5

for the first thing, the object owning it is Desktop$Action - that's how inner classes work

Gang Liang20:01:46

For instance, (. java.awt.Desktop.Action BROWSE), (java.awt.Desktop.Action/BROWSE)...


That’s a great breakdown of the problem. Thank you guys for your input! Going to investigate the serializable-fn approach to see if it will cover the entirety of my problem.


inner classes are fictional, what actually exists is a class with a $ in the middle of the name

Gang Liang20:01:33

@hiredman thanks! Let me try it.


also the parens are allowed, but not needed

Gang Liang20:01:46

Seems it is not in the document -- I did read it, 🙂


@randomizedthinking documented where? The official docs mention how to access an enum and how to access an inner class, but for this case you need to know both


oh maybe they don't directly mention enums...

Gang Liang20:01:42

I found it now -- it refers to the $ syntax at one place -- I missed it.


yeah, I remember things that clearly aren't covered there - it doesn't mention the thing about inner classes and doesn't show using enums either


oh, $ is under "nested" not "inner"


enum values are static field on the enum class


it definitely mentions static fields


yeah, I guess there's a few things you need to know about the JVM internals before all those docs are clear


that isn't really even jvm internals, "enums" exist as a java language contstruct


and they are defined in-language to be equivialent to static fields on an object?


that is what the compiler turns them in to


right, what I'm saying is that there's a piece of information about the internals, that isn't derived from the language spec docs, needed to understand how to access an enum

Gang Liang20:01:58

The official java doc annotate the nested class Action as: java.awt.Desktop.Action -- so java uses . to refer to nested class. Yet clojure uses $.


right - but the clojure docs actually describe that discrepency


what I was getting at is enums, which are indirectly described (you need to know it's implemented as static fields on a class)

Alex Miller (Clojure team)20:01:55

If only there was a way to register these issues for update

😆 5
👍 5
Gang Liang20:01:33

@alexmiller I will register an issue about this one later today. thanks!

Lennart Buit21:01:00

@alexmiller Looking at some of the documentation I sometimes find myself puzzled at what is actually suggested. Take for example, it tells me that it takes a function with three positions, an f/`init`/`coll` and that it applies f to init, k1, v1, and applies f to that result, k2 and v2… etc. This particular case tells me “how” and “what”, but forgets to tell “why”. It is actually, as a beginner in Clojure, surprisingly difficult to quickly find functions that I need due to these highly dense detailed pieces of documentation that “forget” to tell the higher picture. Certainly written with great intention, and all information is there, but not usually in a very “yes this is what I want”/“no I don’t want this” kinda way. If that makes any sense?

👆 5
Alex Miller (Clojure team)21:01:13

That is pretty much by design. The docstrings are not intended to teach you the language, the idioms, etc of the language. They are meant to be concise statements about what each function does.

Alex Miller (Clojure team)21:01:38

We don’t really have any intention to change that (and in fact, making these much longer and more explanatory would also increase code size and degrade classloading and startup time)

Alex Miller (Clojure team)21:01:26

However, it is perfectly reasonable to combine docstrings with ancillary material that is useful to one or more audiences into a documentation site that would be better for those audiences

Lennart Buit21:01:06

yeah ofc, they are pretty printed docstrings, I get that. I am merely saying that, as a beginner, that is often the only thing I have, and dumps quite a bit information on my “newbie” mind.

Alex Miller (Clojure team)21:01:11 is such a site - it combines the docstrings with examples, links, etc

Alex Miller (Clojure team)21:01:37

some efforts that have been made in adding supplementary docstring material but it’s a big effort and one that’s hard to do well

Alex Miller (Clojure team)21:01:32

maybe some day we will spend more time on this in the core team, but other things seem more pressing at the moment

Alex Miller (Clojure team)21:01:11

there is a lot of intro Clojure material available in a variety of forms and I’d say all of them are a better way to learn the “why” parts than reading docstrings

Lennart Buit21:01:13

Right, link was actually to clojuredocs ^^. Its hard to pinpoint, I’d admit that, but it feels currently that there is a great detailed explanation but no higher level overview. I am merely pointing out what I recently notices was holding me back a bit in terms of documentation. Please take it as no offense

Alex Miller (Clojure team)21:01:54

you are hardly the first to make such an observation :)

Lennart Buit21:01:31

haha ofcourse, and I will certainly not be the last. Its easy saying that “clojure documentation is x”, but “why I think its x”, thats such a different question.


@lennart.buit I'm curious as to what would have helped you here (specifically)? Were you just looking over all the various core functions thinking "Hmm, I wonder when I would use that?" or did you start from a problem, thinking "Hmm, what core function would solve this problem?"


Are the examples of reduce-kv on the page not explaining a "why" here?


Thanks for linking that, super helpful that I wish I found before! Seems to lack a printable version, current one seems to take around ~10 pages


There are several PDF variations that print on 2 pages, if the text isn't too small for you to read, including a US letter color version at the "Download PDF version" near the top of the page. Some other variants available within a couple of clicks through the "Source repo" link next to that.


ah, indeed there is a PDF version! Missed that. Thanks a lot!


I haven't read this but it may be a good resource for this sort of question (anyone have any input on it?)


There's also which i really like. It has examples which often include more of what you want. IE, if you look up defprotocol you're probably gonna want to glance at extend-type or extend-protocol


I understand where you're coming from. From my perspective, it's hard to answer the "why" because answering that is entirely context dependent.


i browse it from CIDER (C-c C-d r) and just saw that it hotlinks to crossclj to find usages. that's pretty cool

Lennart Buit22:01:33

@seancorfield in this particular case I stumbled upon it because a coworker was using it. I think the “problem” of the examples here is that there is no base case. The first example is more complex than it should have been, and most other examples feel more esoteric than valid usecases of the particular function. If this particular page just had a very simple (reduce-kv (fn [memo k v]) ...) init coll) I would already have been helped tremendously in quickly finding out what it is about. (Also, it was just some example of a page that I remembered took me longer to “parse” than it should have imo, don’t assign too much value to the example ^^)


Ah, reading code and finding an unknown function and thinking "Hmm, why have they used this function?" … yeah, I can see that use case... and you're pretty much going to be at the mercy of whatever examples (and comments) folks have added to at that point. At least more examples/comments can be added by the community so now maybe someone here can go add something that would have helped you... or you could add something that would help future you's coming along and hitting the same question/use case.

👍 5
Lennart Buit22:01:31

Right, I knew that was coming, it is a community resource after all. Ofcourse I want to contribute, but I was just taking this as an example of something that “hindered” me as a newbie.


Do you have any prior experience with the functional paradigm?

Lennart Buit22:01:19

yes, have programmed in Haskell before


No worries. There are lots of gaps and rough edges in the public Clojure documentation sphere, unfortunately, and precious few people who have the time/energy to contribute so we all owe them a huge amount of thanks for what we've got so far. None of that helps folks today who hit something that is not well-covered in the docs tho'... 😞


I wish I had more time to spend on docs and tutorials but I'm really not very good at writing that sort of stuff...


we should get the Rust guy who just quit Mozilla. His dream job is Alex's job i think

👏 5

Steve Klabnik is who i was thinking of

Lennart Buit22:01:45

o.O did he quit mozilla

Lennart Buit22:01:49

what a loss for the Rust community


yes. dan luu tweeted about it. and its got some interesting thoughts in it. he was the lowest paid member of his team

Lennart Buit22:01:49

have a link by any chance, Rust is one of those languages I follow with great interest but with lack of time to invest


good thread on it with link to steve's blog:

😕 5
Lennart Buit22:01:12

I kinda hope he finds a new home for his Rust work. That language really shows great potential and needs someone like him as much as any other new language.


i would be quite happy to see him at Cognitect 🙂

Lennart Buit22:01:41

haha also, but I kinda also want Rust to succeed

Noah Bogart14:01:50

Steve is a powerhouse and the Rust community will be worse-off without him. Any community that he joins will benefit greatly.


(not to replace Alex but to work alongside him :)


I thought this last example on clojuredocs was helpful as it is so basic it is showing another way of updating a map.


it's basically merge but restricted to two args


also (reduce-kv assoc m e) does the same thing (though admittedly less clear what it's doing)


It’ll have different behavior if you give it vectors. 😄


merge only works on vectors accidentally


or do you mean this works better on vectors than merge does?


I was making a joke.


The use of the word “work” in the context of using merge with vectors is quite charitable. I’ve never been in a situation where upon finding that a bug due to a mistaken use of merge with vectors was considered “working” nor have I ever been in a situation where anyone recommended merge as a substitute for conj.


"Reduces an associative collection."


This won't help your general issue of better examples, but for this particular question:

Lennart Buit22:01:27

Haha, I know what it does now, its not a hard function, its just hard to parse from the current example[s] (or their order), that it really isn’t.


Personally I've never had an issue with just destructing the map entries using normal reduce, but then I wasn't considering the performance


What's the current preferred libraries for making HTTP requests from an API server?


@whoneedszzz we use both clj-http and http-kit (client).


The latter is nice and simple and async by default. The former is comprehensive with a lot more knobs and dials.


Are there any practical differences between them?


(does my second line answer that or do you want more specifics?)


More details would be helpful to weigh them


My current use case does not require fancy tweaking so I'm more looking at performance, size, http compliance, etc


I guess it depends on what you need it for. clj-http brings in a lot of dependencies (which can be a problem in itself) but it is extremely configurable and has built-in support for a number of over-the-wire protocols and coercions. We've also run into problems with its handling of multipart form POSTs with image files and a few APIs that we needed to interact with (something odd about how it was handling headers I think) and we've switched those to use http-kit instead.


I would prefer fewer dependencies as it is only a small project


Going forward, I think we'll use http-kit's client library more and more (and clj-http less) because we really don't need all the bells and whistles that clj-http offers -- and we like the simple, async-by-default approach of http-kit.


That seems in line with my thinking, thanks


But clj-http has been the "gold standard" in Clojure for a long time... 🙂


I haven't tried it out yet but I've been meaning to

Lennart Buit22:01:05

dependency on Java 11 tho

Lennart Buit22:01:13

that may be a dealbreaker?


I hope not. Not for me for sure


Only if you have an environment that requires a previous version

Lennart Buit22:01:18

right, I know people who are reluctant to upgrade because of licensing concerns and therefore stay on 8


(if folks are concerned about licensing, they should upgrade to OpenJDK11 -- from somewhere like AdoptJDK 🙂 )

👆 5

Staying on (Oracle) JDK 8 means no more updates unless you pay.

Lennart Buit23:01:15

OpenJDK 11 has 6 months of support, no?


OpenJDK from Oracle has only six months.

Lennart Buit23:01:38

right, ofcourse


Other OpenJDK providers are offering longer support periods.


Isn't the idea that it shouldn't be a big deal moving forward? Just upgrade to 12 when it comes out?


I thought I remember that being a design goal of the new structure


Depends whether you want long term support and/or are willing to pay Oracle money...


(and this should probably go to #java before we suck too much air out of #clojure about it)

Lennart Buit23:01:02

Yeah, they are on a faster release schedule, I can see how people were concerned the first time they read “6-months of support or upgrade”.


Personally, I avoid any software that is coupled to a specific version of Java

Lennart Buit23:01:40

Right also I am heading off, I managed to break my sleep schedule enough as is. Was a pleasure discussing ^^


Thanks for linking that, super helpful that I wish I found before! Seems to lack a printable version, current one seems to take around ~10 pages