www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Wish: Variable Not Used Warning

reply Era Scarecrow <rtcvb32 yahoo.com> writes:
 Hmmh, if I would do something like that, I would do it like
 this:
 
 bool isPrime(int number, int[] /* primesList */)
 {
 	bool prime = true;
 
 	static if(false)
 	{
 		// Partial implementation; should still be
 		// syntactically valid D
 		foreach(pnum; primesList) { ... }
 	}
 	else
 	{
 		for(int cnt = 2; ...) { ... }
 	}
 
 	return prime;
 }

Closer to what i am meaning. Wouldn't it throw an error though that you have foreach(pnum; primesList) where the primesList is commented out? course the smart compiler will probably see it as 'don't compile this code' and treat it as a large comment to the else.
  I'll in the middle of my project, make sure all

  openings/closings are good, and then compile the

  never run but instead i use the errors and warnings

  bugs and simple problems earlier, rather then do an

  then trace all the bugs all at once.

That's exactly the same way I work with the code. I keep adding blocks and continuously compile to see, if there are warnings or errors. If there would be a situation like above, and I would be just added that list scanning part but being still unsure if it works, I would add there an assert or similar to catch the program immediately if it goes there; bool isPrime(int number, int[] primeList) { if(primeList) { assert(false); // Don't go here at the moment foreach(pnum; primeList) { ... } } else { for(int cnt; ...;) if(!(number%cnt)) return false; return true; } }

The a reason i had the 'primesList = null;' it's so the functionality of isPrime() could start to be used and implimented right away, checking for a prime, since primesList is only to be used as a speedup later, the purpose of the code is to check for if the number is a prime. If i wanted to use the isPrime (before i got the other half implimented), i'd have to intentionally pass a null, thereby removing intended purpose of it's existance later, Speed. As the example, i could impliment all my code with primesList with an array that is filled with an appropriate number of primes to give me the result for a prime very fast, but if it isn't implimented, it still works. the way i had it. assert(false); //automatically makes the function fail reguardless. Doing it this way, i can only run it if i pass a null. perhaps 'static if(false){...}' is better in this scenario as you said before. But i also wanted to ensure i had my variable names spelling and connections working right, even if the rest of the code wasn't ready just yet.
 But anyway, if I would starting to make that part, the
 build-stoppable 
 warnings about unused code and similar would not be a big
 issue any more, 
 since I would not be executing the program until I get the
 errors & 
 warnings away.

Agreed. Build code, get it to work quickly and easily. Then refactor out un-needed parts, and remove as many warnings as possible without making it ugly and only to get the compiler to shut up about said warning.
 Static if is something like #if-#endif in C/C++, but since
 it is in the 
 compiler, it knows all about the constants & types in
 the code (unlike C 
 preprocessor) \o/

That's nice to know. I'll start using it where applicable.
 Assume, that (a+b) is always smaller than 8, which causes
 infinite loop. 
 The compiler is able to know that. If the programmer was
 intentionally 
 making an infinite loop, why didn't he use
 "for(;;)" or "while(true)"? If 
 the compiler gives an error, that the expression is always
 true, I think 
 there are two possibilities:
 
 1) The programmer was checking out how smart is the
 compiler, by 
 expressing an infinite loop in a hard way; to get the code
 compiled, he 
 should change it to regular "for(;;)" or
 "while(true)".

I can mostly see that only in instances of those trying to make better checkers by making it fail any way possible, or making sure the error comes up on a later build. Either way, if ;(a+b) < 8; always evaluates to less than 8, and there's no way to get a or b to go up or might change to become something higher (or a break somewhere to get out of the loop); most likely something is missing; unless they have some 'clever code' which, then becomes a pain to debug later.
 2) The programmer didn't notice, that the values he was
 using are never 
 evaluated greater than the intended loop termination
 condition. He re-
 examines the code and probably finds something that he was
 missing in the 
 first attempt (forgot to add some other value, forgot to
 change the loop 
 termination condition, ...)
 
 Win-win -situation, isn't that?

Only if he's actually warned about the infinate loop. would this warn you? (i will check myself later) int a,b; for (;(a+b)<8;) { if (a>=0) a++; if (b<=0) b--; } both a and b change. is it smart enough to know it should ALWAYS be 0? (or -1 for a brief time) or... { //...somewhere in the code. a++; b-=a; a=b; } not sure if the compiler will be quiet about this either, but logically something's changing constantly so we know there's a possible potential for an eventual false statement somewhere.
 Yes, right. Of course, compiler should not give any kind of
 warning if 
 the loop is clearly intentionally made infinite, or if the
 condition is 
 clearly intentionally made constant:
 
 	while(true) ...		// No error
 	if(true) ...		// No error
 
 	auto a=file.getSize("myfile.txt");	// ulong
 	...
 	while( a != -1) ...	// Error
 
 In fact, I would change the default behavior of the
 compiler so that it 
 uses all warnings and regards them as errors. For testing
 out incomplete 
 code, a "--cmon-relax" flag could be used :)

Sounds good to me. It just seems like there's a delicate balance where all warnings are errors, and not all warnings can be delt with without some type of ugly work-around (in some situations), where a warning would be better than an error. I honestly believe that unused variables shouldn't be an error; at least until i've finished building a working version of the function. Then start refactoring and removing un-needed parts. Once ready for release, all warnings that can be removed, are treated as errors. Last thing i personally want to do is to put in variables i know i need, and then have to comment them out just to get the compiler to be quiet because they aren't used, just so i can confirm some basic logic right before working on the block of code that would have held the variables i just commented out. The annoyance of jumping back and forth when i could have just left them alone to begin with is mostly where i'm going towards. production code and final code? Variables that aren't used should be errors.
Jul 10 2008
parent Markus Koskimies <markus reaaliaika.net> writes:
On Thu, 10 Jul 2008 15:05:30 -0700, Era Scarecrow wrote:

 Hmmh, if I would do something like that, I would do it like this:
 
 bool isPrime(int number, int[] /* primesList */) {
 	bool prime = true;
 
 	static if(false)
 	{
 		// Partial implementation; should still be // 


 		foreach(pnum; primesList) { ... }
 	}
 	else
 	{
 		for(int cnt = 2; ...) { ... }
 	}
 
 	return prime;
 }

Closer to what i am meaning. Wouldn't it throw an error though that you have foreach(pnum; primesList) where the primesList is commented out?

The block inside of static if is only syntactically checked. It does not have to have valid references to variables, classes or something like that. Like said, it is just like #if...#endif, with the exception that (1) static if knows all about the code around it (i.e. you can use e.g. sizes of some aliased types in expression) (2) static if allos only syntactically correct blocks inside of it (that block is parsed, but anything else is not made for it)
 course the smart compiler will probably see it as 'don't compile this
 code' and treat it as a large comment to the else.

Smart compiler regocnizes, when the attempt is intentional and when it is more likely spurious. Like side, there is a big differece between making infinite loops like: 1) while(true) { ... } 2) while(-4 < -2) { ... } ..Or outcommenting; 1) if(false) { ...} 2) if(-1 > 0) { ... } (you catched the point? If you didn't, consider that the compiler has evaluated a complex expression to correspond the second examples)
   The a reason i had the 'primesList = null;' it's so the functionality
   of isPrime() could start to be used and implimented right away,
   checking for a prime, since primesList is only to be used as a speedup
   later, the purpose of the code is to check for if the number is a
   prime. 

Yes, I understood that. There's plenty of possibilities to do that even with "full C++-like warnings" (D has only ridiculously small set of that) if warnings are treated as errors.
  assert(false); //automatically makes the function fail reguardless.
 
  Doing it this way, i can only run it if i pass a null.

Yes, true, but if it is not working, why do you want it to go there? That was just an example to enable code, and to guard it not to be executed while testing other parts. [...]
  Agreed. Build code, get it to work quickly and easily. Then refactor
  out un-needed parts, and remove as many warnings as possible without
  making it ugly and only to get the compiler to shut up about said
  warning.

Yes, exactly me!
 Assume, that (a+b) is always smaller than 8, which causes infinite
 loop.
 The compiler is able to know that. If the programmer was intentionally
 making an infinite loop, why didn't he use "for(;;)" or "while(true)"?
 If
 the compiler gives an error, that the expression is always true, I
 think
 there are two possibilities:
 
 1) The programmer was checking out how smart is the compiler, by
 expressing an infinite loop in a hard way; to get the code compiled, he
 should change it to regular "for(;;)" or "while(true)".

I can mostly see that only in instances of those trying to make better checkers by making it fail any way possible, or making sure the error comes up on a later build. Either way, if ;(a+b) < 8; always evaluates to less than 8, and there's no way to get a or b to go up or might change to become something higher (or a break somewhere to get out of the loop); most likely something is missing; unless they have some 'clever code' which, then becomes a pain to debug later.

I completely agree!
 2) The programmer didn't notice, that the values he was using are never
 evaluated greater than the intended loop termination condition. He re-
 examines the code and probably finds something that he was missing in
 the
 first attempt (forgot to add some other value, forgot to change the
 loop
 termination condition, ...)
 
 Win-win -situation, isn't that?

Only if he's actually warned about the infinate loop.

In the case that compiler has produced an infinite loop, by optimizing away unnecassary parts, and it recognizes that the source indicates something else (i.e. not "while(true)"), would it be polite to tell that to the programmer? If the compiler is dumb enough not to optimize expressions like: while(-2 < -1) { ... } ...Then there is of course no need to produce warning (i.e. if the compiler generates code, that loads -2 to one register and -1 one register and really performs cmp between those).
  int a,b;
 
 for (;(a+b)<8;)
 {
     if (a>=0)
         a++;
     if (b<=0)
         b--;
 }
 both a and b change. is it smart enough to know it should ALWAYS be 0?
 (or -1 for a brief time)

Oh my god. It would take me a while to really analyze that kind of code. If that kind of loop would appear when I'm keeping review, I would put the programmer to make some simplifications to the loop... In any case, quickly analyzed, that would easily produce an infinite loop. a is growing all the time it is greater than zero, while b is decreasing all the time it is less zero. Likely outputs would be; 1) a < 0 ==> if b < 0, almost infinite, otherwise if (a+b) >= 8 it would not take a round, 2) a > 0 ==> if b < 0, infinite loop; a and b would compensate each other 3) Many undeterministic behaviors; from 0 to 8 rounds, and if more than 8, would lead to almost infinite
 or...
 
 {
 //...somewhere in the code.
  a++;
  b-=a;
  a=b;
 }

The behaviour would be hugely dependent on the inital values of a and b. Many non-deterministic results, and because of a-=b clause it could lead to infinite loops.
 not sure if the compiler will be quiet about this either, but logically
 something's changing constantly so we know there's a possible potential
 for an eventual false statement somewhere.

Compilers cannot regularly catch the things you presented above. They catch much more simple things, most likely caused because of you forgot something.
  Last thing i personally want to do is to put in variables i know i
  need, and then have to comment them out just to get the compiler to be
  quiet because they aren't used, just so i can confirm some basic logic
  right before working on the block of code that would have held the
  variables i just commented out. The annoyance of jumping back and forth
  when i could have just left them alone to begin with is mostly where
  i'm going towards. production code and final code? Variables that
  aren't used should be errors.

Like said, I have used so much "g++ -Wall" and "lint" by making my salary in private companies (which regularly gives a shit to fancy things, it just need to work and you are forced to do code like being in army; no own will, suggestions may be considered in next year), that I have used to sketch code so that it does not generate warnings. My bad, indeed, although I'm not the biggest fan of completely freedom of making code (i.e. good practices).
Jul 10 2008