Intlib logo TheLanguageMacro



Let's consider macro facility for TheLanguage

There's a common idea that macros are generally evil. We all know that example of

  #define x 5

  int f() {
     int x;
     ...
  }

However, the only 'evilness' of macros seem to be that they are dangerous as their identifiers do not obey all the resting language's scope rules.

From the other hand, there needs to be something for generic programming anyway: if we don't call templates 'macros', they are still just smart macros, nothing else. So, I make a statement: It's all not about complete elimnation of macros, it's about making them smart .

In fact there's one problem I don't know how to solve without smart macros: it is moving virtual functions (and the virtuality as such) off the language, into the library.

Macros are dangerous in C/C++ because the macroprocessor is being run between the lexical and syntactic analyses. If we do it within the syntactic analyses, we can make it better.

Definitely there must be contexts in the language, in which macros are never expanded. A good example is a definition of any local identifier (in any scope) which has the same name as an existing macro.

Now, to achieve the best flexibility we can, I believe we should minimize the count of such contexts. In fact, the case above can be the only case. And now there's a problem of clearly (and simply) marking such things.

The syntax of C/C++ is not good for it. E.g.

  void abc(...

can be as well a new identifier declaration, an older identifier definition, or both ;-) But that's not the worst thing. It is even worser that in a definition like

  int (t1 (*)(int (*)(char))) (*f) [25];

it depends on the meaning of identifiers, where the new (being declared) identifier stands.

What I propose is to drop the C/C++ type/var declarations nightmare (anyways we almost decided there can be no syntactic compatibility with C, only the calling conventions compatibility). In Pascal, the things are far more appropriate: there are several keywords, after which the next lexem is always the identifier being declared:

  var a : integer;
  type t = array[1..5] of char;
  function f(var x:integer, y:real): real;

etc.

Now what I propose, exactly:

1) No keyword can be a macro name (it's just like they cannot be a variable name, nor function name, nor anything else's name)

2) There are several keywords which clearly mark the place where a new identifier is declared, and there is no other way to declare a new identifier: var, const, class, label, function, macro. I believe we don't need procedure, just function. I do believe however that labels must be declared just like any other identifier. Also I believe any type should be referred to as a class, whether it is compound or not. Or, we can call it type, not class, but then live without classes :) Compound can be told from any other thing by presence of curly brackets in the type definition, and I'm sure there must be possibility to derive from int or a pointer just like from any class.

3) Parameters of a macro should be enclosed in angle brackets <>, not parentheses, thus resembling C++ templates; no separate notion of a template is necessary.

4) There must be compile-time-solved ifs and even whiles, as well as macro variables.

5) There must be a possibility for a macro to refer to several words or expressions which follow the macro's name (in which case they are eaten up). May be it can be another way of passing parameters to a macro:

  macro min<x,y> ((x) < (y)) ? (x) : (y) ;
  ...
  min<a,f(b)>
  min a f(b)

I feel this will allow us to implement all the virtuality stuff in a library rather than in the language itself.


InteLibWiki PageList RecentChanges PageHistory