This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-01-26
Channels
- # arachne (80)
- # beginners (76)
- # boot (16)
- # cider (66)
- # cljs-dev (62)
- # cljsjs (1)
- # clojure (106)
- # clojure-dev (5)
- # clojure-greece (2)
- # clojure-italy (9)
- # clojure-russia (1)
- # clojure-spec (61)
- # clojure-uk (130)
- # clojurescript (21)
- # core-async (9)
- # cursive (3)
- # datomic (37)
- # events (41)
- # figwheel (31)
- # fulcro (27)
- # hoplon (1)
- # jobs (2)
- # lumo (11)
- # off-topic (155)
- # re-frame (71)
- # reagent (27)
- # ring-swagger (3)
- # shadow-cljs (132)
- # spacemacs (5)
- # specter (1)
- # sql (37)
- # test-check (10)
- # uncomplicate (5)
- # unrepl (2)
- # yada (3)
I'm working in a project that makes liberal use of futures, and it's hard to tell at a glance which functions return futures and which return immediate values. Can anybody share conventions they've used to solve this problem?
I was considering suffixing the future function names with &
, with the mnemonic being it's like running something in the background in the unix shell
Hmm, interesting approach - the in me immediately thought of using an ellipsis for the same purpose, so you’d have (do-foo... x y)
But three characters is probably a lot for that. &
is unusual but seems like it could be a nice marker if it was internally consistent in a code base.
dots in names are a problem - perhaps three in a row would avoid the issues but I’d be cautious
for example
penguin.tracking-test=> (defn foo... [] :OK)
#'penguin.tracking-test/foo...
penguin.tracking-test=> (foo...)
CompilerException java.lang.ClassNotFoundException: foo//, compiling:(/private/var/folders/xb/gyyjxv511q7d9lr24s9_1rzc0000gr/T/form-init7128136753223600421.clj:1:1)
because it thinks you are invoking a constructor because of the . before the )
that error message makes me think it is doing a string/split on .
and then combinging with slashes to make a class name - that would make sense I guess
WRT the Clojure survey, one of the things I find very important is the stability. Upgrading to newer versions of Clojure is basically a non-event.
@slipset This is how we went to production back in 2011 on a 1.3 alpha build and we've taken pretty much every alpha and beta build to production over the years -- so we can always be using the very latest new features in Clojure in production!
I heard great things about your clojure upgrades and it’s amazing. But @U04V70XH6, I’m sure it’s not all been rainbows and unicorns. I’d love to hear about something that went wrong with an alpha/beta build and what you had to do to resolve it.
We dodged a bullet with 1.5.0 — we were on a prerelease build in production, 1.5.0 came out with a newly introduced memory leak and our deployment schedule meant we didn’t put it in production because 1.5.1 came out so soon. That would have been bad — but it wasn’t a prerelease build 🙂 The worst thing I can think of is that we have to change our code as new core functions appear and because we test against master-SNAPSHOT (as well as whatever fixed build we’re using), that means our build can break overnight without us touching anything.
We were very early adopters of clojure.spec
(and this is sort of why we follow prerelease builds — to get access to new functionality) and that meant we had a fair bit of churn as that evolved (namespace changes, functions removed, lots of functions added).
But, no, there’s really nothing that “went wrong with an alpha/beta build”… the Clojure/core team do an amazing job in that regard!
hey Sean, we haven’t actually done an announcement about it as there’s not really anything to announce yet, but 1.10.0-alpha2 is out already :)
Haha… yeah, I saw the pushback reader commits and was surprised you’d released not one but two alphas already just for that! 🙂 We’ve been testing against 1.10.0-master-SNAPSHOT for a while but there’s nothing in the alpha(s) to cause us to move yet.
it’s almost like there’s an unreleased project relying on those new features that needs them
Yeah... almost... and maybe that'll inspire us to jump to an alpha again 🙂
hey guys, quick question. I am trying to use an agent as a component in stuartsierra/component framework but it throws saying that Agents cannot be cast to iObj. I checked the source code and there is indeed a cast from Agent to iObj in order to change the metadata. Is this a known issue? is it not possible to associate meta data to an agent?
can you elaborate why you’d use an agent rather than a record or hash-map? sometimes I’ll put a mutable inside a record or map but I don’t grok how a mutable object as a component would work (or why I would do that)
@noisesmith because I can 🙂. Seriously, the only point of using an agent was not having to go through the verbosity of creating a record and implementing the protocols when I know before hand that only one value will be inside. The same thing as having a component be an atom
.
that is why it accepts a hash-map - why not a hash-map with an atom under a key?
component
supports that use case by using identity
as start/stop and since I refresh the system for that, then there is no problem with it
@noisesmith as I said, verbosity. Yeah I could do it like that, but I just didnt want to, and since component says it support elements where start/stop is a no-op then I wanted to use it
you need to be able to assoc onto a component, that is non-negotiable
you can’t assoc onto an atom or agent
it supports a hash map, then it just uses identity, but if you can’t assoc the other components it uses onto it as keys, component breaks, that’s fundamental to the design
as a degenerate case you could make a deftype that allows assoc as a no-op and contains the agent in a field, but I’m not sure if that’s better than using a hash-map
> you need to be able to assoc onto a component, that is non-negotiable
I dont think that is correct. You only need to assoc into it if the component depends on other components. If the atom/agent is suppose to hold the mutable state of the system or part of it then there shouldnt be any problem in just declaring it as a component. For me putting everything into a hashmap/record is the same mentality as everything must be an object
… but at that point we are back to java 😞
I already got a very good explanation on another thread of why it doesnt work but yeah I know that what I was asking is not the usual pattern
The comparison I would use here is that clojure.core/+
and clojure.core/min
(and most other mathematically useful functions) are designed not to be overloaded to non-numeric types. This isn’t because “everything is a number” it’s because we don’t do polymorphism for its own sake. I don’t find the idea of a system where some components are maps with keys representing their features alongside things they depend on, and others are arbitrary types, to be a coherent design. And there’s every indication that the author of the library thinks similarly.
@noisesmith from the component readme > Any type of object, not just maps and records, can be a component if it has no lifecycle and no dependencies. For example, you could put a bare Atom or core.async Channel in the system map where other components can depend on it. I think mixing different types is at the core of Clojure. Not allowing that would be a waste in my opinion
Oh, I didn't catch that. Still seems odd to me, but good to know.
is there anything tha combines core.match pattern matching with the extensibility of multimethods?
@carocad agents implement IRef
and alter-meta!
, since they are stateful. IObj
is for immutable values, so it’s a different interface.
thanks for the explanation, but this is not obvious to me. I thought that the agent itself is immutable but that the value that it points to is what changes :thinking_face:
An agent is a stable identity for a piece of state - the state inside is immutable, but that makes the atom itself a mutable representation. When you change metadata on a normal clojure value, you get back a new value with the updated metadata. Ref types, on the other hand, are meant to be stable so it wouldn’t make sense for you to get back a different agent when you change the metadata. Hence, the side-effecting alter-meta!
which updates it in-place.
One common pattern in component systems when you are working with stateful objects that may not play nice with metadata is to wrap them in a map if you don’t need lifecycle methods. If you do, then usually you’d define a new record type which had that state (say, your agent) as a field and implements component/Lifecycle
and the start
and stop
methods.
@U8XJ15DTK thanks a lot for your thoughtful explanation. It is much clearer now 🙂
I wanted to use the agent precisely to avoid having to wrap my mutable representation in a record since for me that is kind of make everything an object
mentality which starts to sound absurd taken to that point.
IPFS support in clojure is: complete & good?
@sova you might be interested in https://github.com/greglook/blocks and https://github.com/greglook/merkledag-core - IPFS-inspired, and semantically compatible if you wanted to back a block-store with IPFS itself.
Wow thanks for the links! I'm very interested in this. Our application leverages a blockchain and also IPFS for distributed storage like torrents... the design decisions of today make the towers of tomorrow...
if you like those, I’m building an immutable analytics database on top of merkledag as a POC: https://github.com/greglook/merkle-db
InterPlanetary File System?
Yessirs!
Java library does work but looks like i'm trying to floss my teeth with code
IPFS is, based on my research, the next level up from BitTorrent for distributed file storage, distributed apps, etc. Provided we can make a nice wrapper for it... I think a lot of people would be drawn to making Distributed Applications in Clojure 😄
anyway, attack me with an update if you use IPFS 😄
@stathissideris you want to look into predicate dispatch… IIRC Rich was banging on about it for a long time and then David Nolen took up the challenge and started exploring the area a few years back, but I’m not sure if he ever shipped anything.
@rickmoynihan I think it was core.match that was supposed to fill that gap
@rickmoynihan @stathissideris rh is opposed to pattern matching on principle, if that clarifies anything https://gist.github.com/rgdelato/3d7b6ecbcb7e9b86335ded905667feb8#why-no-pattern-matching
@noisesmith it sounds like he’s opposed to pattern matching that’s “closed, enumerated in a single construct”
of course nothing stops you from using a cond
form as your defmulti dispatch function, I do that frequently
but that undermines the intention of defmulti because cases are hard wired in the dispatch
what I’m asking for it something that would be in the spirit of multimethods but with more powerful dispatch
the problem is that if your dispatch is pattern matching, you can’t extend the dispatch without extending your pattern, right?
@stathissideris that sounds interesting but I don’t fully understand it - I didn’t bring up that point from rich to discount your idea, just to provide context for why things are the way they are now
ok, but what I’m saying is that he’s opposed to pattern matching which is localised and final
right, and that’s the part that is intriguing though I don’t understand it personally - I have no idea what extensible pattern matching looks like
maybe it looks a bit like this: https://github.com/selfsame/pdfn
there seems to be a talk by David Nolen on the subject: https://www.youtube.com/watch?v=iCl9rB1tyxo
@stathissideris, @noisesmith is right about RH being opposed to it on principle. Predicate Dispatch is like extensible multimethods + pattern matching. That’s why I was suggesting you look into it; though the last time I looked (which was sometime ago) David Nolen hadn’t released anything. So I assume it never left the research or toy prototype stage.
though I think the research it’s based on is complete; I think the open questions are around doing it in an open manner.
That talk is probably one of a few he gave where he mentions it
it would be really convenient to have such a mechanism for overriding/extending parts of my javafx DSL
I’ll look into pdfn (linked above)
I am starting to imagine a multimethod that uses another multimethod for dispatch - (defmulti dispatch-foo (partial map type))
(defmulti foo dispatch-foo)
- so you extend both dispatch-foo and foo… maybe… maybe that’s crackpot
yeah, so worthless
best tool for documenting a websocket API? swagger can't handle it and traditional documentation libraries are focused on functions only
like I said before I have no solid idea of what sane and clear extensible dispatch would look like
alternatively I can build my own 🙂
@joelsanchez what about making a spec or schema that succeeds for valid messages?
@noisesmith sure, easy to do that, but I was talking about the frontend side of things
you can easily use spec or schema in frontend code - that’s a common pattern in my app actually to use the same schema file on both ends
unless your frontend isn’t clojurescript
yes, but for example swagger lists the requests you can make, the params they take, and lets you try them
well, schemas are data
makes sense
good idea, thanks
clojure numeric functions are not generic for things that are not numbers
@petr that said you can use eg. min-key or (first (sort …))
=> (min-key int \a \b)
\a
(apply (juxt min-key max-key) #(.getTime %) ...)
@joelsanchez we have used swagger for web-socket api docs too. Actually generate a set of http post endpoints & ws-message handlers from a plain map (or multimethods).
could you show me an example?
Not right now. need to extract it from a project. Goal is to push all to a small support lib.
Wow thanks for the links! I'm very interested in this. Our application leverages a blockchain and also IPFS for distributed storage like torrents... the design decisions of today make the towers of tomorrow...
I have an uberjar using jetty that runs fine locally. However when I deploy it to heroku it dies with a null pointer exception in ring_debug_logging. Is this a known issue with a (hopefully) simple fix? Also, I inserted logging into my ring stack and I see that, but I do not see any output from println calls in the heroku logs.
Looks like your heroku box doesn't have allocated tty. You can try to configure your logger to use file instead of stdout.
Don't think so, I inserted an error into my program and got the println error message, so I am pretty sure it's not configuration.
Hey look! A survey - you should take it! https://www.surveymonkey.com/r/clojure2018
is it strange that it’s faster to read an SVG byte stream into a String and re-find the viewBox attribute than it is to use (-> (clojure.data.xml/parse (io/reader svg)) :attrs :viewBox)