[OT] Generative C++

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Fri Jul 28 10:18:35 PDT 2017


On Fri, Jul 28, 2017 at 07:49:02AM +0000, Yuxuan Shui via Digitalmars-d wrote:
> Someone made an interesting proposal to C++:
> https://herbsutter.files.wordpress.com/2017/07/p0707r1.pdf
> 
> Thoughts?

This is very interesting, both as a subject in and of itself, and also
in terms of the enthusiastic response it's receiving.

It goes along the same lines of thought I've had for a while now,
starting from Andrei's observations way back when in TDPL, that
programmers tend to dislike special cases and "magical" behaviour, i.e.,
special behaviour enjoyed by native types that cannot be emulated by
user-defined types.  IOW, we programmers want to be able to "get under
the hood" when we need to, and not be locked out by the black box of the
language implementation. Black boxes are nice and good when they work,
but as we're beginning to realize, no black box is completely
satisfactory all the time -- there will always be times when you need to
get under the hood.  And it's very frustrating when you're not allowed
to, even when it's clear that a tiny tweak to the way things are done
would greatly improve your code.

At a deeper level, what we're fundamentally looking for is symmetry --
and I mean that in the mathematical sense of "unchanged under some
operation X" (or some set of such operations).  In this particular case,
we're looking for symmetry between the language implementation --
default behaviour of built-in types -- and user power -- the ability to
change this default behaviour, as exemplified by Meyer's diagram where
you're given the ability to modify how the compiler transforms to the
source code to the "effective" source code.

This can also be viewed as symmetry between built-in types and
user-defined types: it should be possible to write a user-defined type
that behaves as though it were a built-in type (the symmetry operation
here is commuting baked-in behaviour with user-defined behaviour, or one
may say, symmetry between the ability of the language authors and the
language users: if the language authors can make the language behave a
certain way, the user ought to be able to do the same).

Another instance of symmetry can be found in the principles Meyer set
forth at the beginning of his paper: no special syntax should be
required for metaclasses; you should be able to employ normal class
definition syntax.  IOW, syntax should be symmetric under the operation
that exchanges "metaclass definition" with "normal class definition".

An example of *asymmetry* is in C++ template syntax, where the foreign
<> syntax is asymmetric w.r.t. non-template syntax (esp. because it
clashes with normal uses of the symbols '<' and '>'), and as a result
causes readability issues and parsing difficulties.  D template syntax
is closer to "normal" syntax, and the higher degree of symmetry makes it
easier to use, easier to parse, and have less pathological corner cases.

Metaclasses are only the first step, however.

If we were to take symmetry between baked-in behaviour with user-defined
behaviour to the logical conclusion, we would have a language where, at
least in theory, *every* language behaviour can be specified in the
language itself. I.e., in some sense, the language becomes its own
meta-language.

Or, to put that in more concrete terms, the language is formed of two
parts: a standardized IR (that forms part of the language spec), and a
set of default, higher-level abstractions that the user usually employs
as-is, but with the ability to specify new behaviour in terms of the IR
and have it available at the higher-level of abstraction.  You could
think of the IR as the "core" language that higher-level constructs are
lowered to (D already does some of this, to a small extent).  You'd
usually use the higher-level constructs, but the IR is directly
available to the user, and is standardized so that it works with every
language implementation.

Coming back to the topic of metaclasses, the IR would let you specify
things like the default access permissions of a class, the default
methods, and so on.  The high-level default simply specifies "private"
as the default access permission, and implicit ctors, copy ctors, etc.,
as the default methods.  But since the IR is directly available to the
user, he can easily define his own kind of types, maybe call them
publicSerializableClass's, where the default permission is "public" and
the default methods include a serialize() method.

But having a standardized IR that's available at the language level
gives you much, much, more possibilities than merely metaclasses.  You
would be able to define foreach loops for ranges without baked-in
compiler support, for example. And foreach loops for other kinds of
aggregates, and you wouldn't even need opApply.


T

-- 
Life is complex. It consists of real and imaginary parts. -- YHL


More information about the Digitalmars-d mailing list