Thoughts about "Compile-time types" talk

H. S. Teoh hsteoh at quickfur.ath.cx
Fri May 10 00:33:04 UTC 2019


Skimmed over Luís Marques' slides on "compile-time types", and felt
compelled to say the following in response:  I think we're still
approaching things from the wrong level of abstraction.  This whole
divide between compile-time and runtime is IMO an artificial one, and
one that we must transcend in order to break new ground.

I haven't fully thought through this yet, but the basic concept is that
there should be *no need* to distinguish between compile-time and
runtime in the general case, barring a small number of situations where
a decision has to be made.  Ideally, a function should have just a
single parameter list -- which Luís has already hit upon -- but I'd go
even further and propose that there should be NO distinction made
between runtime and compile-time parameters, at least at the declaration
level.  It should be the *caller* that decides whether an argument is
compile-time or runtime. And that decision in the caller does not have
to be made within the caller itself, but could be dictated by *its*
caller, and so on. As far as *most* code is concerned, you're just
passing arguments from one function to another -- whether it's CT or RT
is immaterial. Only at the very top level do you need to make a decision
whether something is compile-time or runtime.

The result should be that you can make a single top-level change and a
whole cascade of function arguments down the call chain become
instantiated at compile-time, or resp. runtime.  Most of the code in
between *does not have to change* at all; the compiler *infers* whether
something is available at CT or has to be deferred to RT, based on the
caller's arguments.  Some things, of course, like alias parameters and
what-not will force CT (though in theory one could implement RT
counterparts for them), but that should be *transparent* to the
surrounding code.

Just like in OO, changing a class's implementation ought not to require
changing every piece of code that uses the class (encapsulation and
Liskov substitution principle), so the distinction between CT and RT
should be transparent to *most* code.  Only code that actually cares
about the difference should need to choose between one or the other.
The rest of the code should remain agnostic, and thus remain symmetric
under any decision to switch between RT/CT.

For example, we could have first class types in the language: a function
can take a type argument and do stuff to it, and depending on whether
this type is known at CT, the compiler could resolve it at compile-time
or implement it at runtime using the equivalent of typeid() -- and the
function *doesn't have to care which*.  You could sort a list of types,
use range algorithms on them, etc., and if you call it at compile-time,
it will produce a compile-time result; if you call it at runtime, it
will produce a runtime result.  Which one it will be doesn't have to be
a decision that's arbitrarily decided within the function itself; it can
be delegated to higher-level code that has the wider context with which
to make the best decision.

Another example, you could have general matrix multiplication code with
matrix size as a parameter, and at higher-level decide you only need,
say, 4D matrices, so the size can be made a CT argument for one project,
allowing the optimizer to generate the best code for the 4D-specific
case, but an RT argument for another project that wants to operate on
general n*n matrices, without needing to implement matrix multiplication
twice. The latter would have the size as an RT parameter, so you trade
off optimization for flexibility -- *at the decision of higher-level
code*, rather than arbitrarily tossing a coin or guessing what your
callers might want.


T

-- 
MASM = Mana Ada Sistem, Man!


More information about the Digitalmars-d mailing list