I’m having a hard time with “defer is executed at the end of the scope” thing.
I want to do conditional defer, i.e. “defer this call if the condition is met”. But I can’t do that with current defer behavior:
foo :: proc() {
cond := true
// This won't work, because defered call will be executed at the end of the `if` block
if cond {
defer fmt.println("if cond { defer }")
}
// This will won't work because of the same reason
if cond do defer {
fmt.println("if cond do defer")
}
// Edit: Same behaviour here
if cond do defer fmt.println("if cond do defer")
// This won't work because `if cond` check will be executed at the end of the procedure
// and at that moment cond will be modified to false
defer if cond {
fmt.println("defer if cond")
}
cond = false
fmt.println("exit")
}
Is there a way to evaluate if
outside of defer and at the same time defer the call on the procedure level (and not in if block level)?
I am completely new and clueless to Odin, but why not:
if cond do defer fmt.println("if cond do defer")
Untested, but it just might work 
Edit: I read/saw somewhere that “braces or a do are always required”
Tested it now, it worked the same way as if cond do defer { … }
foo :: proc() {
cond := true
// This won't work, because defered call will be evalueted at the end of the if block
if cond {
defer fmt.println("if cond { defer }")
}
// This will won't work because of the same reason
if cond do defer {
fmt.println("if cond do defer {}")
}
// Same behaviour here
if cond do defer fmt.println("if cond do defer")
// This won't work because if cond check will be evaluated at the end of the procedure
// and at that momend cond will be modified to false
defer if cond {
fmt.println("defer if cond")
}
cond = false
fmt.println("exit")
}
if cond { defer }
if cond do defer {}
if cond do defer
exit
I tested it by copying the cond to other_cond and set other_cond to false:
...
other_cond: bool = cond
other_cond = false
fmt.println("exit")
}
The output:
if cond { defer }
if cond do defer {}
if cond do defer
exit
defer if cond
If it doesn’t work with the same boolean, why not capture it at the start of the procedure and use that for the defer?
I did it the other way around out of laziness 
Edit: I know that I am not really answering your question, but it’s better than no input, I hope!
Technically yes, it would be better to not reuse original boolean. But I can think of situations when that’s not the case. E.g. when using ok
variable with multiple function calls
If any function call fails, and you are forced to exit/panic, then the defers will be called at the end of scope, so no need to use a bool to test if a defer should be set.
I wouldn’t use defer for program logic, just something that is guaranteed to be called if something goes awry. Like _at_exit() or whatsitcalled in C.
I wonder if this is acceptable to you.
At the point where you would do if cond do defer
, which is the point which you want to cement the value which the defer will respect, I instead set a constant. This constant is made especially for the defer block.
main :: proc() {
// Use this for defers - const so it can't change before defer
cond_DEFER : bool : true
// Use a copy for logic that is mutable.
cond : bool = cond_DEFER
cond = false
defer {
if cond_DEFER do fmt.println("deferred and iffed")
else do fmt.println("deferred and elsed")
}
}
Of course you could expand it to use a switch statement for more complex situations, and if your goal is some type of error handling I imagine the switch is what you would use.
1 Like
main :: proc() {
@(deferred_in=check_later_guard)
check_later :: proc(b: bool, pred: proc(bool)) -> bool {
fmt.println("initial value", b)
return b
}
check_later_guard :: proc(b: bool, pred: proc(bool)) {
fmt.println("defer value", b)
pred(b)
}
ok := check_later(false, proc(b: bool) {
if !b do fmt.eprintln("error...")
})
fmt.println("ok is =", ok)
ok = true
fmt.println("ok is =", ok)
}
Bit more cucumbersome but this will call the guard at the end of the function, and can be reused multiple times so you don’t have to have multiple magic variables declared. 
2 Likes
why not keep this simple and make a copy of the condition so that it is evaluated there and then?
this_cond := cond
defer if this_cond {
fmt.println("defer if this_cond")
}
6 Likes