-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Full YASGuide implementation #198
Comments
@ararslan which of these is preferable
|
That's a good question, I don't think I've ever seen a comment in the middle of a comprehension. The YASGuide itself definitely doesn't have anything specific to say on this. I'd probably be inclined to prefer the latter just because I would find it visually odd to separate loops that way, but also having the dangling I guess a third option is comp = [a * b + c
for a in 1:10, # comment
b in 11:20,
c in 300:400] but that indentation feels unsatisfyingly arbitrary. |
Yeah, I don't think the YASGuide mandates anything here, but in my own code, I think I tend to prefer @ararslan's third option. For complicated multiline comprehension bodies, I'll sometimes use comp = [begin
x = a * b + c
y = x^2 + 3x # comment 1
end
for a in 1:10, # comment 2
b in 11:20,
c in 300:400] I haven't thought too hard about this preference though 😁 |
It's no longer possible to use |
It's allowed in untyped comprehensions like this one, but not in typed comprehensions. |
Ah, gotcha. |
should this be formatted differently then? https://github.com/beacon-biosignals/Onda.jl/blob/master/examples/tour.jl#L61-L62 |
I'd say so, good catch 😄 |
can you give an example? |
@StefanKarpinski are there a cases where import would be preferred instead of using? |
If you want to add methods to the binding without qualification then module A
export f
function f end
end Then this doesn't work: julia> module B
using ..A: f
f() = 1
end
ERROR: error in method definition: function A.f must be explicitly imported to be extended
Stacktrace:
[1] top-level scope at none:0
[2] top-level scope at REPL[2]:3 Whereas this does: julia> module B
import ..A: f
f() = 1
end
Main.B I don't particularly like this distinction and argued against it pre-1.0, but there you have it. If, however, you use qualified names to extend imported functions then you can always use julia> module B
using ..A: A, f
A.f() = 1
end
WARNING: replacing module B.
Main.B Note, however, that if you're explicitly listing the names to include, you have to list |
hmmm ok, I was wondering whether I should make that conversion the default but it looks like it could break code in some cases |
There's definitely a transformation that could be done, but it's more annoying and non-local than one would want. The normalization that would be safe is this:
So yeah, that's a very annoying and fussy normalization process just to unify on
I think that should never break code. And of course, you'd want to combine |
For the purposes of YASGuide compliance, |
function f(x)
function g(y)
# do whatever
return thing
end
return something
end should instead be function f(x)
g = y -> begin
# do whatever
return thing
end
return something
end |
Yup, this is a requirement of the YASGuide anyway:
|
sample formatting so far beacon-biosignals/Onda.jl@master...domluna:test-yasfmt
|
Requiring function f(x)
g = y -> begin
# do whatever
return thing
end
return something
end prevents defining inner functions that have multiple methods. Seems like an overreaction to the fact that putting method definitions in the branches of a conditional doesn't do what one expects. |
Yeah, Eric Davies and I had a good chat about this rule in Slack a while back; looks like history has been erased by now though 🤦♂should've saved it. To provide a concrete example in the vein of what you said, the rule is there in an attempt to make it less likely for people to confuse themselves by doing stuff like julia> f(::Int) = 1
f (generic function with 1 method)
julia> function g(x::T) where {T}
f(::T) = 2
f(x)
end
g (generic function with 1 method)
julia> g(1.0)
2
julia> f(1.0)
ERROR: MethodError: no method matching f(::Float64)
Closest candidates are:
f(::Int64) at REPL[1]:1
Stacktrace:
[1] top-level scope at REPL[4]:1 ...where a lot of newcomers will get confused/frustrated by the fact that there wasn't some persistent top-level method overload. Not that that's a reasonable expectation on their part, just a common mistake I've seen folks trip up on. IIRC the conclusion of the chat with @iamed2 was that inner method overloads were useful enough as a feature that this rule was deemed overly defensive and not worthwhile for BlueStyle. In practice, I think you can often (but maybe not always? haven't thought about it) refactor actual usages of this feature to instead use explicitly callable types instead of inner methods. My preference for that is much more subjective and less substantiated though. This isn't a super critical rule for me, and I could be convinced to change it; for example, if we ever went through the massive bikeshed required to merge YASGuide and BlueStyle, this would be a rule I'd easily give up for the sake of compromise. |
This actually introduces a few guide violations:
Couple of "not sures", would be good to have @jrevels chime in on them:
|
bug
bug
not implemented yet |
Thanks for confirming 🙂 |
For the following
would you want return inserted as well?
|
Yep 👍 |
Made more improvements: JuliaLabs/Cassette.jl@master...domluna:yasfmt |
I'm going to clean up the draft branch and merge it in since there's non YAS specific improvements in there as well. Any other additions / fixes will follow. Also, I'm going to hold off on the last 2 items on this list for now - there's a couple other items I'd like to investigate in the meantime. |
This is part of v0.4 now |
I just had a go at running JuliaFormatter on a small non-open source YASStyle repo and it worked pretty well, as vetted by @ararslan! Just ran into two things, first I think the method function p_kw(style::YASStyle, cst::CSTParser.EXPR, s::State)
t = FST(cst, 0)
for a in cst
add_node!(t, pretty(style, a, s), s, join_lines = true)
end
return t
end taken from the example https://domluna.github.io/JuliaFormatter.jl/dev/custom_styles/ should be added for The second is that function f()
for long_variable_name in ("Fusce eu justo at purus finibus sagittis.",
"Nulla egestas magna vitae lacus.",
"Aenean finibus nisl at magna feugiat finibus.",
"Etiam sodales ligula a hendrerit efficitur.",
"Vestibulum sed lorem vel massa consequat.",
"Nulla ut turpis pretium, sollicitudin.")
println(long_variable_name)
end
return 1
end is YAS-compliant but gets undesirably formatted into function f()
for long_variable_name in
("Fusce eu justo at purus finibus sagittis.", "Nulla egestas magna vitae lacus.",
"Aenean finibus nisl at magna feugiat finibus.",
"Etiam sodales ligula a hendrerit efficitur.",
"Vestibulum sed lorem vel massa consequat.",
"Nulla ut turpis pretium, sollicitudin.")
println(long_variable_name)
end
return 1
end I'm not really sure what rule could be made but it's better to have the list start on the first line rather than have 2 items on the second line. |
Not sure about YAS, but it seems to me that the preferred formatting of the latter example would be: function f()
for long_variable_name in (
"Fusce eu justo at purus finibus sagittis.",
"Nulla egestas magna vitae lacus.",
"Aenean finibus nisl at magna feugiat finibus.",
"Etiam sodales ligula a hendrerit efficitur.",
"Vestibulum sed lorem vel massa consequat.",
"Nulla ut turpis pretium, sollicitudin.",
)
println(long_variable_name)
end
return 1
end |
for the 1st point you can set For the 2nd point it's nesting/breaking on |
Ah, thanks for updating the docs. I actually didn’t realize that those options weren’t set automatically by choosing For the second point, I don’t know if YAS is specific enough about exactly how nesting should work but based on the example, maybe the rule could be the list should start on the first line unless the length exceeds 92 chars? Or if each entry (any entry?) is longer than X amount they should each be on their own lines? @StefanKarpinski I like that style too since it’s easy to add/remove items without touching other lines. I don’t think all users of the YASGuide necessarily agree (I think @ararslan doesn’t prefer it?) but I also don’t see anything in the guide itself one way or another about it, besides that the arguments should line up, as they do in your example. |
this was originally how it was but then there were requests to have spaces between keyword arguments but keep yas style indentation so it was split out into an option. What a style has governance over has changed over time but at the moment the styles handle indentation and nesting (line breaking). Of course there's nothing stopping a style from handling more than indentation and nesting but given people have different preferences (even for the small things) decoupling these things as much as possible is the way to go IMO. |
Couldn’t that happen by the style changing what the default choices are but not overriding the options altogether? Eg that could be enabled by using YASStyle + a keyword argument. Definitely makes sense to me to have options but it also seems like it would be good if choosing Not a big deal either way though! |
The options part of the style I suppose, then the defaults could be different for each style |
@ericphanson it's technically disallowed by the current rule, ref jrevels/YASGuide#16 for discussion/bikeshed on that one |
Ah, thanks for the clarification. |
With open("table.txt", "w") do io
println(io, table)
end gets reformatted into open("table.txt", "w") do io
return println(io, table)
end which doesn't seem right to me. I could put an explicit |
AFAIK the transformation there is correct per the YASGuide. |
the return thing doesn't always work as one might like on some edge cases right now though #233 |
FYI e.g. (using JuliaFormatter v0.10.9) julia> str = "foo(1, 2, a=3)";
julia> println(format_text(str, YASStyle()))
foo(1, 2, a=3)
julia> println(format_text(str, BlueStyle()))
foo(1, 2; a=3) |
Here are some (hopefully complete) to-dos to make the experimental YASGuide implementation complete, for whomever wishes to work on it. This is the style guide my company uses, so we'd likely adopt JuliaFormatter if it supported it. This guide has a significant amount of overlap with BlueStyle, so adding the functionality outlined below would also increase the ability to support other popular guides. (Indeed, all but a couple of these apply to both YAS and Blue.)
;
to separate positional and keyword argumentsx |> f
tof(x)
format_text
errors for me with function arguments on multiple lines)return
for returned values in long form function definitions anddo
blocksx[i+1:end]
->x[(i + 1):end]
)import X
tousing X
@Module.macro
toModule.@macro
::Any
=
in named tuple literalsThe text was updated successfully, but these errors were encountered: