[erlang-questions] some language changes

Thu May 31 03:09:02 CEST 2007

On 31 May 2007, at 1:51 am, Mats Cronqvist wrote:
[1. simplify the language]
[2. replace the preprocessor]

>  conditional compilation should (i think) be
> disallowed (rarely used and utterly horrible).

I have been saying "Delenda est preprocessor!" since it came out.
I note, however, that there are 518 "-if[n]def(...)." occurrences
in the R11B sources.

Quite a lot of those are protection against multiple includes:
	%% thingy_whatsit_gubbins.hrl
To my astonishment, some of the files that do this contain nothing else!
The answer is simple:  they are produced by some kind of tool that
emits -record declarations, and for these files there happened to be
none.  Some use a _HRL suffix; some use a -MIB suffix.

This usage accounts for 165 (32%) of the -ifs.  Either of two changes
would eliminate them entirely.

(a) -require(File_Name).
     would resolve the File_Name just like -include(File_Name),
     then check a list of included files.  If the file was in that
     last, -require would do nothing, otherwise it would act just
     like -include.  -include (and thus -require) would add the
     resolved file name to the list.

(b) Allow -define and -record declarations to be repeated, as long as
     the repetitions are identical as token sequences.  (This is what
     C does about #define.  6.10.3 "An identifier currently defined as
     a macro ... shall not be redefined by another ... directive unless
     the second definition is [the same kind, with the same arguments
     if any] and the two replacement lists are identical.)

There's a bunch of
	-define(default_verbosity, silence).
in lib/snmp/src/... , many of which never visibly mention
default_verbosity again.  One wonders why this stuff isn't in
snmp_verbosity.hrl itself.  2.5% of the -ifs have to do with
SNMP verbosity; there has to be a better way to do this.

Another 121 have "debug" in their name.

Then there are at least 122 (24%) which are clearly Hipe-related.
The use of -if to select data structures isn't really necessary.
Instead of

	%define(USE_TUPLES, true).
	-define(USE_GBTREES, true).
	new(N, V) ->
	    erlang:make_tuple(N, V).
	new(N, V) ->
	    gb_trees:from_orddict(mklist(N, V)).

one could write

	Use = gb_trees.  % or tuples.

	new(N, V) when Use =:= tuples ->
	    erlang:make_tuple(N, V);
	new(N, V) when Use =:= gb_trees ->
	    gb_trees:from_orddict(mklist(N, V)).

This plus constant propagation, dead code elimination. and inlining
does the trick.  Just allowing

	<variable> = <constant expression>.

at top level would go a long way towards eliminating -define.
What this replacement cannot do, and what Hipe sometimes does,

(not an actual example).

Wait a bit.  Make that 141 (27%) in Hipe.  All the
occurrences (19 of them) seem to be in there.  This amounts to  
out code which is not currently in use but you're not quite ready to get
rid of.  One problem with this is that code that is not compiled  
tends to
suffer bit rot.  Other aspects of the code around it change so that when
you decide that after all you DO want it back, it tends to have become
unusable.  One could imagine a -moribund directive which would cause
the following declaration to be syntax checked but discarded from the
AST output.

Prolog has a rather nice feature.  When you are reading terms from a
file, the end of the file is indicated by returning the term
'end_of_file'.  So you can cause the compiler to stop early in a file
by explicitly writing
So I tended to put test code and moribund code and big explanatory
comments after an end_of_file, making it trivial to move them back
where the compiler would see them if I wanted it to.  If you want to
allow module definitions in the shell, you are going to want an -end
directive there.  An -end directive is particularly nice for letting
you put lots of commentary and examples and stuff in a file where
people can see it, but where the compiler won't spend ANY time looking,
unlike ordinary comments.

That leaves about 76 (15%) of -ifs unexamined, and it's time I stopped.

[3. Replace type guards by ::constraints on variables in patterns]

Some IBM mainframe Prolog (was it VM Prolog?) did this, using infix
$ rather than infix ::.  I've seen it in another language whose name
I unfortunately forget.  However,

  (a) This proposal makes the language more complicated.
  (b) It makes some code more readable, but it makes other code
      less readable.
  (c) You STILL need type guards when there is a call to element,
      hd, or tl in a guard, e.g.,
	f(N, T) when is_pid(element(N, T)) -> ...
  (d) You STILL need type guards when a guard is disjunctive, e.g.,
	f(X) when is_record(X, update) ; is_record(X, delete) -> ...

The Variable::type feature could be handled by source-to-source
translation; the one case where this wouldn't be trivial is
Pattern = Expression.

More information about the erlang-questions mailing list