great job josh
@nogeek: we invented boot partly so we could do transforms on source like that, http://hoplon.io is a cljs dialect that is translated to cljs at build time with a goal of reducing boilerplate
@nogeek: another example, with lein, is https://github.com/ztellman/sleight
does the metadata reader macro just expand to wrap the following form in with-meta?
@atroche: not exactly - https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L781
the reader constructs the meta map in there and attaches it to the form, doesn't go through with-meta
I muted #C03RZGPG1, and it's better. The channel won't appear unread, and I'll be notified of mentions of myself only.
alandipert: thanks!
@alandipert: very nice will try it out
Hello all. I'm relatively new to Clojure, and am learning by working through Advent Of Code. Anyway, I have a style question, if you don't mind such a newbie question. Which of these two approaches would be more idiomatic / preferable?
(map (partial into []) ["hello" "world"])
or
(map #(into [] %) ["hello" "world"])
thanks.
My money would be on the 2nd. With the 2nd you can see the parameter so it is easier to read.
thanks @cjmurphy - that's a good point.
@dj (map vec ["hello" "world"])
gosh that is nice, thank you also @mikethompson.
Yeah, Mike's would be the canonical way to do that.
Although into
is one of my favorite and quite-often used functions. So handy.
With or without transducers.
@mikethompson: Here's wishing you continued success with re-frame in 2016, btw. :simple_smile:
@dj the partial version is apparently the prefered version, according to the style guide, but no good reason was provided
thanks @jethroksy - didn't realise there was one. Found this (assuming it's the one to which you're referring as there's a direct ref to this in it) https://github.com/bbatsov/clojure-style-guide#partial
usually partial
is marginally better than the equivalent #()
and why is that
had a long discussion about this in #C03S1KBA2 a while ago, it ended up as personal preference
in #C053AK3F9 actually i think
and @dj yes was referring to that
@glenjamin: partial will be slower in some cases
not that it matters most of the time, but it might be relevant depending on your usage
I thought the partial speed difference went away in 1.7?
It kind of depends on the context, though. For example, I usually use partial
when the argument that I'm partialing in is some computed value that I don't want to recompute over and over again. Especially if said function is itself going to be passed to some other function as an argument.
partial
doesn't instantiate a new function object like #()
does, but partial
uses varargs and apply
internally for >4args, which is slower
@glenjamin: what @bronsa said
@donaldball: partial was unrolled for <4 args in 1.7
Thanks for the clarification
The original context of these questions is really odd, I just want to add. While valid code, neither example is something I would expect to see in the wild when you can just do (map vec ["hello" "world"])
of course
And I say that as someone who loves the into
function and uses it a lot. 😉
but the question between choosing partial
or #()
actually comes out a lot
Interesting. I see them as fairly different beasts.
personnaly I used to prefer partial but I now find that #() reads better ...
Bearing in mind the >4 args issue, I see partial as just a way to shorten up an existing function by partialing in early arguments that aren't going to change in the given context.
it's also more common in clj code in the wild
Whereas #() is just syntactical sugar for an inline defined function
I agree with @meow in terms of usage
I tend to just go with (fn [foo bar baz] ...)
unless the #()
form is super easy to understand.
especially with reduce
and then you also have the limitation that you can't easily return a vec from the #() form
after getting tripped up by that its just easier to (fn []) the darn things
I think its just function composition is just prefered
that's why partial
seems like the more popular choice
on the other hand, if the (fn []) version just adds noise then I use #() - its all about clarity
Well, Clojure not being statically typed can't have as nice partial application as Haskell can - partial
is nice and all, but usually when it's not longer to write out than a function.
My first reflex is to use partial
because partial application seems natural to me and then I have to backtrack because it's too verbose.
unless there is a performance issue, to me the act of coding is an act of communication and clarity of the code for both others and my future self is of utmost importance
there we go again: personal preference hahaha
but yes ultimately it's still whatever floats your boat
partial is useful if you have an indeterminate amount of args to be applied :simple_smile:
you could accomplish the same with %&
in #()
@jethroksy: I did not know that!
:simple_smile:
Yeah, it's always bikeshed this, bikeshed that with programming languages : D
jaen, seriously re: partial application…always disappointed using partial in Clojure. haha
does %&
bind to a collection though, or does it splice the args?
ends up in a list
your usual destructuring rules apply
I used to code in Python where "one right way" to do something was what I liked. However, I like Clojure even more and while there does seem to be some amount of personal preference in these things I'm finding that even though I still try to do things one and only one way in Clojure that I need to vary my style of code in order to achieve the clarity and simplicity that I'm after. So these variations aren't a bad thing if handled properly in a variety of contexts.
Thats not the same then, you would have to #(apply f x y %&)
to get the same effect as (partial f x y)
but doesn't partial use apply
too?
the end code is almost the same
When I first started with Clojure, I found reading fn
s to be clearer to understand than partial
. Mostly because I was unfamiliar with the fns that were being partialed, and because of the explicit argument list in fn. Later, as I've become more skilled with Clojure and I have a good chunk of the std-lib understood, partial seems a lot more straightforward, whereas fn
s seem a bit messy in comparison
no actually partial implements multiple short arities, giving potential performance boosts. Tis bikeshedding for sure!
uhm
pkobrien, interesting point. I tend to find that how to implement something in Clojure comes down to exactly what kind of performance characteristics I want along with the shape of the data. I think the whole partial
vs. #()
thing is less common, in general—I don’t often struggle to figure out what the right way to do something in Clojure is.
I guess some sugar for partial
would have been nice, but alas.
jaen, re: your previous point it really seems to be less generally applicable, but if you are at all used to the Haskell way of doing things it seems more appealing…it’s just so natural to pass partially applied functions around in Haskell
so I often don’t end up using partial at all in Clojure, because the evaluation strategy is so different
it just feels a lot less idiomatic
Here's a fun use of partial from my code:
(defn rewrite
"Returns a successor, which must be a vector or a function. If no match is
found in the rules mapping, the original module is return within a vector."
[rules m]
(or (rules m) [m]))
(defn rewriting
"Returns a rewriting transducer."
[axiom rules generation]
(map (partial rewrite (get-rewriting-rules axiom rules generation))))
@danstone: don't think there's performance difference at all
@jethroksy: look at the impl
i am
can you give an example where partial has better perf
functions returned from partial don't use apply for small numbers of arguments
@ddellacosta: Interesting indeed. I tend to think in terms of the API that I would enjoy using and worry about performance later. And I've only been doing clojure for 8 months with a mostly OO background and no real functional experience so early on it was a real struggle for me.
ah ok i see how this works now
And here's how much I like into
. Built a whole bunch of uber over it:
(defn produce
"Returns a lazy sequence of colls from a recursive, axiomatic,
transformative process."
[seed prep-f get-xf]
(letfn [(process
[coll]
(lazy-seq
(when (seq coll)
(let [new-coll (into (empty coll) (get-xf coll) (prep-f coll))]
(cons new-coll (process new-coll))))))]
(process seed)))
there was some mention of how slow get
was too yesterday
@ddellacosta: I suppose that's a sensible POV. I'm just probably wishing that you could do something closer to map (* 2)
than to (partial map #(* % 2))
.
@danstone: #() never uses apply ... so I don't see how it could be faster
try to expand #(...)
@mpenet: We were talking about when you have an indeterminate amount of args to be applied to the partial function
you'll need it when you have variable args
ah nevermind
its just whether the perf boost from bikeshedding > eval-ing the partial
fn
In my mind its the only practical difference, everything else is just clarity/readability/subjective
I have learned to think twice when I find myself writing a function with >4 parameters.
^ yes this is key
If its a top-level thing that rarely gets called, that's one thing. But a low-level function that gets called a lot, or will be called using partial or apply == not good.
sometimes i end up having to do a whole load of destructuring in my functions
and wonder if there's a better way to access the params i need from the map
@jethroksy: got an example?
functions with >4 arguments is always a bad idea in any language.
https://github.com/jethrokuan/ttagenda/blob/master/src/ttagenda/core.clj#L8-L15
in clojure, I normally try to consolidate them as maps, and use schema do document the structure. I have a feeling there is probably a better alternative.
my code is pretty bad, because i did some quick hacks
In Python I never thought twice about how many parameters were required by a method.
its just a simple slack integration thing, but it's hackish to allow easier syntax
i also don't see code in the wild where functions are passed keywords
and in python you have named parameters so its easy to deal with lots of args
I don't think I've written any clojure functions that take keywords as args
Oh, kwargs. Another Clojrue bikeshedding topic. I for one prefer not to use them, since they compose badly.
I think destructing domain values in fn binding forms is a bit of a smell. Unless its literally opts
or config
- I would rather see a noun describing the parameter. And hopefully have as few of these nouns as possible.
in this case i preferred the verbosity
if a value ultimately needs to be destructed why not do that in the parameter definition?
Because I like to know what an argument is
I don't smell the smell there. Got an example?
because yesql takes a map
so i'll need the params
map anyway
@jethroksy: Give me an idea of the domain so I can write an example - what are you adding
an agenda to?
@meow: I suppose he means the fact that the parameter lacks a name, but then again you could always use :as
for documentation I suppose.
I don't think you can generalize - sometimes destructed adds clarity, sometimes it takes it away. No universal rule there imo.
@jaen :as is better than no :as thats for sure
@meow: I agree, thats why I said domain values - the nouns of the program or the datastructures we are operating on and would like to give a name.
well, the destructed bits are getting names - again, I think it depends
I'm not saying its never appropriate, only a sith...
add-agenda
takes a map with those vals
adds in the db
then posts to slack with a webhook
obviously i failed in the code clarity part
i destructed because i wanted them in the text portion for my webhook
Sounds like you want to model an agenda
I hear what you are saying about domain values. But again, sometimes even with domain values I might want to take the focus off of what is getting passed into the function and just focus on what the function is doing to the bits and pieces and so avoiding using a name actually helps there. For me the rule is always clarity of communication and understanding, not adherence to one style of code.
And have fns like (db/add-agenda! db agenda)
@meow: I agree
(db/add-agenda!)
is generated by yesql
it's arity 1 and takes a map
wrap it?
or not?
hmm
if you can pass the agenda
straight through there is no point, unless you want the clarity of documentation, arg names etc
what better representation of agenda
could there be, if not a map?
the point is it should be clear what a function operates on. Sometimes that really is a map with some set of keys in it. Other times it is a value you are modelling in your domain.
@jethroksy: a map is fine, I am just saying give it a name, and surface that name in your api
ah i see
so a user (or you in 5 months) can say, "oh that takes an agenda". "These functions operate on agendas" and so on.
like params should probably be agenda
Useful tool to limit the amount of context one has to keep in her/his head
what can be better than a map? sometimes a defrecord and protocols
@jethroksy: And then maybe a schema Agenda, and a constructor agenda
with a nice docstring.
That is just my personal preference, I gotta go, but hopefully it helps you see things in a different way?
yeah schema would actually be really nice
thanks for the feedback!
its just one of those build in a few hours, push and forget projects, but i'm not pleased with the way i've gone about it
I'm constantly revising my code. That's the only way to improve.
need to start reading more code in the wild
I never like any of the code I wrote in the past.
As god-emperor Rich once said - Nothing much really matters for small programs that will just be hacked out the door and forgotten about
:simple_smile:
I'm brutal on my own code. I don't often like the code I wrote the day before. But I'm okay with that and expect it. Coding for me is more like writing or art - I expect to do multiple drafts.
I wish I had that liberty: where i work at i'm churning out about 1 slack integration a day
building a larger scale one soon, that's where i get my chance
i'm having trouble deciding on the extent to which i should avoid internal state in a library i'm working on. If I have an internal id, that basically serves as a static field that is incremented every time a library operation is performed, is it fine just to define that as a top level atom in the library and increment it whenever the function is called, or is it better to leave that to the user of the library to take care of?
@jjttjj: I think you might run into problems if someone uses your library and e.g. uses some of the namespace reloading tools commonly used for interactive development.
I definitely adds a lot of complexity for people using and reasoning about your lib
@tgk: cool thanks!
jjttjj: you might want to look into UUIDs for that purpose
glenjamin: unfortunately i'm depending on a java lib that needs an int for the unique idea
*unique id
really interesting discussion coming out of the earlier question about partial
vs #(...)
usage - I've learned a lot, thank you. And @meow you are not wrong to comment (https://clojurians.slack.com/archives/general/p1452010834003083) on the oddness of my question - it's mostly due to ignorance on my part, sorry.
@jjttjj: you could use a volatile inside your fn
@dj: don't be sorry or feel like I was criticizing - just trying to provide some perspective
Although the "100 functions 1 data structure" Perlis epigram has a price - I didn't know (yet) about vec
, or at least had forgotten :simple_smile:
@dj: trust me, I've been coding for about 30 years now and learning to think functionally was not an easy switch
I agree. But even at this early stage (for me) it is enlightening and definitely worthwhile.
That's why I jumped on the chance to get a conversation going - it turned out to be a good one.
@jjttjj: avoid state, totally
@jjttjj: two related patterns: * to define the api in a protcol and use a record for state management- so any internal state, like a metric capturing library utilization is a member of the record, and the record is passed in and returned from all api calls * if the need is just for metrics, and these metrics are important for the semantics of the library, consider just building on http://metrics.dropwizard.io/
global state, especially
Here's an example from a different context but it shows one way to increment a counter inside a stateful function:
(defn gen
"Returns a function that, when called, will call f with an incremented
generation number and an additional context data argument."
[f]
(let [generation (volatile! (long -1))]
(fn
[data]
(vswap! generation #(inc (long %)))
(f @generation data))))
I hate when library authors use global atoms for state
Or rather, I hate when library authors store state globally when it doesn't need to be global.
There are exceptions, but they should be few and far between.
And when they exist, I (as the user of said library) should be glad they are there, not irritated, imnsho. :simple_smile:
great advice everyone, thanks!