type variables

Paul Backus snarwin at gmail.com
Sun Aug 2 02:21:30 UTC 2020


On Sunday, 2 August 2020 at 00:19:46 UTC, Bruce Carneal wrote:
> Current dlang type 'variables' are created in a strictly 
> functional style.  IOW, they come from declarative syntax, CTFE 
> constants, and possibly recursive application of templates.

In D, currently, there are a few different ways you can refer to 
a type.

1) By its name.

     int x; // refers to `int` by name

2) By an alias.

     alias T = int;
     T x; // refers to `int` by the alias `T`

3) By a template parameter.

     template foo(T) {
         T x; // refers to any type by the parameter `T`
     }

4) By a typeof expression.

     typeof(42) x; // refers to `int` by the expression 
`typeof(42)`

5) By a __traits expression.

     struct Node {
         int data;
         __traits(parent, data)* next;
         // refers to `Node` by the expression `__traits(parent, 
data)`
     }

6) By a string mixin.

     mixin("int") x; // refers to `int` by the string mixin 
`mixin("int")`

By "type variables", I am going to assume you mean #2 and #3, 
aliases and template parameters, since they both involve giving 
an existing type a new name.

Currently, these "type variables" are immutable, in the sense 
that once a name is given to a type, the same name cannot later 
be given to a new type. For example, you are not allowed to write 
code like this:

     alias T = int;
     T x = 42;
     T = string; // error: can't assign to an alias
     T s = "hello";

In general, this is a good thing--having `T` refer to two 
different types at two different points in the program makes the 
code harder to read (because you have to keep track of which type 
it refers to) and harder to modify (because you have to make sure 
the changes to `T` and its uses remain in the correct order 
relative to one another).

However, in certain specific contexts, the ability to modify an 
alias or a template parameter can be useful. This is where 
proposals like type functions come in: they provide a context in 
which aliases like `T` can be mutated, while still leaving them 
immutable in "normal" D code.

> Pure functional programming is great wrt correctness, it's 
> working today, but it's not-so-great when it comes to 
> readability/maintainability.  For starters, composition is a 
> challenge.  Unwinding recursions in your head is another 
> challenge.  Debugging is another challenge.

The main issue with recursion is not that it is difficult to 
understand or maintain, but that it has poor performance. In 
order to process an argument list of length N using template 
recursion, N separate template instantiations are required. Using 
mutation instead of recursion would reduce the memory required by 
such templates from O(N) to O(1).

This is the primary motivation behind proposals like Stefan 
Koch's type functions and Manu's `...` operator.

> Additionally, any template recursions extend the type names in 
> a very ugly way.  Yes, the extension will give you a unique 
> (unintelligible ginormous) name but that's about it.  Seems 
> that we should be able to get a unique mangle without the 
> garbage, something that a human could read and have a prayer of 
> understanding while the universe is still warm.

As far as I'm aware, the problem with ginormous names had nothing 
to do with template *recursion*. Rather, it resulted from the 
fact that code making heavy use of templates (for example, UFCS 
chains of std.algorithm and std.range functions) generated names 
in which the *same exact* type names were *repeated* many, many 
times.

If you know of an example of excessively large symbol names 
resulting *specifically* from template recursion, I would be 
interested to hear about it.


More information about the Digitalmars-d mailing list