-
Notifications
You must be signed in to change notification settings - Fork 23
Description
here's my thought regarding effectsDelayed (nim-lang/Nim#18610): IMO what we should do instead is same as what we do for {.nosideeffect.}, where a func is allowed to have side effects so long they're only through parameters:
nosideeffect: effects are allowed through params:
when true:
proc fn1 = echo "ok1" # sideeffect
proc maybeCall(a: proc()) = a() # maybeCall can be assumed to call a
func bar1(a: proc()) = a() # direct call => no func violation because all sideeffects happen through params
func bar2(a: proc()) = maybeCall(a) # potentially indirect call vs direct call doesn't matter: same analysis as bar1
bar1(fn1) # ok
bar2(fn1) # ok
when false:
# this correctly gives: Error: 'bar3' can have side effects
# the side-effect is not through a param => error
func bar3() = maybeCall(fn1)
raises: effects should also be allowed through params:
when true:
proc fn1 =
if false: raise newException(ValueError, "")
type A = proc() {.raises: [ValueError].}
proc maybeCall(a: proc()) = a()
proc bar1(a: proc()) {.raises: [].} = a()
proc bar2(a: proc()) {.raises: [].} = maybeCall(a)
bar1(fn1)
bar2(fn1)
var f: A = fn1 # ok
when false:
# this correctly gives: Error: fn1() can raise an unlisted exception: ref ValueError
# the raises is not through a param => error
proc bar3() {.raises: [].} =
fn1()so far so good, it behaves the same as nosideeffect.
The problem is the following; which is what this RFC is about:
when false: # BUG!
# this gives: Error: a() can raise an unlisted exception: ValueError
# BUG: this should work, because the raise only happens through params
# it doesn't make sense that we'd disallow this but now `bar1` which is more general
proc bar4(a: A) {.raises: [].} = a()
# proc bar5(a: A) {.raises: [].} = maybeCall(a) # same as bar4, the distinction indirect vs direct should be irrelevantproposal
- don't introduce
effectsDelayed, it's not needed - make effect tracking work uniformly and in same way as it already works for
nodesideeffect, such that effects are allowed through params - in the manual https://nim-lang.org/docs/manual.html#effect-system-exception-tracking, remove distinction between direct and indirect call, it's not what's relevant; what's relevant is whether the effect happens through a param (allowed) or not (tracked and disallowed if mismatch)
note
this is analog to how purity works in D, eg: https://forum.dlang.org/thread/[email protected]
D's working definition of a pure function is "effect only depends on parameters". Mutating parameters does fit the definition.
This is less tight than other languages' definition, but we believe it's a sweet spot between reaping the modularity benefits of purity, and benefiting of the advantages of mutation.
and related articles, eg: https://klickverbot.at/blog/2012/05/purity-in-d/
›Weak‹ Purity Allows for Stronger Guarantees