Clojurians
#cursive
<
2016-01-11
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

tord17:01:04

In a function argument list, if I refer to some earlier argument in the list at some later point in the list, Cursive marks it as undefined. Is this a bug?

tord17:01:12

Here's an example:

tord17:01:21

(defn foo [a & {:keys [b] :or {b (first a)}}]
  [a b])

tord17:01:45

The a in (first a) is marked as undefined.

meow17:01:13

probably

meow17:01:52

I tend not to get that complex with inline destructing of args like that

meow17:01:12

so I haven't run into that one

meow17:01:14

moving :or to (let [b (or (b (first a))] should fix that, but I'm guessing that's not how you want to write that code

alexmiller20:01:10

I think you are in the area of "undefined" wrt ordering and you shouldn't do that

jaen20:01:19

Oh, Clojure doesn't guarantee left-to-right evaluation of function arguments?

alexmiller20:01:07

no, related to destructuring

alexmiller20:01:01

destructuring is a macro, so order of evaluation is up to the macro

alexmiller20:01:51

there are known issues with relying on the ordering of binding in :or for example - the :or definition is an (unordered) map, so each :or binding might be evaluated in any ordering (and this ordering has changed between releases in the past)

alexmiller20:01:32

the assumption here is that the sequential outer destructuring binds a prior to the associative destructuring bindings in :or

meow21:01:10

@alexmiller: that's good to know

jaen21:01:10

Oh I see, that makes sense. But in this case isn't the a outside of the map destructuring clause so the order should be defined?

meow21:01:21

so my advice does apply

alexmiller21:01:00

@jaen: that's true, I'm really just thinking through this as I type

alexmiller21:01:42

it does seem to work at the repl, I'm just trying to convince myself that Clojure would guarantee that it should

meow21:01:07

it does look like it should work

meow21:01:23

not sure I would write it that way, but it should work

cfleming21:01:17

I added explicit code for handling some of the tricky :or cases, but I might have missed that one. I actually didn’t realise that the values of :or could refer to other parameters.

cfleming21:01:38

Like @alexmiller says, it sounds like a recipe for ordering confusion

cfleming21:01:12

But I’m assuming that all the :or clauses are evaluated after the actual parameters are bound.

alexmiller21:01:22

I think that code is making an assumption about how defn works that is not guaranteed by any docs or reference material

alexmiller21:01:33

which does not mean it doesn't work now or for an arbitrary period of time, but also means it could stop working at some future point

jaen21:01:07

Hmm, well

spieden21:01:20

does anyone know how to use the “configure indentation” intention action?

jaen21:01:22

I at least would assume that defn argument vector being, you know, a vector

jaen21:01:26

Guarantees ordering.

spieden21:01:37

seems like it should let you configure additional symbols to be indented like e.g. defn, ec.

spieden21:01:46

.. but it has no discernible effect on formatting when i use it

meow21:01:44

what is contained in an argument vector

meow21:01:25

or is it a parameter vector

alexmiller21:01:47

@jaen: I'd say the vector guarantees that the incoming arguments are maintained in order. it does not necessarily mean that defn binds the incoming arguments to the parameters in order (although that's a reasonable assumption)

cfleming21:01:56

@spieden: It does. Place the caret on the head symbol of the form you’d like to change indentation for. From the popup, select the option that corresponds to the formatting you need.

cfleming21:01:43

@spieden: That specific instance of the form will be reformatted right away, others will need to be reformatted explicitly.

alexmiller21:01:43

@jaen: for example, the defn macro implementation could pair up parameters and arguments in an (unordered) map and then let bind them in arbitrary order

jaen21:01:57

@alexmiller: hmm... if I understand you correctly - given Clojure has strict evaluation what you mean is that, before calling a function, the arguments are evaluated left to right in the order of the argument vector, but the order compiler resolves binding names might not be sequential nonetheless, even though they are defined in a vector?

alexmiller21:01:17

@jaen yes, essentially - those are two separate things - the vector in a defn is just syntax defined by the defn macro - it's up to defn how it's interpreted

spieden21:01:18

@cfleming: am i missing something?

spieden21:01:35

(i expected :bye to be two spaces in)

cfleming21:01:40

@spieden: What’s the indentation you’re trying to achieve?

cfleming21:01:56

Ok, in that case you want either 1, or “Only indent"

cfleming21:01:10

I really need to put an explanation of how this works in the doc, sorry :disappointed:

spieden21:01:25

ah the unit is level not spaces!

cfleming21:01:36

Umm, no :simple_smile:

spieden21:01:37

maybe just a label on the field

cfleming21:01:46

Here’s how this works:

spieden21:01:51

hmm, setting it to 1 gave me what i expected

cfleming21:01:56

The fact that the indent is two spaces is set separately in Settings-&gt;Editor-&gt;Code Style-&gt;Clojure-&gt;Indent

cfleming21:01:52

Cursive indents forms assuming that you have a head symbol, some number of parameters, and then some number of body forms

spieden21:01:20

ah, so the unit is number of parameters?

cfleming21:01:38

So the head symbol gets no indentation, then the parameters are all aligned, then the body forms are all just indented from the parent.

spieden21:01:54

perfect, thanks

cfleming21:01:57

So that is the number of forms after the head form which will be aligned.

jaen21:01:17

@alexmiller: gotcha; though I must say it might be somewhat confusing for the programmer given that vectors in Clojure imply ordering.

cfleming21:01:29

@spieden: To get a feel for it, play around with (foo :a :c :d :e :f)

cfleming21:01:52

whoops, damn emoticons

spieden21:01:56

@cfleming: makes total sense now — i should have experimented more

cfleming21:01:21

No worries, it needs some explanation in the doc, for sure, and probably in the popup too

spieden21:01:48

making a huge difference already!

meow21:01:46

@cfleming: careful how you talk about my little emoticon buddies - they have feelings too, you know

meow21:01:14

and reactji performance art is hard work for them

meow21:01:22

be gentle

meow21:01:06

@jaen @alexmiller looking at it slightly differently, one could argue that this should be explicitly considered bad coding and no guarantees made as to the order of binding of args to params

meow21:01:41

just to emphasize the distinction

meow21:01:08

whoops, I said that wrong

jaen21:01:32

I disagree. I can agree that {a :a b :b :or {a b b a}} is certainly bad coding, because maps don't guarantee ordering. But a vector?

meow21:01:49

the vector does guarantee the order of binding of arg to params, but not evaluation of params in the :or destructing

jaen21:01:50

Well, if you say > vector does guarantee the order of binding of arg to params then [a & {:keys [b] :or {b (first a)}}] is valid according to that. a is ordered before the destructuring map.

jaen21:01:31

The thing Alex is trying to point out that there can be an abstraction leak of an implementation detail here - if the macro implementation is using a map (which are unordered) to store the parameter names, not a vector, it will break that guarantee.

meow21:01:32

I don't like overly complex destructing in the param def but I'm not sure I can win this argument.

jaen21:01:27

Oh sure, I agree overtly complex destructuring is bad, it quickly starts becoming less readable than having a let in the body and destructuring there

jaen21:01:42

But it's not an excuse for imprecise semantics either.

meow21:01:55

agree 100%

meow21:01:28

I used to have an annoying friend that had a habit of saying "I agree with you 100% but..."

meow21:01:42

and he was serious

meow21:01:47

clueless jerk

jaen21:01:04

That's imprecise semantics right there ;' )

meow21:01:19

:simple_smile:

alexmiller22:01:22

@jaen: fwiw, I agree with you that your expectation is reasonable, and that it shouldn't be ambiguous :)

alexmiller22:01:58

destructuring is actually implemented in clojure.core/destructure - a fn that rewrites into the bindings for a let

alexmiller22:01:43

so this example would be invoked with something like (destructure '[[a & {:keys [b] :or {b (first a)}}] [[1]]]) where the data being bound is [[1]]

alexmiller22:01:09

the result (re-formatted a bit) is the binding part of a let:

alexmiller22:01:31

[vec__21 [[1]]
 a (clojure.core/nth vec__21 0 nil)
 map__22 (clojure.core/nthnext vec__21 1)
 map__22 (if (clojure.core/seq? map__22)
           (clojure.lang.PersistentHashMap/create (clojure.core/seq map__22))
           map__22)
 b (clojure.core/get map__22 :b (first a))]

alexmiller22:01:02

and it's clear that this happens in-order such that a is available for the :or destructuring

alexmiller22:01:33

while I maintain that nothing exists in the Clojure docs to guarantee this behavior, I think given the extensive use of this code both inside and outside Clojure, I think it's highly unlikely we would alter this aspect of the implementation

alexmiller22:01:34

I'm going to file a ticket to clarify this stuff and add tests related to :or (which do not exist)

jaen22:01:21

Yeah, would be nice to document the fact that vector destructuring is sequential so that it is part of the language spec.

meow22:01:57

@alexmiller: you rock!

meow22:01:16

@jaen: so do you :simple_smile:

jaen22:01:39

Nah, I'm just obnoxious xD

meow22:01:02

as I aged it mellowed into sarcasm

jaen22:01:36

Yeah, at 26 it's probably just annoying : V But at least we do get a doc improvement out of that.

alexmiller22:01:12

there is really a cluster of problems (mostly around :or) that would be nice to clear up (both in docs and in implementation)

cfleming22:01:39

@alexmiller: Anything that makes the semantics of this clearer is great by me!

alexmiller23:01:55

@jaen I created a ticket for this specific issue at http://dev.clojure.org/jira/browse/CLJ-1881 and a thing that groups a bunch of other tickets at http://dev.clojure.org/display/design/Destructuring+cleanup

jaen23:01:50

Nice : )