What are the downsides to defining a C macro that works like the Python “with” statement?

StackOverflow https://stackoverflow.com/questions/8542320

  •  19-03-2021
  •  | 
  •  

Вопрос

After playing around a bit with C preprocessors, I thought of a way to have something similar to a Pythonian with control structure, defined like this:

#define with(var) for(int i##__LINE__=0;i##__LINE__<1;)for(var;i##__LINE__<1;++i##__LINE__)

Sample usage:

#include <cstdio>
#include "FileClass.hpp"
#include "with.hpp"

int main(){
    with(FileClass file("test.txt")){
        printf("%s\n",file.readlines().c_str());}
    return 0;}

The idea is that a doubly-nested for loop has an outer obfuscated iteration variable which is incremented once in the inner loop to break it. This causes the following code to be executed once with var in its scope.

Are there any downsides to this? If I obfuscate the iteration variable enough, there would be almost no chance of having a name clash, it uses only standard preprocessor features in a way that doesn't seem to have any possibility of backfiring, and it's very easy to understand.

It almost seems too good to be true - is there any reason this isn't used everywhere?

Это было полезно?

Решение

It's similar in spirit to the macros used in the original Bourne shell, which was written in C. They were intended to provide a syntax similar to Algol 68, which apparently was Bourne's preferred language.

A small sample from http://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h :

#define IF    if(
#define THEN  ){
#define ELSE  } else {
#define ELIF  } else if ( 
#define FI    ;}

The result tends to be code that's difficult to read either for C programmers (who have to familiarize themselves with your macros as well as the syntax of C itself), or for Algol 68, or in your case Python programmers.

If I read a C++ program that uses your with() macro, I can't really understand what it's doing without (a) realizing that with() is a macro (macros are conventionally given all-caps names), (b) tracking down the macro definition, and (c) deciphering the rather odd C code that results from expanding the macro. That's assuming I don't fall into the trap of thinking that it's a compiler-specific extension, or that C has a with statement that I didn't know about.

Or, if I happen to understand Python with statements, then I still need to (a) realize that your with() macro is intended to mimic a Python with statement, and (b) trust you to get it right.

Years ago, I thought that this:

#define ever ;;
...

for (ever) { ... }

was very clever. I still do think it's clever; but I no longer think that cleverness is such a good thing.

Другие советы

is there any reason this isn't used everywhere?

Yes, C++ is not Python, and if I understood your code correctly, this does exactly the same:

{
  FileClass file("test.txt");
  printf("%s\n", file.readlines().c_str());
}

So, what are the downsides? Unnatural syntax, usage of the preprocessor for code obfuscation, achieving the same thing as above with much more boilerplate code, and unidiomatic use of C++. Enough?

C++ has the very important concept of value types and scope-based deterministic destruction of stack variables. This leads to very important idioms like SBRM (scope-bound resource management, also called RAII).

It almost seems too good to be true - is there any reason this isn't used everywhere?

Sure, that is a great structure that works well for you, but what about the rest of the people on the team? What about the future you - in six months - that can't remember the cute macro that you wrote?

In short, syntactic gymnastics like this are great exercises at home, but are terrible in a collaborative environment, or even for code that you alone will maintain in the future. Stick to the best practices and your code will be much easier to maintain and understand.

That isn't to say that you shouldn't do this kind of thing at home. Do what you enjoy, keep your brain limber. But don't use your warm-up exercises in production!

Is this really "with"? The big advantage of "with" in Python is that it works with context managers, which take care of automatically closing/releasing/unlocking/unallocating the variable in the "with" statement. In C++, there are standard methods for doing this. For instance, auto_ptr will take care of auto-deleting pointers that were allocated with new. Learn these standard idioms before reinventing them yourself.

The obvious downside to this is that no one will be able to read your spaghetti bastardized-Python-in-C++ code. So good luck maintaining that code.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top