-
Notifications
You must be signed in to change notification settings - Fork 5
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
Insert explicit return expressions in functions/macros/do-blocks #48
Conversation
Currently broken for For inserting into macro's like |
Not broken but simply that the last expression is the macrocall here. It does't seem valid to peek inside the macro, but perhaps it can be done for macros that have one argument and the argument is a code block or something? Alternatively, if the last expression is a macrocall it could just be left as is...
Yea, maybe this (and other existing transformations?) need to be disabled inside macros. |
This would rule out |
f859303
to
ff383c0
Compare
I think I like normalizing to |
Right now it will leave
I think it would be slightly annoying if Runic removed the
Sure, maybe that is better. |
Yeah, I just noticed that Runic wasn't consistent in what it inserted. I do agree with not removing explicit "return nothing". |
Hmm, it should be? If you are thinking about the diff in JuliaGPU/KernelAbstractions.jl#516 the cases where there is just a |
I also noticed in JuliaGPU/KernelAbstractions.jl#516 and JuliaDocs/Documenter.jl#2564 that whenever the function ends with and |
222fc20
to
5d9634e
Compare
Fwiw my preference would be
|
Would you then also insert
should become
?
If I understand you correctly then this isn't a valid transformation because the value of the complete |
Are you asking about this function? function foo1(cond)
if cond
1
end
end This code has a hidden function foo1(cond)
if cond
1
else
nothing
end
end |
Yes that's what I meant, and I agree that adding the else branch makes the nothing return value more obvious. |
Just to show what I mean, here's some more code. A function with only one (1) exit point doesn't need return. function f(x)
y = x + 1
x + y
end A function in which at least one (>=1) exit point returns a value, all exit points should return a value explicitly, including function f(xs)
if isempty(xs)
# Explicitly return `nothing` here.
return nothing
end
println("hello") # side effect in branch
return Some(first(xs))
end A function in which no branch (0) returns a value just uses function f(xs)
while true
if isempty(xs)
return
end
pop!(xs)
end
end |
I disagree with this. If for example the last statement is a function call it is unclear if it's value is indented to be returned or if it just happens to be the last statement. |
A function's return value is an important part of its contract, so I don't think it should be left unclear. However, leaving the bare expression at the end doesn't prevent accidentally returning values, so adding When I don't want to return the last value, I will add When I do want to return a value at the end, I just leave it. It's concise and effective. |
5d9634e
to
8d45d65
Compare
Just to add another perspective into the mix, I'm rather attached to expression-oriented over statement-oriented programming. In my codebases, in line with this, I only use Thoughts on the `if ... end` exampleI much prefer having function preferred(args...)
# some work...
if cond value end # I know people have thoughts on inline if statements too, but I like them when they're short
end over function disliked(args...)
# some work...
if cond
return value
else
return nothing
end
end I find arguments[1] around accidental[2] return values somewhat convincing, but would find it a pity if this resulted in autoformatting[3] that structured Julia code more like a statement-oriented language despite Julia being largely expression-oriented by design. [1]: Some earlier discussion on the topic, https://groups.google.com/g/julia-users/c/4RVR8qQDrUg |
8d45d65
to
3e0f791
Compare
This patch make sure that function and macro definitions, as well as do-blocks, end with an explicit `return` statement before the last expression in the body. The following exceptions are made: - If the last expression is a `for` or `while` loop (which both always evaluate to `nothing`) `return` is added *after* the loop. - If the last expression is a `if` or `try` block the `return` is only added in case there is no `return` inside any of the branches. - If the last expression is a `let` or `begin` block the `return` is only added in case there is no `return` inside the block. - If the last expression is a macro call the `return` is only added in case there is no `return` inside the macro. - If the last expression is a function call, and the function name is `throw`, `rethrow`, or `error`, no `return` is added. This is because it is pretty obvious that these calls terminate the function without the explicit `return`. Since adding `return` changes the expression that a macro will see, this rule is disabled for function definitions inside of macros with the exception of some known ones from Base (e.g. `@inline`, `@generated`, ...). Closes #43.
3e0f791
to
a7eb0dc
Compare
…cks (fredrikekre#48)" This reverts commit cca294f.
Just FYI, for my own usage I'll be using a fork of Runic with this rule disabled. |
This patch make sure that function definitions end with an explicit
return
statement before the last expression in the body.If
for
orwhile
is the last expression areturn nothing
node is inserted after the loop instead ofreturn for ...
.if
,try
,let
, andbegin
are currently are left as they are. Perhaps in the future Runic will recurse down into branches, or insertreturn if
but for now this is left alone.Another exception is also made whenever the last expression is a call to
throw
orerror
because it is pretty clear that the function will not return in this case (return throw(...)
look silly).Closes #43.