10

Many months back, I had to fix up some code that caused some problems. The code looked basically like this:

int badFun() { return badFun(); }

This obviously caused a stack overflow even in the high level language I was working with (4Test in SilkTest). There's no way this code could be seen as beneficial. The first sign of problems were warnings seen after the script finished, but no compile errors or warnings. Curiously, I tried writing programs in C++, C# and Python with the same structure, and all of them compiled/interpreted with no syntax errors or warnings, even through there were runtime errors in all cases. I didn't even see any warnings in any of these cases. Why isn't this seen as a possible problem by default?

EDIT: I tried writing the equivalent of that function in all three languages, so I added those function tags. I'm more interested in overall reasons why code like this gets through with no warnings. Please retag if necessary.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
joshin4colours
  • 1,656
  • 4
  • 16
  • 27
  • 4
    Is your question itself about C#, C++ *or* Python? The code sample looks a whole lot like C# to me. – BoltClock Jan 06 '12 at 17:58
  • 10
    It's not the compiler's job to keep you from doing something stupid. In most languages, it's possible for some external event to cause a construct like this to exit. – 3Dave Jan 06 '12 at 18:00
  • In MSVC (C++), it will give you a warning if you call the function: `warning C4717: 'badFun' : recursive on all control paths, function will cause runtime stack overflow` – Mysticial Jan 06 '12 at 18:00
  • 6
    Because it's not the computer's responsibility to prevent you from intentionally shooting yourself in your own foot: http://www.fullduplex.org/humor/2006/10/how-to-shoot-yourself-in-the-foot-in-any-programming-language/ See Lisp. – Bob Cross Jan 06 '12 at 18:00
  • 1
    Some IDE tools will warn you, such as Resharper for C# and VB.NET in Visual Studio. – jrummell Jan 06 '12 at 18:08
  • 1
    But it's the compiler's job to tell me I have a single unused int variable? As opposed to something that can crash my entire app if called? – joshin4colours Jan 06 '12 at 18:08
  • 4
    Tail recursion like this may be implemented as a loop by the compiler, and so this code may not be a runtime error, instead similar to `while(true);` – Pubby Jan 06 '12 at 18:12
  • @joshin4colours: That isn't the compiler's job either (at least in C++). It is purely a quality of implementation question / balancing the cost of detecting this problem (compile-time overhead, programming effort) vs the gains (catching a few problems). - Basically, it is impossible to miss an infinite loop/recursion at runtime, whereas "unused" variables resulting from typos can lead to much more subtle problems. – UncleBens Jan 06 '12 at 19:13
  • @casperOne: Why was this closed? – Neil G Jan 08 '12 at 13:54
  • @NeilG: Just guess but at a minimum the "why" could be different for every single implementation out there (for *four* languages none the less). Rotten question. The right answer is *"Someone decided the `odds of a programer doing that / work required to detect it` made it too low a priority to bother with. End of story. – dmckee --- ex-moderator kitten Jan 09 '12 at 01:24

7 Answers7

38

Here's the deal: compiler warnings are features. Features require effort, and effort is a finite quantity. (It might be measured in dollars or it might be measured in the number of hours someone is willing to give to an open source project, but I assure you, it is finite.)

Therefore we have to budget that effort. Every hour we spend designing, implementing, testing and debugging a feature is an hour we could have spent doing something else. Therefore we are very careful about deciding what features to add.

That's true of all features. Warnings have special additional concerns. A warning has to be about code that has the following characteristics:

  • Legal. Obviously the code has to be legal; if it is not legal then its not a warning in the first place, its an error.
  • Almost certainly wrong. A warning that warns you about correct, desirable code is a bad warning. (Also, if the code is correct, there should be a way to write the code such that the warning goes away.)
  • Inobvious. Warnings should tell you about mistakes that are subtle, rather than obvious.
  • Amenable to analysis. Some warnings are simply impossible; a warning that requires the compiler to solve The Halting Problem for example, is not going to happen since that is impossible.
  • Unlikely to be caught by other forms of testing.

In your specific example, we see that some of these conditions are met. The code is legal, and almost certainly wrong. But is it inobvious? Someone can easily look at the code and see that it is an infinite recursion; the warning does not help much. Is it amenable to analysis? The trivial example you give is, but the general problem of finding unbounded recursions is equivalent to solving the halting problem. Is it unlikely to be caught by other forms of testing? No. The moment you run that code in your test case, you're going to get an exception telling you precisely what is wrong.

Thus, it is not worth our while to make that warning. There are better ways we could be spending that budget.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 2
    +1 Excellent answer and really gets at what I was asking about. I know compilers shouldn't keep you from writing awful code, but good compilers should at least throw a "hey, whatcha doin there?" sometimes. – joshin4colours Jan 06 '12 at 18:41
  • 2
    There is the related problem with `int BadProperty{get{return BadProperty;}}` and its setter equivalent, where the mistake is very easy to make, and not that easy to spot. But this problem is clearly easy to detect when you actually run the code, which reduces the benefit of this feature a lot. – CodesInChaos Jan 06 '12 at 23:10
  • 2
    @CodeInChaos: Indeed, that is one place where the warning might be justified. – Eric Lippert Jan 06 '12 at 23:49
  • 1
    I don't agree with the inobvious -- you should also get warnings for obvious mistakes. – masterxilo Apr 13 '13 at 23:48
22

Why isn't this seen as problem by default?

The error is a run time error, not a compile time error. The code is perfectly valid, it just does something stupid. The very simple case that you show could certainly be detected, but many cases that would be only slightly more complicated would be difficult to detect:

void evil() {
    if (somethingThatTurnsOutToAlwaysBeTrue)
        evil();
}

In order to determine whether that's a problem, the compiler has to try to figure out whether the condition will always be true or not. In the general case, I don't think this is any more computable than determining whether the program will eventually stop (i.e. it's provably not computable).

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • 18
    +1. Compilers don't bother because the halting problem is uncomputable in the general case. – Patrick87 Jan 06 '12 at 18:06
  • 1
    By the same logic, a compiler wouldn't bother to warn about unreachable code. And yet it does - in a particular subset of cases. – harold Jan 07 '12 at 17:44
  • @harold As Eric Lippert explained nicely, it boils down to a decision about the cost and benefit of producing the warning. What I was trying to say here is that detecting the trivial case doesn't seem very useful, and the nontrivial cases where a warning would be useful are likely to be difficult or impossible to detect. – Caleb Jan 07 '12 at 18:41
3

No compiler of any programming language has any sort of idea about the semantics of the code it compiles. This is valid code, though stupid, so it will be compiled.

Mithrandir
  • 24,869
  • 6
  • 50
  • 66
  • The compiler understands a lot about the semantics of code. It would be quite easy to implement this warning on a reasonable level. But I don't know if its worth the work to specify, implement, document and maintain that feature. – CodesInChaos Jan 06 '12 at 23:04
2

How is the compiler or interpreter suppose to know what the function is doing? The scope of the compiler and interpreter is to compile or interpret the syntactical code-- not interpret the semantics of your code.

Even if a compiler did check for this, where do you draw the line? What if you had a recursive function that calculated factorial forever?

Donald Miner
  • 38,889
  • 8
  • 95
  • 118
  • 1
    The compiler knows a lot about what your function is doing. It knows all code paths in the function. It uses this semantic knowledge to do analysis like detecting unreachable code, ensuring a variable is initialized before read on all code paths,... – CodesInChaos Jan 06 '12 at 23:07
1

Because compiler will not check for these kind of stuff.

If you install a code analyzer like Resharper in Visual Studio it bring a warning of infinite recursive call or sth like that in case you enabled the code analysis option.

Jahan Zinedine
  • 14,616
  • 5
  • 46
  • 70
1

I doubt the compiler can detect a run-time phenomena (stack overflow) at compile time. There is many valid cases to call a function inside itself, recursion. But how can the compiler know the good from the bad cases of recursion?

Unless it has some added AI to it, I don't think a compiler could detect the differences between good and bad recursion, that's the job of a programmer.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
0

As you have mentioned Compiler just checks syntatical errors. the recursive function isperfectly valid w/o any error.

During Runtime,

when stack is overflown it throws an error because of stack overflow *not because of code*.

Recursive function is perfetly valid, but again in implementation we need to put condition check to return values before stack is filled.

Manas
  • 2,534
  • 20
  • 21