13 comments

[ 2.7 ms ] story [ 30.4 ms ] thread
Of course, to "really" solve this problem you'd have to recognize "mutually unused" arguments: foo(a,b) calls foo(b,a) and doesn't otherwise use the arguments. But foo(x,a) which uses x and calls foo(a,x) uses both. Not difficult to solve, and a few seconds' thought puts it in O(m*n) with m recursive calls and n parameters... but probably not worth the trouble.
Even worse, foo(a,b) could call bar(a,b,c) which calls foo(b,a), all without otherwise looking at a or b. This could get really bad really fast.

But that feels like the wrong way to analyze this. Even though a full solution isn't practical, a limited one may be.

There is no way of fully detecting it, because of function pointers.
Sorry, how is this O(m*n)?
Hmmm... represent the parameters as nodes in a directed graph. For each of m recursive call sites, process each of n parameters and add edges from formal parameter name to passed argument (i.e., if we have signature foo(a,b,c) and recursive call foo(c,b,c), add edge a->c; self-edges are unimportant). This step is O(mn). Then, assuming we already know what parameters are used outside of function calls, flood-fill the graph from those nodes; this is O(n). O(mn+n)=O(m*n).
> "Then, assuming we already know what parameters are used outside of function calls" This is something that needs to be done, I guess my confusion was that you already have this information and that should be sufficient to finding the unused parametres.
This really is looking like a job for a static code analyzer. I'm all for the compiler emitting warnings as much as it can, but I also want it to compile my code very fast...

I think the right approach here is to run slow code analysis tools frequently, but less frequently than compiles.

ok my brain is running on empty right now but I don't really see any explanation about what the problem actually is... I get that something related to some scripting language you're using for your game isn't working, but you never actually explained what is broken.

Are unused arguments a problem when recursing? I can imagine they are if they're taking up stack space and you're doing an awful lot of recursing (I don't really use recursion enough in my C++ code to really run into issues like this, so I am a little ignorant on the side effects of recursing deeply).

Anyway it's time for bed and I'm sure this article is going to be giving me nightmares tonight.

I think the problem the author is trying to bring up is that if the only place the variable is used is in a recursive call, this should be the same warning as if its not used at all. There's no way it can impact the return value (or side effects) of the function.
I found this a bit confusing as well at first, but it's really simple enough: The point of the article isn't the scripting language itself. It's that the author encountered a bug in the scripting language implementation that would have been found much earlier if the compiler had warned about the argument that is de facto unused.

This is a general point: More warnings can help find more bugs earlier - but you do have to worry about false positives, and warnings that increase compile time can also be a net negative.

The author's example is probably simple and efficient enough to add to a compiler, assuming that it performs some basic recursion analysis already.

gcc also doesn't detect the unused variable. Looking at the -Wunused warning description it does so correctly since a variable is considered unused if it is declared only. In this case it is also used as a parameter.

To detect it, split the recursive function into two, one that recurses and one that does the job at the end. Both can take the same relevant arguments and the latter function will detect any unused parameters.

Just a gut feeling. Properly solving this might require solving the halting problem: you don't know the variable is unused until you actually evaluate the code. Otherwise you can only aim for detecting very trivial cases.
Yes. See my comment below. The bug is trivially avoided by adhering to a coding standard that actually makes the code better. See my other comment below.