admin-announcements

Announcements from the Clojurians Admin Team (@U11BV7MTK @U077BEWNQ @U050TNB9F @U0ETXRFEW @U04V70XH6 @U8MJBRSR5 and others)
2016-01-05T01:34:17.003037Z

great job josh

2016-01-05T01:40:07.003038Z

@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

2016-01-05T01:41:46.003039Z

@nogeek: another example, with lein, is https://github.com/ztellman/sleight

atroche 2016-01-05T03:53:56.003042Z

does the metadata reader macro just expand to wrap the following form in with-meta?

2016-01-05T03:57:37.003045Z

the reader constructs the meta map in there and attaches it to the form, doesn't go through with-meta

2016-01-05T04:01:41.003046Z

I muted #C03RZGPG1, and it's better. The channel won't appear unread, and I'll be notified of mentions of myself only.

atroche 2016-01-05T04:07:03.003048Z

alandipert: thanks!

2016-01-05T08:38:25.003050Z

@alandipert: very nice will try it out

2016-01-05T11:14:04.003054Z

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.

cjmurphy 2016-01-05T11:42:30.003055Z

My money would be on the 2nd. With the 2nd you can see the parameter so it is easier to read.

2016-01-05T11:52:03.003057Z

thanks @cjmurphy - that's a good point.

2016-01-05T12:33:19.003058Z

@dj (map vec ["hello" "world"])

2016-01-05T12:49:43.003060Z

gosh that is nice, thank you also @mikethompson.

meow 2016-01-05T13:17:28.003061Z

Yeah, Mike's would be the canonical way to do that.

👍 1
meow 2016-01-05T13:18:53.003062Z

Although into is one of my favorite and quite-often used functions. So handy.

meow 2016-01-05T13:19:14.003063Z

With or without transducers.

meow 2016-01-05T13:20:41.003064Z

@mikethompson: Here's wishing you continued success with re-frame in 2016, btw. :simple_smile:

🍻 3
jethroksy 2016-01-05T16:00:11.003066Z

@dj the partial version is apparently the prefered version, according to the style guide, but no good reason was provided

2016-01-05T16:02:04.003067Z

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

glenjamin 2016-01-05T16:02:20.003069Z

usually partial is marginally better than the equivalent #()

jethroksy 2016-01-05T16:03:38.003070Z

and why is that

jethroksy 2016-01-05T16:04:05.003071Z

had a long discussion about this in #C03S1KBA2 a while ago, it ended up as personal preference

jethroksy 2016-01-05T16:04:18.003072Z

in #C053AK3F9 actually i think

jethroksy 2016-01-05T16:04:47.003073Z

and @dj yes was referring to that

mpenet 2016-01-05T16:17:12.003074Z

@glenjamin: partial will be slower in some cases

mpenet 2016-01-05T16:17:37.003075Z

not that it matters most of the time, but it might be relevant depending on your usage

donaldball 2016-01-05T16:18:47.003076Z

I thought the partial speed difference went away in 1.7?

meow 2016-01-05T16:19:03.003077Z

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.

bronsa 2016-01-05T16:19:05.003078Z

partial doesn't instantiate a new function object like #() does, but partial uses varargs and apply internally for >4args, which is slower

mpenet 2016-01-05T16:19:24.003079Z

@glenjamin: what @bronsa said

bronsa 2016-01-05T16:19:25.003080Z

@donaldball: partial was unrolled for <4 args in 1.7

donaldball 2016-01-05T16:19:35.003081Z

Thanks for the clarification

meow 2016-01-05T16:20:34.003083Z

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"])

jethroksy 2016-01-05T16:22:45.003085Z

of course

meow 2016-01-05T16:22:49.003086Z

And I say that as someone who loves the into function and uses it a lot. 😉

jethroksy 2016-01-05T16:23:30.003087Z

but the question between choosing partial or #() actually comes out a lot

meow 2016-01-05T16:26:01.003088Z

Interesting. I see them as fairly different beasts.

mpenet 2016-01-05T16:26:47.003089Z

personnaly I used to prefer partial but I now find that #() reads better ...

meow 2016-01-05T16:27:10.003090Z

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.

mpenet 2016-01-05T16:27:13.003091Z

it's also more common in clj code in the wild

meow 2016-01-05T16:27:46.003092Z

Whereas #() is just syntactical sugar for an inline defined function

jethroksy 2016-01-05T16:28:20.003093Z

I agree with @meow in terms of usage

meow 2016-01-05T16:28:46.003094Z

I tend to just go with (fn [foo bar baz] ...) unless the #() form is super easy to understand.

jethroksy 2016-01-05T16:29:04.003095Z

especially with reduce

meow 2016-01-05T16:29:28.003096Z

and then you also have the limitation that you can't easily return a vec from the #() form

meow 2016-01-05T16:30:08.003097Z

after getting tripped up by that its just easier to (fn []) the darn things

jethroksy 2016-01-05T16:30:40.003098Z

I think its just function composition is just prefered

jethroksy 2016-01-05T16:30:51.003099Z

that's why partial seems like the more popular choice

meow 2016-01-05T16:30:57.003100Z

on the other hand, if the (fn []) version just adds noise then I use #() - its all about clarity

jaen 2016-01-05T16:31:59.003101Z

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.

jaen 2016-01-05T16:32:33.003102Z

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.

meow 2016-01-05T16:32:44.003103Z

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

jethroksy 2016-01-05T16:33:20.003104Z

there we go again: personal preference hahaha

jethroksy 2016-01-05T16:33:57.003105Z

but yes ultimately it's still whatever floats your boat

wotbrew 2016-01-05T16:34:00.003106Z

partial is useful if you have an indeterminate amount of args to be applied :simple_smile:

jethroksy 2016-01-05T16:34:23.003107Z

you could accomplish the same with %&amp; in #()

wotbrew 2016-01-05T16:34:36.003108Z

@jethroksy: I did not know that!

wotbrew 2016-01-05T16:34:37.003109Z

:simple_smile:

jaen 2016-01-05T16:35:10.003111Z

Yeah, it's always bikeshed this, bikeshed that with programming languages : D

2016-01-05T16:35:11.003112Z

jaen, seriously re: partial application…always disappointed using partial in Clojure. haha

wotbrew 2016-01-05T16:35:17.003113Z

does %&amp; bind to a collection though, or does it splice the args?

jethroksy 2016-01-05T16:35:26.003114Z

ends up in a list

jethroksy 2016-01-05T16:35:44.003115Z

your usual destructuring rules apply

meow 2016-01-05T16:35:56.003116Z

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.

wotbrew 2016-01-05T16:36:04.003117Z

Thats not the same then, you would have to #(apply f x y %&amp;) to get the same effect as (partial f x y)

jethroksy 2016-01-05T16:36:42.003119Z

but doesn't partial use apply too?

jethroksy 2016-01-05T16:36:53.003120Z

the end code is almost the same

danmidwood 2016-01-05T16:37:25.003121Z

When I first started with Clojure, I found reading fns 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 fns seem a bit messy in comparison

wotbrew 2016-01-05T16:37:25.003122Z

no actually partial implements multiple short arities, giving potential performance boosts. Tis bikeshedding for sure!

jethroksy 2016-01-05T16:38:04.003124Z

uhm

2016-01-05T16:38:05.003125Z

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.

jaen 2016-01-05T16:38:28.003126Z

I guess some sugar for partial would have been nice, but alas.

2016-01-05T16:39:27.003127Z

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

2016-01-05T16:39:50.003128Z

so I often don’t end up using partial at all in Clojure, because the evaluation strategy is so different

2016-01-05T16:39:58.003129Z

it just feels a lot less idiomatic

meow 2016-01-05T16:40:00.003130Z

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))))

jethroksy 2016-01-05T16:40:11.003131Z

@danstone: don't think there's performance difference at all

wotbrew 2016-01-05T16:40:43.003132Z

@jethroksy: look at the impl

jethroksy 2016-01-05T16:40:51.003133Z

i am

jethroksy 2016-01-05T16:41:25.003134Z

can you give an example where partial has better perf

wotbrew 2016-01-05T16:42:46.003135Z

functions returned from partial don't use apply for small numbers of arguments

meow 2016-01-05T16:42:51.003136Z

@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.

jethroksy 2016-01-05T16:44:09.003137Z

ah ok i see how this works now

meow 2016-01-05T16:45:15.003138Z

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)))

jethroksy 2016-01-05T16:46:33.003139Z

there was some mention of how slow get was too yesterday

jaen 2016-01-05T16:46:43.003140Z

@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)).

mpenet 2016-01-05T16:51:02.003141Z

@danstone: #() never uses apply ... so I don't see how it could be faster

mpenet 2016-01-05T16:51:12.003142Z

try to expand #(...)

wotbrew 2016-01-05T16:51:27.003143Z

@mpenet: We were talking about when you have an indeterminate amount of args to be applied to the partial function

jethroksy 2016-01-05T16:51:34.003144Z

you'll need it when you have variable args

mpenet 2016-01-05T16:51:38.003145Z

ah nevermind

jethroksy 2016-01-05T16:52:59.003146Z

its just whether the perf boost from bikeshedding > eval-ing the partial fn

wotbrew 2016-01-05T16:53:32.003147Z

In my mind its the only practical difference, everything else is just clarity/readability/subjective

meow 2016-01-05T16:55:22.003148Z

I have learned to think twice when I find myself writing a function with >4 parameters.

jethroksy 2016-01-05T16:55:33.003149Z

^ yes this is key

meow 2016-01-05T16:56:45.003150Z

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.

jethroksy 2016-01-05T16:58:22.003151Z

sometimes i end up having to do a whole load of destructuring in my functions

jethroksy 2016-01-05T16:58:37.003152Z

and wonder if there's a better way to access the params i need from the map

meow 2016-01-05T16:59:21.003153Z

@jethroksy: got an example?

roberto 2016-01-05T17:00:38.003155Z

functions with >4 arguments is always a bad idea in any language.

roberto 2016-01-05T17:01:13.003158Z

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.

jethroksy 2016-01-05T17:01:42.003159Z

my code is pretty bad, because i did some quick hacks

meow 2016-01-05T17:01:57.003160Z

In Python I never thought twice about how many parameters were required by a method.

jethroksy 2016-01-05T17:02:16.003161Z

its just a simple slack integration thing, but it's hackish to allow easier syntax

jethroksy 2016-01-05T17:03:01.003162Z

i also don't see code in the wild where functions are passed keywords

meow 2016-01-05T17:03:08.003163Z

and in python you have named parameters so its easy to deal with lots of args

meow 2016-01-05T17:04:02.003164Z

I don't think I've written any clojure functions that take keywords as args

jaen 2016-01-05T17:04:49.003165Z

Oh, kwargs. Another Clojrue bikeshedding topic. I for one prefer not to use them, since they compose badly.

wotbrew 2016-01-05T17:05:03.003166Z

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.

jethroksy 2016-01-05T17:05:46.003167Z

in this case i preferred the verbosity

meow 2016-01-05T17:06:24.003168Z

if a value ultimately needs to be destructed why not do that in the parameter definition?

wotbrew 2016-01-05T17:06:58.003169Z

Because I like to know what an argument is

meow 2016-01-05T17:06:59.003170Z

I don't smell the smell there. Got an example?

jethroksy 2016-01-05T17:07:13.003171Z

because yesql takes a map

jethroksy 2016-01-05T17:07:24.003172Z

so i'll need the params map anyway

wotbrew 2016-01-05T17:08:25.003173Z

@jethroksy: Give me an idea of the domain so I can write an example - what are you adding an agenda to?

jaen 2016-01-05T17:08:32.003174Z

@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.

meow 2016-01-05T17:08:44.003175Z

I don't think you can generalize - sometimes destructed adds clarity, sometimes it takes it away. No universal rule there imo.

wotbrew 2016-01-05T17:08:48.003176Z

@jaen :as is better than no :as thats for sure

wotbrew 2016-01-05T17:09:20.003177Z

@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.

meow 2016-01-05T17:09:24.003178Z

well, the destructed bits are getting names - again, I think it depends

wotbrew 2016-01-05T17:09:42.003179Z

I'm not saying its never appropriate, only a sith...

jethroksy 2016-01-05T17:09:52.003180Z

add-agenda takes a map with those vals

jethroksy 2016-01-05T17:10:13.003181Z

adds in the db

jethroksy 2016-01-05T17:10:27.003182Z

then posts to slack with a webhook

jethroksy 2016-01-05T17:10:36.003183Z

obviously i failed in the code clarity part

jethroksy 2016-01-05T17:10:57.003184Z

i destructed because i wanted them in the text portion for my webhook

wotbrew 2016-01-05T17:11:10.003185Z

Sounds like you want to model an agenda

meow 2016-01-05T17:11:25.003186Z

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.

wotbrew 2016-01-05T17:11:28.003187Z

And have fns like (db/add-agenda! db agenda)

wotbrew 2016-01-05T17:11:46.003188Z

@meow: I agree

jethroksy 2016-01-05T17:11:57.003189Z

(db/add-agenda!) is generated by yesql

jethroksy 2016-01-05T17:12:05.003190Z

it's arity 1 and takes a map

wotbrew 2016-01-05T17:12:11.003191Z

wrap it?

wotbrew 2016-01-05T17:12:15.003192Z

or not?

jethroksy 2016-01-05T17:12:19.003193Z

hmm

wotbrew 2016-01-05T17:12:36.003194Z

if you can pass the agenda straight through there is no point, unless you want the clarity of documentation, arg names etc

jethroksy 2016-01-05T17:12:59.003195Z

what better representation of agenda could there be, if not a map?

wotbrew 2016-01-05T17:13:08.003196Z

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.

wotbrew 2016-01-05T17:13:28.003197Z

@jethroksy: a map is fine, I am just saying give it a name, and surface that name in your api

jethroksy 2016-01-05T17:13:51.003198Z

ah i see

wotbrew 2016-01-05T17:13:55.003199Z

so a user (or you in 5 months) can say, "oh that takes an agenda". "These functions operate on agendas" and so on.

jethroksy 2016-01-05T17:13:57.003200Z

like params should probably be agenda

wotbrew 2016-01-05T17:14:08.003201Z

Useful tool to limit the amount of context one has to keep in her/his head

meow 2016-01-05T17:14:11.003202Z

what can be better than a map? sometimes a defrecord and protocols

wotbrew 2016-01-05T17:15:03.003203Z

@jethroksy: And then maybe a schema Agenda, and a constructor agenda with a nice docstring.

wotbrew 2016-01-05T17:15:44.003204Z

That is just my personal preference, I gotta go, but hopefully it helps you see things in a different way?

jethroksy 2016-01-05T17:15:57.003205Z

yeah schema would actually be really nice

jethroksy 2016-01-05T17:16:01.003206Z

thanks for the feedback!

jethroksy 2016-01-05T17:16:40.003207Z

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

meow 2016-01-05T17:17:13.003208Z

I'm constantly revising my code. That's the only way to improve.

jethroksy 2016-01-05T17:17:21.003209Z

need to start reading more code in the wild

roberto 2016-01-05T17:17:26.003210Z

I never like any of the code I wrote in the past.

wotbrew 2016-01-05T17:17:26.003211Z

As god-emperor Rich once said - Nothing much really matters for small programs that will just be hacked out the door and forgotten about

roberto 2016-01-05T17:17:27.003212Z

:simple_smile:

meow 2016-01-05T17:18:56.003213Z

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.

jethroksy 2016-01-05T17:20:06.003214Z

I wish I had that liberty: where i work at i'm churning out about 1 slack integration a day

jethroksy 2016-01-05T17:20:26.003215Z

building a larger scale one soon, that's where i get my chance

2016-01-05T17:34:24.003216Z

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?

2016-01-05T17:47:51.003217Z

@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.

2016-01-05T17:48:09.003218Z

I definitely adds a lot of complexity for people using and reasoning about your lib

2016-01-05T18:05:09.003219Z

@tgk: cool thanks!

glenjamin 2016-01-05T18:22:00.003220Z

jjttjj: you might want to look into UUIDs for that purpose

2016-01-05T18:24:43.003221Z

glenjamin: unfortunately i'm depending on a java lib that needs an int for the unique idea

2016-01-05T18:24:47.003222Z

*unique id

2016-01-05T18:39:50.003223Z

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.

meow 2016-01-05T18:39:53.003225Z

@jjttjj: you could use a volatile inside your fn

meow 2016-01-05T18:40:47.003226Z

@dj: don't be sorry or feel like I was criticizing - just trying to provide some perspective

👍 1
2016-01-05T18:41:03.003229Z

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:

meow 2016-01-05T18:43:28.003230Z

@dj: trust me, I've been coding for about 30 years now and learning to think functionally was not an easy switch

2016-01-05T18:44:12.003231Z

I agree. But even at this early stage (for me) it is enlightening and definitely worthwhile.

meow 2016-01-05T18:44:56.003232Z

That's why I jumped on the chance to get a conversation going - it turned out to be a good one.

meow 2016-01-05T18:45:19.003233Z

@jjttjj: avoid state, totally

2016-01-05T18:45:32.003234Z

@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/

meow 2016-01-05T18:45:34.003235Z

global state, especially

meow 2016-01-05T18:49:10.003236Z

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))))

meow 2016-01-05T18:51:28.003237Z

I hate when library authors use global atoms for state

meow 2016-01-05T18:52:58.003238Z

Or rather, I hate when library authors store state globally when it doesn't need to be global.

meow 2016-01-05T18:53:17.003239Z

There are exceptions, but they should be few and far between.

meow 2016-01-05T18:54:19.003240Z

And when they exist, I (as the user of said library) should be glad they are there, not irritated, imnsho. :simple_smile:

2016-01-05T19:07:25.003241Z

great advice everyone, thanks!