This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-01-07
Channels
- # announcements (3)
- # beginners (124)
- # calva (60)
- # cider (81)
- # cljs-dev (65)
- # cljsrn (1)
- # clojure (268)
- # clojure-dusseldorf (2)
- # clojure-europe (3)
- # clojure-italy (9)
- # clojure-losangeles (1)
- # clojure-nl (22)
- # clojure-russia (3)
- # clojure-spec (24)
- # clojure-uk (34)
- # clojurescript (72)
- # code-reviews (8)
- # cursive (20)
- # datomic (32)
- # fulcro (49)
- # jobs (1)
- # jobs-discuss (15)
- # juxt (10)
- # lein-figwheel (10)
- # nrepl (4)
- # off-topic (37)
- # overtone (1)
- # portkey (2)
- # protorepl (8)
- # random (1)
- # re-frame (1)
- # reagent (43)
- # reitit (8)
- # ring (16)
- # ring-swagger (2)
- # rum (6)
- # shadow-cljs (63)
- # specter (2)
- # testing (32)
- # tools-deps (32)
- # unrepl (1)
- # vim (3)
@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.
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
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
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).
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.
So I'm very strongly against global shared state these days because of that experience.
Vars are global shared state.
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
@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 https://common-lisp.net/project/mcclim/ 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: https://github.com/minikomi/simple-static Hiccup, cljs, garden for css.
Thanks for that! I've used it before to learn 🙂
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?
@hiredman Ah right. That would work great then as the merge is the simplest to implement. Thanks 🙂
as an option copy somewhere online with syntax highlight and copy back - keynote might use the colors.
I use http://pygments.org/demo/ with the Clojure option and copy back the code which comes with the colors. Supports multiple highlight styles too
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) -> https://melpa.org/#/htmlize
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 https://github.com/daveray/seesaw
(See also: https://github.com/fn-fx/fn-fx)
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
@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.
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 https://clojure.org/reference/*. 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 https://github.com/clojure/clojure-site/issues 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 om.next, something else? Is there even an acknowledged pattern?
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 https://clojure.org/community/books 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. https://clojure.org/reference/transducers would have links to books that have a significant part about transducers)
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
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
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)
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.io.IOException: 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(Clojure.read(namespace));
.
Actually, the code looks almost identical to this: https://github.com/gorillalabs/sparkling/blob/b6e93ca6005a86b3d67bfae646db5e26d145dc68/src/java/sparkling/serialization/Utils.java#L33-L58
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?
For this first cut I'm defining myfn
as:
(defn myfn
[x]
(inc x))
It's only run once so I think its name would be the same?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
then you run into what I was saying
the name is auto-generated gibberish that changes on reload
I'm not sure if it can be avoided. The anonymous function is calculated through an expensive ML-esque process.
I've seen this https://github.com/technomancy/serializable-fn 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
(defmacro ^{:doc (str (:doc (meta #'clojure.core/fn))
"\n\n Oh, but it also allows serialization!!!111eleven")}
> it's the only technique that will reliably work correctly across restarts / vms though How come?
because anonymous function names are auto-generated
hmm - actually, maybe having a predictable name isn't needed for object deserialization? honestly I don't know
I guess you could serialize the class itself with the instance...
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
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.
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.
if you have a namespace and load the file via require then multiple loads won't result in new code generation
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
the problem with serializing arbitrary object graphs from memory (which closure serialization is) is pointer identity is not preserved
Not sure I totally understand. Is that a performance trade off or a different behavior than originally expected?
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 is some tool that people use for deploying clojure functions as aws lambdas, you might check that out (I forget the name)
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.
for the first thing, the object owning it is Desktop$Action - that's how inner classes work
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
@hiredman thanks! Let me try it.
also the parens are allowed, but not needed
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...
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"
yeah, I guess there's a few things you need to know about the JVM internals before all those docs are clear
and they are defined in-language to be equivialent to static fields on an object?
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
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)
@alexmiller I will register an issue about this one later today. thanks!
@alexmiller Looking at some of the documentation I sometimes find myself puzzled at what is actually suggested. Take for example https://clojuredocs.org/clojure.core/reduce-kv, 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?
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.
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)
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
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.
http://clojuredocs.org/ is such a site - it combines the docstrings with examples, links, etc
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
maybe some day we will spend more time on this in the core team, but other things seem more pressing at the moment
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
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
none taken! :)
you are hardly the first to make such an observation :)
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 http://clojuredocs.org page not explaining a "why" here?
@lennart.buit You may find this helpful: https://clojure.org/api/cheatsheet
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.
I haven't read this but it may be a good resource for this sort of question https://www.manning.com/books/clojure-the-essential-reference (anyone have any input on it?)
There's also https://www.conj.io/ 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
@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 http://clojuredocs.org 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.
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?
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
o.O did he quit mozilla
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
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: https://twitter.com/danluu/status/1082321431109795840
really sad
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.
haha also, but I kinda also want Rust to succeed
Steve is a powerhouse and the Rust community will be worse-off without him. Any community that he joins will benefit greatly.
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)
merge only works on vectors accidentally
or do you mean this works better on vectors than merge does?
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
.
haha OK
"Reduces an associative collection."
This won't help your general issue of better examples, but for this particular question: https://stackoverflow.com/questions/48732579/when-to-use-reduce-kv-over-reduce-in-clojure
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... 🙂
dependency on Java 11 tho
that may be a dealbreaker?
I hope not. Not for me for sure
Only if you have an environment that requires a previous version
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 🙂 )
Staying on (Oracle) JDK 8 means no more updates unless you pay.
OpenJDK 11 has 6 months of support, no?
OpenJDK from Oracle has only six months.
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)
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
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