zverok (Victor Shepelev) wrote in #note-3:
Honestly, it is no different than any name used in a branch that wasn’t tested. E.g. if you have this:
if foo
OneClass.new
else
OtherClass.new
end
...and the else
branch wasn’t covered by tests, and the OtherClass
isn’t defined, then it will struck in production. The rescue clauses can be seen as kind of “syntax sugar” upon this:
# ...
rescue => e
case e
when SomeClass
# ...
when OtherClass
# ...
else
# ...
end
end
Which makes it more obvious that unless you ran into the rescue
branch, any name inside it wouldn’t be evaluated, and no name errors would be caught.
So the common answer is “it should be covered by testing and/or static code analysis.”
Though theoretically, “opt-in forced resolution of everything that looks like a module name” might be an interesting idea to play with (but it probably shouldn’t be limited to rescue
blocks).
I would agree that any such opt-in feature should probably catch other cases. I'd say that there's a bit of nuance here about the testing situation: I feel like, in practice, rescue blocks are much more likely to be neglected in test coverage than else blocks. That is mostly an ergonomic issue around testing, of course. Of course, bigger picture, anything that can be detected at parse-time is one less than for which a test case needs to be written. That constitutes a win for programmer productivity.
To address byroot's comments: I don't follow how it could lead to circular dependency issues, but I confess I have probably not thought it through as deeply so I defer to your thinking on that. I do see how it could make load ordering concerns more in absence of autoload, which is why I suggested it be a purely opt-in feature. Certainly if autoload adds another dimension of complexity, that could make even an opt-in feature useful in significantly fewer cases -- to the point that it might not be worth implementing. That said, I was unaware that sorbet (and potentially steep) addressed this. Thank you! I will check those out.