This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-21
Channels
- # beginners (82)
- # bitcoin (1)
- # boot (38)
- # cider (6)
- # cljs-dev (13)
- # cljsrn (5)
- # clojure (320)
- # clojure-italy (22)
- # clojure-losangeles (6)
- # clojure-russia (55)
- # clojure-spec (25)
- # clojure-uk (48)
- # clojurescript (64)
- # component (16)
- # core-async (6)
- # cursive (54)
- # data-science (2)
- # datascript (2)
- # datomic (8)
- # docker (1)
- # ethereum (1)
- # fulcro (1)
- # garden (1)
- # graphql (16)
- # heroku (6)
- # hoplon (12)
- # jobs (4)
- # juxt (1)
- # leiningen (9)
- # off-topic (39)
- # om (13)
- # om-next (2)
- # onyx (9)
- # pedestal (2)
- # portkey (12)
- # re-frame (25)
- # reagent (6)
- # ring-swagger (4)
- # schema (1)
- # shadow-cljs (10)
- # spacemacs (11)
- # testing (19)
- # uncomplicate (1)
- # unrepl (6)
- # vim (21)
- # yada (3)
@bbloom I've been working on a couple generator functions that I've found useful enough for Clojure, but one of the prior arts I'm looking at is Rust's unfold implementation. Lemme grab a link
Is it really true that neither jetty nor httpkit gives you access to the HTTP verb (POST, OPTIONS) part of the request? Or am I just looking in the wrong places?
use ring if you aren't already, and the request itself should have a :request-method
key on it https://github.com/ring-clojure/ring/wiki/Concepts
if you are using eg. compojure remember that the destructuring is hiding most of the data for you
Is there a place for a #documentation channel to coordinate and support clojure documentation efforts?
OK, link worked, that's a start
@noisesmith There is indeed such a key, however when I get the value it is :options
It looks very much like a bug where there is no value so the next key becomes the value.
@jrootham Some browsers send an OPTIONS request first to find out what is supported.
If you're building a REST API, you need to support OPTIONS.
Ah, my bad, I was not expecting the leading :
It is indeed an OPTIONS message.
https://github.com/r0man/ring-cors -- we use that middleware to provide OPTIONS support, as I recall.
I am working on building something exceedingly small and simple
But yes, I need to support options.
Even if not incredibly well
Use appropriate middleware so you don't have to reinvent every wheel.
Have you looked at ring-defaults? That offers a standard set of middleware for both "web sites" and "APIs" -- and SSL/non-SSL variants of each.
(it doesn't include CORS so you still need that as well)
Clojure is all about composing small things 🙂
Thanks I will look at that, but CORS is the one thing I need and I don't want to have to use routes to use CORS middleware, which is what I inferred from the middleware documentation I saw.
You inferred incorrectly. my-routes
is just whatever handler you have.
a CORS exchange needs to use OPTIONS right?
Routing is just middleware anyway.
@noisesmith Yes. I have to send a good header back when I get an OPTIONS.
The docs are less than obvious. I don't even see where to find the type of my-routes
a router is a function that gets a request and passes it to a request handling function
usually it is made with a library like compojure or bidi
What's the output?
I mean technically it could just be a function that takes a request and does whatever but in practice that's what it is
the output is described, along with the inputs, on the wiki page I linked
if you return a string, that becomes the body of the response, if you return a hash-map various keys set properties of the response, it's all documented on the ring wiki
for your convenience here's the link again https://github.com/ring-clojure/ring/wiki/Concepts
Sorry for being obtuse, I will go quietly to my corner and RTFM.
I'd recommend reading through the Ring documentation and following the tutorials to get a sense of how web development is done in Clojure -- it's very different to how most languages do it.
@jrootham if you have specific questions I'm happy to help, but that wiki is more concise and accurate than I could manage to be if your question is just "what's a response" (actually you asked what the output was, but the handler should return a valid response etc.)
I do have the mild problem of starting to learn Clojure on Monday and going live on Friday.
oh wow that sounds super fun
@noisesmith Thanks very much, I am mostly just being slightly confused by new nomclemature.
The good part is that it is not a job, so the comeback isn't really painful, it's just an app for a small group.
@jrootham In that case you want to write as little "boilerplate" yourself and rely on existing components as much as possible. After all, you shouldn't have to worry about writing code to support CORS -- but your app needs to support it -- so... middleware. Same with route handling, JSON decoding of the body (if relevant) and pretty much all the basic stuff any web app or API needs.
But learning things in a hurry is actually fun.
The downside is: you need to "grok" Ring -- and pretty much everything in Clojure is based on Ring or is compatible with Ring.
CORS I need, architecture is 1 endpoint.
Our web apps and REST APIs all use a standard stack of middleware and can choose to run on Jetty or http-kit at startup.
there's a cors middleware, the model of ring is data -> function -> data, so you get a hash-map, do some work, and return something (likely a hash-map)
and a middleware takes a handler and returns a new one with a feature added
That makes sense
which either adds data to the incoming request, or to your reply
(usually - they can just do side effects instead of course)
What, do they launch nukes? 🙂
so the wrap-cors middleware will have some way of letting your handler pretend it's a normal request, and doing the options handshake with the client for you, and it should be smart enough to know when to pass data to your actual function
Authorization? Middleware. Request logging or timing / metrics? Middleware. Providing configuration from the environment or database connections or something? Middleware. 🙂
a pattern I use quite a bit is to decompose an app into features, and have each one manage its resources or configuration or initialization as needed, and return functions that others can use, including middleware for the http server. so the http server is the component that pulls in all the others, and knows which middleware to pull out of them and apply to its handler to get the runtime features it needs
What do I put in the dependencies in project.clj to get ring-cors? And more generally how do I find that out?
its on the github page for it. also, you can search clojars at https://clojars.org/
the image is nice as its updated by publishing mechanism but you can't copy paste unfortunately
Fun fact, you can if you load the svg directly. Just not via github's proxy which converts it to png
I like to work with maps containing several little functions and it would be really usefull
@pbaille the function as a value is fairly opaque, yep. I'm not sure why metadata isn't applied to functions, and is instead on their vars (or why not both!).
I'm sure there's a good reason though, usually surfacing around complexity or edge-cases which don't make sense.
@pbaille (clojure.repl/source ns/fname)
will fetch sources, assuming you can load them from a clj file sitting in the classpath
@reborg thank you, yes I was aware of this, but my concern is more about anonymous functions
once the lambda is evaluated there is no more sources available (unless of some tricky stuff to rebuild them from the bytecode)
@mbertheau don't actually use it, ->
implies something should be done with 1st argument ({} in this case), and might waste reader's attention on figuring out whether author forgot to add something
generally, you would not want to see in code today something you called a "trick" 2 weeks ago
Trying to embed a REPL in my app in code. Trying to run this in REPL: (clojure.core.server/start-server {:name "repl-server" :port 5555 :accept 'clojure.core.server/repl}) and then doing lein repl :connect localhost:5555. My windows command shell just hangs doing nothing. If I use a different accept-function, I get an error so the connection is established, it's just not starting the REPL. Is this the right way to start a new socket repl in code?
@ingesol lein repl
tries to connect to an nREPL server, clojure.core.server
is a socket REPL which is just plain tcp.
either start https://github.com/clojure/tools.nrepl or use a different client
Anyone knows who’s done https://clojurians-log.clojureverse.org ? Are there any more friendly export formats beyond html?
maybe @U07FP7QJ0 knows?
@U04V1HS2L there are the raw logs. They're not public but I can share them. Please DM me with what you need it for.
@pbaille if you define an anonymous function with a name, it becomes slightly less opaque (`(fn foo [] ...)` instead of (fn [])
) - the bigger gain is that stack traces make more sense, but it also becomes helpful if you run into a function literal. But! if you find yourself passing around maps full of functions, double check that your design wouldn't work out better with multimethods, or records implementing protocols.
@noisesmith thank you for the advice, I tend to avoid protocols and multimethod these days (I like to program with only maps and functions as much as possible) but they are really cool and when performance is needed I use them.
@pbaille but this isn't about performance, it's about not making a total mess
records are maps, protocol methods and multimethods are functions
a clojure record is a superset of a hash-map - it does all the things a hash-map does, plus it lets you extend functionality in an organized way
because it lets you write code that makes a design clear to the reader - but if your function composition isn't organized around something that matches dispatch, then it's not your solution sure
@pbaille this suggestion came from working with a legacy codebase that was full of partials and first class functions that rendered the design of the system opaque, which over time led to errors and duplicated work
I find this kind of way of coding offers a great deal of flexibility when used in the context of research and early dev but in prod maybe not
the fact that the authors of the code could no longer read about and understand the parts of the system (or even see a system in order to recognize parts) led to an avalanche of partials and closures that became unmaintainable, the solution was to use records and protocols to deliniate the "big picture" features of the app. This is all slightly fuzzy stuff, if you don't need to do this you don't, that's fine.
@pbaille right, the early flexibility sabotaged long term maintenance (in this project, and some other similar ones)
well, flexibility plus lack of developer skill / lack of developer understanding
Yes I see, I wrote lots of protocols and types in the past, and I became tired of this layer
right - I'm definitely not suggesting types and protocols everywhere
I thought I was seeing one of those classic symptoms - a big bag of functions in a hash-map and you lose track of what's what, and got flashbacks 😆
For example, there are places in the code where I ended up replacing a hash-map with a record that implemented no protocols. This was so that a) we could actually determine how much of the garbage sticking around in the profiled system actually came from this source (someone had a suspicion and we had to measure it somehow) and b) later the fact that it was a #some.ns.foo{} clarified things somewhat when looking at the data that comes into the other part of the system
I don't know if you have profiled a big clojure system, but the fact that everything is a clojure.lang.PeristentFoo datastructure or a LazySeq or clojure.lang.IFn eliminates 80% of the info a profiler would usually be giving you
That’s a good point. I previously worked on a large clojure backed webapp and we used AppDynamics. It helped but we were definitely limited because of all of the clojure-specific structures
it's not that they are clojure specific (it's all java at the bottom and the profiler can sort it all out), it's that they are not differentiated - the type of the data doesn't tell you anything about who made it other than "something in clojure" and the methods being called don't tell you much more than "some clojure generated byte code is running" (though in the latter case it's mostly noise rather than lack of data and if you keep digging you can actually figure out what code is doing what)
does anyone have any experience with integrant? how do you find it comparing to luminus?
integrant is a resource management library, luminus is a template made of a large number of libraries, the library it uses which integrant would/could replace is mount
there's a lot of debate around mount vs. integrant vs. stuartsierra/component
component was the first one, and people found it very useful for keeping their code running as they reload and redefine things (it ensures that even if you have running state you can safely tear it down and restart without exiting your repl process)
but people found it either "too OO" or "too boiler plate" and alternatives like mount and integrant were made
mount uses vars to put state in global shared mutable containers
integrant uses function args to pass in components (like component does) but has a syntax and some conventions which simplify the common use cases
@noisesmith thanks!
sorry for confusion, I wanted to say 'duct' vs luminus, but thanks for explanation about integrant!
haha, OK
Say, what do people favor as a convention for the names of constant values? I have (def ^:const buffer-size 100)
and I'm wondering whether to name it BUFFER-SIZE
, but that seems uncommon. I've also seen *buffer-size*
to indicate globalness, but the convention in clojure seems to favor using *var-name*
for dynamic vars, not necessarily global ones
@timgilbert typically style guides suggest having no special convention for constants, all data should be constant in clojure with very few exceptions
I'm generally ok with that, but there is something nice about a visual indicator that means I don't have to read back through a bunch of let-bindings to figure out where the thing was defined. Something about CAPS_LOCK just doesn't look right in Clojure though
OK - you asked about conventions, and in clojure the "convention" is to not to name constants differently
in practice something is either defined in a let block (the whole let block should fit in your screen at once) or else it's at the top level of the file, so finding it should not take long at all
There is a lisp convention which is +var+, but it's not considered idiomatic clojure.
https://dev.clojure.org/display/community/Library+Coding+Standards > Use earmuffs only for things intended for rebinding. Don't use a special notation for constants; everything is assumed a constant unless specified otherwise.
1. How do I convert string (representing a unicode char) to a char? 2. The answer is NOT read-string, as it fails on "(" 3. "a" -> \a, "b" -> \b, "\u2323" -> \u2323 How can I do this in both clj/cljs ?
@qqq assuming you want unicode code points (which is not the same as a Java Character), your best option is to use (.codePoints "adsf")
unicode characters in Java are stupid tricky to get right because Java chars are UTF-16, which means that higher code points are represented with TWO chars
And easy way to turn them into a seq is: (iterator-seq (.iterator (.codePoints "asdf")))
Here's a good example:
(seq "𐐷")
=> (\? \?)
(iterator-seq (.iterator (.codePoints "𐐷")))
=> (66615)
Notice just calling seq
produces TWO java chars, when, in reality, they represent a single unicode code point.
I have no idea about cljs. Surely there is some JS library that can translate a string to unicode code points.
I'm using component
and for some reason, no combination of the following is running my latest changes
- component/stop
- clojure.tools.namespace.repl/refresh
(or (refresh :after ...)
)
- component/start
any idea what's up?
You may want to ask in the #component room but I suspect the answer is that your code changes are directly part of your system components and you’re not rebuilding your system
> ask in #component
good advice, I will
> directly part of system components
they're actually not in this case 😞
> not rebuilding your system
stop
ping and start
ing should rebuild my components right? even if I were changing components directly?
No, you’d just be calling the stop and start methods on the existing system
(IE, if I add a prn
command, or delete something, or add any new logic, and then refresh, I'm still working with my previous version until I close cider and relaunch it)
Hi, does anyone know how can I create a record with dynamic fields?
Right now I'm doing (defrecord MyRecord [attributes])
but then I can't assoc without prepending attributes
(assoc-in myrecord [:attributes :key] value)
you can assoc anything into a record
so (assoc myrecord :key value) will work
sure, but then the new field won't overwrite the old one, passed at construction
There's also (map->MyRecord {}). that function is generated automatically for every record.
user=> (defrecord MyRecord [attributes])
user.MyRecord
user=> (def a (->MyRecord {:key :value}))
#'user/a
user=> (assoc a :key :new-value)
#user.MyRecord{:attributes {:key :value}, :key :new-value}
user=>
@joelsanchez that's because you're creating a record that has the {:key :value}
map as value for the :attributes
key
@joelsanchez wouldn't it do what you want if you used map->MyRecord
instead of ->MyRecord
?
ya, a MyRecord can't not have an :attributes key, that would mean it doesn't satisfy the one and only requirement that makes it a MyRecord
why put everything under one key?
I agree with @noisesmith use multiple keys at the same level as attributes
correct
user=> (def a (map->MyRecord {:key :value}))
#'user/a
user=> (assoc a :key :new-value)
#user.MyRecord{:attributes nil, :key :new-value}
I can simply define no arguments and then use map->
yes but also note @hiredman's point, avoid creating named records just for the sake of it, use a map instead unless necessary
I know
thanks
honestly unless you've got a specific reason (with data!) I wouldn't use records, just maps
and with maps you can use namespaced kws: {:attribute/key 42 :padding/left 33}
this is a very simple example outside of my application so that the issue would be clear
these records extend protocols and I need the polymorphism
(previously I was using maps and an awful lot of multimethods)
that's the most flexible
and the cleanest approach. Multimethods are faster than most people expect.
I dunno, I definitely prefer protocols, but if you have all dynamic fields, that is a map, not a record
you most likely have four or five sets of static fields that you are treating as the same thing for some reason
no, I don't, I have records whose particular fields I don't care about, but I care about what they implement and the type they have
the given solution works flawlessly
of course I could just use maps with a :type
field, and then use multimethods: I was doing that before
not a fan of doing defmethod
many times over 9 namespaces for defining how certain entities should behave
how does using protocols help with that?
you still have to define 9 protocol implementations
the defmethod
approach ignores the fact that the defmethods that dispatch on the same type, are actually describing the same entity
yes, I still do, but I find it is way cleaner and less error prone
How so? (defmethod my-method :box [...]) Vs. (extend-protocol IMyMethod Box (my-method [...])
i'm not using extend-protocol, rather the contrary: extend-type (which is what defrecord does)
they're both syntactic sugar over (extend...) so I still don't understand
(defmethod method-a :box ...)
(defmethod method-b :box ...)
(defmethod method-c :box ...)
vs
(defrecord Box []
WhateverProtocol
(method-a [this] ...)
(method-b [this] ...)
(method-c [this] ...))
matter of taste but latter is more comfortable imo
i guess your pointn is that you like being able to group implementaiton for the same type together?
using protocols with defrecord are not closed for modification (or at least not for extension).
I get the point, and I've felt the same way in the past (grouping things). But I've more often been hit by the limitations of type polymorphism. That's where multi methods help.
what's the limitation? I'm very sure I will only dispatch on type
otherwise being equivalent (both can be extended afterwards, with more multimethods in one case and with extend-type in the other), I prefer this one in this case
also I get satisfies?
the multimethod approach gives me the equivalent of instance?
by checking the value of type
to implement satisfies?
I would need a dedicated multimethod
The limitations come when you want to dispatch on two types at once, or perhaps two aspects of the same type
sure, I won't
@joelsanchez there's also get-method
and you can check if the method returned is equal to the default
right @noisesmithbut these records may not extend any of the possible fns of the protocol, and still should be considered part of it
I've just found myself coming full circle lately. Started with multimaps, moved to protocols because of some of the reasons you listed, and over time found them more trouble than they were worth.
that sounds very possible 😛
@thheller @chris @potetm: I ended up using (.charAt ...) -- thanks for all the suggestions!
I wonder how different libraries dependencies are resolved. For example I use 2 libraries and they use different version of the same third one. I bugs me a little but not that much to explore myself 🙂
The algorithm it's a little complex. But the software that answers that question is a java library called maven/aether-resolver
Yes, you can specify :exclusions
on a dependency to prevent the third one being pulled in, then specify it as a dependency directly with the version you want.
[[lib-a "1.2.3" :exclusions [lib-c]]
[lib-b "4.5.6" :exclusions [lib-c]]
[lib-c "2.2.2"]]
Also, I think any explicit dependencies you provide at a top level will override any transitive dependencies, so you don't need the exclusions, but it does make things clearer, and prevents lein warnings
how I wonder how to find out what libraries are used. I built uberjar and looked inside, that's kinda gross
lein deps :tree
(or boot show -d
, if you're using Boot)
Leiningen has a "pedantic" mode that makes sure you have no possible conflicting versions (and won't run if you do!).
Boot also has a "pedantic" mode that shows possible conflicts (but still runs). We have a small Boot task that throws an exception if it detects conflicts -- and we use that for all our builds!
It can be really painful to get to zero conflicts -- but it's worth it for your sanity! And once you get there, it's easy to stay there even when adding new libraries.
The algorithm it's a little complex. But the software that answers that question is a java library called maven/aether-resolver
@ghadi Generated css class names
Yeah, sorry. I'm using the hash of the styles to generate css class names. The main issue is with server side rendering creating different class names. Up to this point I thought they were equivalent, until I ran into integers not being consistent.
Normally, but not always
They might be any immutable type.
Perhaps an md5 hash or something.
well if it's not too complex, you may want to flatten the map and sort explicitly, then do some sort of securehash
That may work. The goal is really just to get a consistent unique name.
clj and cljs would generate the same bytes from transit for equal data right? what about hashing the transit string?
That's not a bad idea. ^
no @noisesmith -- transit does not have a canonical encoding
oh, that's too bad
@bfabry if that was the only difference you could just sort the map entries as part of the process, but yeah, good point
@ghadi So far it seemed to not have any conflict issues. Though I haven't used it extensively. I'm just now realizing integers are different.
you have to sort map's key-values, transit doesn't give you a hook into that (there's also caching)
Is pr-str consistent?
I'd do as ghadi said. turn the data structure into nested vectors (where they're sorted in the case of a map) then sha1 it or whatever
Even for basic data types?
What are you trying to do? Arachne has a lib for consistent equality hashing
i.e. things that are equal in Clojure will have equal serialization hashings
let me look up the lib
got any other bright ideas @U07TDTQNL?
i'm using a blockchain with a requirement that the state transition functions produce the same hashed output, and the output could be an arbitrary blob. if you serialize JSON as the output of a function that runs on every blockchain node ('validator') they must all produce the same result -- so you have to sort json keys
How do you access this
inside a proxy
definition?
(pr-str {:1 1 :2 2 :3 3})
=> "{:1 1, :2 2, :3 3}"
(pr-str (assoc {:3 3} :2 2 :1 1))
=> "{:3 3, :2 2, :1 1}"
Thanks, @bfabry
@martinklepsch every method takes a this arg
oh - wait, it's automatically named 'this
So, a discussion I’m having with @staypufd over in the #docker channel has led to what I believe is a bug in tools.nrepl. Is there someone here who can review what we’re seeing and confirm if a Jira ought to be opened?
I think you only need to xform+sort map and set and you're good though. particularly if you're just talking about css which is probably a small subset of types
@noisesmith @bronsa thanks! 🙂
@gonewest818 I tried it again last night and it does seem that you are right. I haven’t fully verified yet, but it does seem if you don’t put “0.0.0.0” for :bind that you get a Socket failure on the nrepl
Good. I was pretty sure. I’ve got a repl in alpine linux right now and it’s easy to reproduce that unhandled exception by following what “start-server” does under the hood.
I have to pass in “0.0.0.0” as the nrepl :bind or it fails with that Socket exception every time
@gonewest818 It would be good for someone else to see same issue. We’re seeing it on DockerMac, so wonder if that is the issue as well, b/c DockerMac docs say there are a few issues surrounding network stuff…
btw, I just tried this and it doesn’t resolve the issue.
It’s Alpine linux where (I believe) ipv6 is disabled by default. The description in NREPL-83 suggests it will try “::” first and then fall back to “localhost” but in this case the attempt to bind “::” throws an exception and the fallback never occurs. It’s easy to workaround but IMHO the feature is not behaving as advertised because of the unhandled exception. Steps to reproduce are in this gist: https://gist.github.com/gonewest818/ae5c5caf49380f81c5a2667408da6d4f
yep. nrepl 0.2.13… the gist is very explicit
Ok, well I’ve googled a bit and it appears the proper path for opening a bug is to ask in the Google group first, and confirm if the behavior is in fact considered a bug.
Hi All, I've inherited some code that has some threads running a a service, distilled to essentially this:
(def test-channel (chan 5))
(def running (atom true))
(thread
(while @running
(let [m (<!! test-channel)
x (m :a)]
(some-fn x)))
(defn stop-service []
(close! test-channel)
(reset! running nil))
that's going to hit an npe when <!! returns nil from a closed channel
you can put '```' on each end
Which really only happens during testing, as that's about the only time the service is stopped as such. However, there has to be a nicer idiom/pattern to doing this?
yes
(loop []
(when-some [m (<!! test-channel)]
(m :a)
(recur)))
It's not causing issues in production, but another error in the tests masked this NPE
then you don't need an atom - closing the channel stops the loop
Hmmm... yeah, I like that. I guess my code snippet doesn't exactly show the issue as in the 'let' expression there are more bindings based on the read from the channel
then put a let block inside when-some
since you don't want to do any of that if you got nil on the channel anyway
@noisesmith Thanks for the clarity and help, took your suggestions and the code is so much better!