break after definition return type, but only if function can't be a one-liner?

Hi, list :slight_smile:

I'm new to clang-format, and I'm really impressed with this tool. I
think the value of an automated tool like this is so great, that I'll
happily let it process all my code even if it doesn't do what I want
100% of the time. Most of the times when it's done something
different from my habit, I've decided it actually looks better, and
the only reason I wasn't formatting that way was because it would be a
pain to do it manually. Amazingly, there seems to only be one thing
that makes me hesitate before running it on everything, and even this
"issue" may not stop me from doing so. I'd like to share my use case
& suggested change, and see what you think.

=== MY USE CASE

I want to allow one-liner functions
("AllowShortFunctionsOnASingleLine"), but if a function does not fit
on one line I want to "BreakAfterDefinitionReturnType". The
configuration options don't seem to allow this, although they do what
it says on the tin: "AlwaysBreakAfterReturnType" really means ALWAYS,
but I don't want it always, I want it only if the function can't fit
on a single line. Is this actually possible now, or could it be done
in a future version?

=== MY SUGGESTED CHANGE

My suggestion would be to remove "AlwaysBreakAfterReturnType", and add
"BreakAfterReturnType" with three options: "always", "never", and
"multiline", where "multiline" means break after return type if the
function is not eligible for writing on a single line. Is this a
sensible request? For clarity, "BreakAfterReturnType=multiline" would
be equivalent to "BreakAfterReturnType=always" unless
"AllowShortFunctionsOnASingleLine=true".

Without this change, I think I'd probably turn off
"AlwaysBreakAfterReturnType", but I'd like to have my return types on
their own line & (as a higher priority) have my one-liners too if
possible.

Thanks for any advice :slight_smile: It's a great tool.

-Adam

I am somewhat torn with regard to adding this option. Every additional option has a certain cost associated with it (harder discovery of options, more maintenance, more combinations of options that can lead to undesired behavior, etc.).

Now, these costs aren’t particularly high for the option you are suggesting, but I also don’t understand the gain.

AlwaysBreakAfterReturnType is mostly implemented to support GNU style. The rationale that GNU style gives for having this style is so that it becomes easier to grep for function names, navigate between functions, etc. This rationale certainly doesn’t apply if you exclude single-line functions. If you don’t care about grep’ing of function names, it seems fine to use what LLVM style does and break after the return type first (before breaking anywhere else). Can you elaborate on why you think that your proposed style is useful?

Hi Daniel,

I’ll try to elaborate a bit.

I like one-liners whenever possible because many of my class declarations contain a bunch of one-liners, and if those take 4 lines instead, when I’m looking at that header file I’m not seeing as much of the class declaration in front of me on a single screen, and I don’t like how it looks when a trivial function that “should” be one line (according to me) is gobbling up screen space like that. At the same time, for function definitions that aren’t simple one-liners, I prefer to have the return type on a separate line because I find it easier to read & work with, and I get more room to work with for “ClassName::MethodName(arg1_type arg1_name, …)”. In a way it does have to do with searching for function names: when I’m looking at the code I spend the bulk of my time working with (i.e. not one-liners) I’m accustomed to seeing the return type at the start of a line, and finding on the next line “ClassName::MethodName(”. This is what my brain is used to looking at – finding return types & method names at column 0, but I like the dead simple functions to be one-liners (particularly inside class declarations, although we don’t need to concern the tool with different rules for inside class declaration vs. not).

I think I can only justify my preferences for the formatting up to a point. I think the usefulness of support for a given preference is proportional to the number of users who share that preference. In the case of this change, there seems to not be a large % of users who want the configuration I want. However, as clang-format is more & more widely used (which we can expect), the number of users who would configure it the way I request could easily climb up well into the thousands. I want to highlight a positive aspect of this change, which is that the number of configuration parameters is not increased. This change only re-conceives an existing parameter to make it more capable, and able to co-operate with another existing parameter (whereas “AllowSimpleFunctionsOnASingleLine=true” is currently made irrelevant by “AlwaysBreakAfterReturnType=true”).

Without this change, I’d probably give up the one-liners in my class declarations. Anyway, great tool no matter what. For some reason it was surprising to find a tool that does such a nice job, and can come so close to what I prefer (when not introducing me to new preferences) that I actually may process every source file I ever wrote with it, and even configure emacs to clang-format buffers just before saving.

first, hope that everybody is having a lovely Xmass time.

it is on my todo list to hack the clang-format tool. Wonder if there is
some plugin mechanism in place (or if not, why not think about), that would
accommodate situations presentend by the original poster. It is in my
opinion a healthy middle way. I think once one would discover the power of
the tool, would find tons of ways and reasons to deviate from the existing
bit limited range of options.

As for the option: It has never been the intention of clang-format to support any style that someone somewhere has come up with. We’d rather support a limited set of established styles really well. You could probably make an argument that we have already lost that war, looking at the number of options that clang-format already has. However, we still have the general rule that we’d rather introduce options only for stuff that is used in big (ideally open-source) projects or publicly available style guides. Now again, I don’t think this option will have a terribly high maintenance effort, but it is also not trivial. At least until we are able to pull out a better abstraction for “do this if stuff fits/doesn’t fit on one line”. I still haven’t made up my mind. Are you willing to prepare a patch showing what this would actually look like?

As for a plugin mechanism: I have not come up with a good way to do this yet. Especially, I have so far failed to see what the right level of abstraction would be here. Basically every single of such options requires manipulating a separate set of things. And I am also unsure whether this solves anything. Somebody writing such a plugin will still file the same bugs if we change a different part of clang-format breaking the plugin’s behavior. And then we are in pretty much the same situation except that we might not have the test cases we need and no good way to reproduce the behavior.

It does make sense to me that it’s impractical to have clang-format support all the formatting styles people like. I think if I was maintaining this program, I’d want a stronger justification for increasing the number of configuration parameters than I would for making an existing parameter able to better co-operate with another existing parameter.

I haven’t looked at the source for clang-format yet, but I don’t rule out having a go at making a patch. If I do that I’ll surely send it to you, to get your feedback.

Anyhow, Happy New Year!

I don’t think a new option is necessary here; if you set both AllowShortFunctionsOnASingleLine and AlwaysBreakAfterReturnType, the only reasonable thing you could mean is for the former to overrule the latter. There doesn’t seem to be any inconsistency in saying that AllowShortFunctionsOnASingleLine has higher priority than AlwaysBreakAfterReturnType.

(OK, there’s a remote possibility that you might mean that constructors, destructors, and conversion functions can go on a single line, but functions with return types can’t, which is what clang-format does today, but I don’t think that’s a reasonable formatting style.)

If you (re-)read my original post, I wasn’t actually asking for “AlwaysBreakAfterReturnType” to remain, yet act differently when “AllowShortFunctionsOnASingleLine” is indicated. I suggested renaming it to “BreakAfterReturnType”, with available settings “always”, “never”, and “multiline”, where “multiline” means break after return type unless “AllowShortFunctionsOnASingleLine=true”, and the function can fit on a single line.

Anyway I’ve been formatting with AlwaysBreakAfterReturnType, and I think I can live with the loss of the simple one-liners in the class declarations. It’s just really nice to be freed from having to dink around with the formatting manually, and knowing it’s all consistent.

I think Richard is right, though.

AllowShortFunctionsOnASingleLine should simply trump AlwaysBreakAfterReturnType. Renaming the latter might or might not make sense, but I don’t think introducing an enum for it is necessary.

(Also BreakAfterReturnType=never would be very misleading as clang-format would break after the return type, but that is beside the point).

Oops, I did a poor job reading what Richard wrote. After considering it, I agree it’s not appropriate to rename AlwaysBreakAfterDefinitionReturnType and make an enum for it. If anything, maybe I would just remove the “Always” prefix from the name (while keeping it as a toggle option), but even that may not be necessary. “AllowShortFunctionsOnASingleLine” seems to inherently be a higher-priority directive. There, it occurs to me to remove the “Allow” prefix. Saying X is “allowed” seems to be a bit different from saying “do X whenever you can”. Probably I overthink the names a bit, though.