Replies: 14 comments 44 replies
-
Wow! That's a lot to digest. Thank you for the effort to explain all of this to me. I have read this over several times, but not yet gone into great detail in trying to make it happen. Overall, zprint is designed for just this sort of thing -- you can have it the way you want it. As you have noted. This writeup could certainly make it into the documentation for zprint, possibly with minor adjustments to the tone so that it isn't quite so adamant about the "right" way to do things. But we can see about that as we get it working. At first glance, these are the things that might be hard:
I'm not asking for you to explain more at this point, though I will be for sure as we get into this. I want to fix the existing bugs (in particular the multithreading one you noted, #226), and get a new release out. After that, I think the way to approach this is to work on one or two sections at a time, get them the way you want, and then move on to the next. Possibly with a number of alpha releases that you can play with to see how it works. I envision this overall as a Thanks again for the effort in writing all of this up. I'm looking forward to getting into this soon! |
Beta Was this translation helpful? Give feedback.
-
Cheers. Thanks as always for taking these into consideration.
👍
FWIW, for my use case I plan invoke zprint from the same JVM as the REPL's, so that knowledge would be accessible. For the "binary / CLI" use case, I could regularly emit zprint files from said REPL JVM, keeping those auto-generated files version-controlled, maybe shared in a .jar, etc.
You can find snippets for
Yes, that would be perfect. Feel free to work on these in a PR format and request a review from me. Quite obviously I'm not in a position to review the impl - instead I can come up with more / trickier test cases for each feature.
Indeed, this would maximize usefuless and ensure cleanliness. |
Beta Was this translation helpful? Give feedback.
-
So, I've made some good progress with this work. I have implemented the function name "alias" you suggested in Issue #234. I have also added a particularly finicky enhancement which allows configuration of multiple lines in lists, which several of your requests required and which zprint pretty much didn't do (without using guides). I have also slightly enhanced guides themselves. I rewrote the So, I have a moderately enhanced basic zprint (library). I have then written an options map which seems to do (most of?) what you are requesting. At some point, when (if) we like it, I'll bake the options map in as a style directly into zprint, but treating it as a separate "thing" at this point makes sharing changes easier. I am very interested in you having a chance to try this, in part simply to find test cases where what I've done simply doesn't work right, and also to expose places where my understanding of what you desire is flawed. I expect about equal numbers of each kind of problem to appear. My thinking on how to share this with you is as follows. I believe you are using zprint as a library, so if I were to push up a In addition to an alpha library and an options map to use when testing things, I also need to respond to a number of your requests with a comment or two. Just FYI (as I'll probably change it a bit as I continue testing), here is the current options map:
As you can see, the numbers in the "sub-styles" correspond to the numbers you created in this issue. I expect that when we are finished, I'd name them something more evocative, but for now I wanted to be able to figure out what I was doing relative to what you requested, above. I'll give explicit instructions as to how to use this after I hear back from you and post an alpha. It has been an interesting experience trying to bend zprint to fit your approach, and so far I have been kind of surprised at how few modifications I had to make to the basic code to get as close as I have gotten (which may or may not be on target, we'll see). I have certainly had to read my own documentation, since some of the features I'm using were implemented several years ago. |
Beta Was this translation helpful? Give feedback.
-
General comments on your definition of "semantic", above: 1.5 - Macros taking a & body
For the If there are any with three arguments and then a body, I'd love to hear about it. Well, not really, but it would be good to know. At present zprint has no way to know about macros in real time. I know that your use case has access to this information, and so you can tell zprint what should be done, but that's not something that I can solve in the general case. We might want to talk about just how you might want to tell zprint what should be done in case I can make that more efficient or easier for you to do. One take-away for me is that I need to implement 2 - Independent forms within a body get one line each Basically, zprint doesn't ever do this. Well, with some work you can configure it to do this, and you can do this easily with guides, but unless you try hard, zprint won't do this. 3 - The first argument of a function call must be placed in the same line as the function name
zprint will never do the "incorrect" version, above. What you are looking for is for a function that doesn't fit on one line, for zprint to "hang" the arguments, instead of "flowing" the arguments. If the hang causes things to look bad (i.e., it is toward the margin, and pushing things even more toward the marging looks bad), then zprint will do this:
It will make the indent appropriate (when using If you want people to fix things manually, the issue seems to me to be: how to tell them that it needs to be fixed? One answer would be to think of this kind of output:
as a signal that you should fix things so that a hang will fit. Or, if it doesn't bother you, don't change it. 4 - Multi-line sexprs cannot be siblings of single-line sexprs zprint will never do the incorrect thing. Well, I can configure it to do so, but unless I work hard, it will not do this. 5 - Argument vectors are placed in the same line as the function name To the best of my knowledge, the current implementation of |
Beta Was this translation helpful? Give feedback.
-
Just a quick thought on 1.6, above -- where you want
zprint has the capability to format things with two arguments on one line, but force them to hang (as you specify above) if there are more than two arguments (or more than three arguments). So, it could be configured easily to do this:
If that is interesting to you. |
Beta Was this translation helpful? Give feedback.
-
I'm going to convert this issue to a "Discussion", with the category of "Ideas". I think that we will be better able to go back and forth and actually interact on the various details of what you want there. I've never done this before, so my apologies if it all falls apart. Presumably GitHub will place a pointer in this issue redirecting you to the appropriate discussion. |
Beta Was this translation helpful? Give feedback.
-
One of the things to think about as we move forward here is how much of what zprint does by default do you want to keep around? That is what the first sub-style is all about:
This is just a placeholder for removing the formatting instructions for things you don't want. It actually is meaningless as presently written, as both But the question is real. As an example, take
Thus:
This is sort of a small thing, but it may or may not fit into what you want to do. There are a number of |
Beta Was this translation helpful? Give feedback.
-
What do you want to do with multi-airity things in a For instance, I'm guessing that this is not what you want:
I expect that you would like the multi-airity
But I don't really know what you have in mind here. This isn't a trivial question, as the first is what comes out today. The second example I have hand-edited. I will have to work to make that happen, but if that is what you want, I'll figure it out. I have some ideas on how to do that. |
Beta Was this translation helpful? Give feedback.
-
Getting back to the discussion ASAP, apologies for the delay and thanks so much for the news! |
Beta Was this translation helpful? Give feedback.
-
@kkinnear : trying this out. In the meantime it seems worthwhile to merge master into |
Beta Was this translation helpful? Give feedback.
-
Ok, so I've given it a quick pass. A first issue that I observed is that if both Also, (defprotocol ISql
:extend-via-metadata
true
(execute! [this q])
(execute-one! [this q])) ...This would seem a reasonable "rule": (defprotocol ISql
:extend-via-metadata true
:other-option true
(execute! [this q])
(execute-one! [this q])) i.e. options are expressed in one line each, with no surrounding blank lines. Finally, I could keep trying out :sall after getting these sorted out - sounds good? Thanks! |
Beta Was this translation helpful? Give feedback.
-
I have pushed a new branch, Here is the associated options map:
Note that I created yet another style: I believe that this branch and options map fix all of the problems that you have so far identified. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the update. I may just be having a slow day, so excuse me if this makes no sense. (It is very hot where I am at the moment, and as I am quite literally "off the grid", AC isn't an option.) You mentioned two groups of functions above, those with "indent of 1" and those with an "indent of 0". Generally, zprint does an For the group above, the one starting with
I think of this as "body" indentation (when doing For the second group above, the one starting with
I also think of this as I was thinking this might be Given the two groups above, Thanks! |
Beta Was this translation helpful? Give feedback.
-
Also, there are no regex rules. Somebody asked for some a long time ago, but the trouble with regex rules is that instead of a single relatively fast map lookup on every function name (or sometimes two if there is a "/" in the name), zprint would be doing multiple series of regex matches on every function name. The performance difference would probably be noticeable, though I haven't actually implemented it enough to benchmark to be sure. I do know that I've spent a lot of time working on performance, and so I've been unwilling to move backward when I can reasonably avoid it, and I imagine that regex-based rules would be a step backward. Just FYI. |
Beta Was this translation helpful? Give feedback.
-
Hi there,
in #170 we devised a style called
:rod
which various people liked/adopted. I'm using it at work currently (even if we aren't quite happy with the results yet).However I never found the time to explain more exhaustively how it looks like (for a variety of forms), and importantly, why, so that users can understand this choice and perhaps make this style easier to share/adopt.
While :rod isn't necessarily a widespread style, it is a very reasonable/non-fanciful one, derived (and compatible) from well-known styles and backed by years of real-world usage in team settings.
Importantly, I think that implementing this style would be a great showcase/benchmark for zprint's capabilities, and surely would leave composable primitives.
Perhaps
:rod
was bit of an organic name, I think that:semantic
would do it more justice.So, without further ado...
The
:semantic
styletldr
:semantic
is a subset of:which is stricter in a few ways, emphasizing meaning over concision, and a sense of homogeneity that makes formatting more predictable (e.g. I can predict how a formatting will look like, vs. seeing a seemingly random result influenced by concision or a column limit).
Explanation
It is 'semantic' in that there's a rigid mapping between forms (e.g.
defn
,if
) and where the newlines should be located. So a maintainer can say things such as:In other words: by visually scanning the whitespace, before seeing the contained forms, I can already tell what I'm about to find.
This IME greatly decreases cognitive costs, reducing friction as one reads/maintains code.
Importantly, it makes Clojure look more 'like a language', as opposed to simply mashing sexprs together.
Case study:
if
As a very self-contained example of my ideas, we can consider
if
. Here's an example to be avoided:What's wrong here?
(foo)
represents a condition, while1
represents a 'then'. By placing them in the same line, they look as if they belonged to the same category.They don't: they're not simply different items in a list, but things with profoundly different meanings.
So allocating one line for each kind of thing makes this distinction clearer:
There are many other examples for making such distinctions. Such as:
Here we put an argv and a
[]
return value in the same line. They look visually identical and nearby, so one is suggesting that they are the same kind of thing, when they aren't.This is what I mean with
make Clojure look more 'like a language'
. In many programming languages observes a certain relationship between syntax and newline placement, and honors it even if there's a way to shortcut it.The rules in question
1 - Certain forms have a canonical newline placement
Under
:semantic
, certain forms have a canonical placement for newlines and blank lines.The most important being the following:
1.1 -
defn
,fn
1.2 -
defprotocol
,defrecord
,extend*
1.3 -
defmethod
1.4 -
if
,if-not
1.5 - Macros taking a
& body
1.6 -
=,
not=
,<
,<=
,or
,and
1.7 -
->
,->>
->
is a bit different: it has some considerations as a macro (relative to newline placement), but it indents like a defn.clojure-mode
also makes this exception.1.8 -
try
2 - Independent forms within a body get one line each
Given a body, e.g.
defn
's ordo
's, no two independent forms should reside under the same line.3 - The first argument of a function call must be placed in the same line as the function name
Given a function call, its first argument must reside in the same line as that of the function being called. This forces aligned style.
If it was impossible to make such a sexpr fit within a column limit, I'd prefer if users fixed it manually (which is very often possible with simple refactorings e.g. split into
let
bindings, or helperdefn
s)4 - Multi-line sexprs cannot be siblings of single-line sexprs
5 - Argument vectors are placed in the same line as the function name
This consideration emphasizes that a function is a function of something. e.g.
f
is af(x)
, which is deeply related to math and FP notation.I think that
:rod
already satisfies a few of this expectations, and probably a few others are very much at hand.For others I don't know if they would entail a lot of work. I'd love to know your impression of what's possible first. If everything seems at hand I can try coding the rules myself which would seem nice.
Probably #223 is a blocker - I can't quite reason about things when they currently happen to be broken.
Also, rule 1.5 requires understanding what "special" and "non-special" (body) arguments are, which is related to #225 .
I hope you appreciate the issue writeup, it might sound ranty in some passages but I'm simply trying to convey its rationale. Probably much of the issue could eventually make it to the official doc? I could eventually further refine these words.
Cheers - V
Beta Was this translation helpful? Give feedback.
All reactions