type variables

Bruce Carneal bcarneal at gmail.com
Sun Aug 2 19:09:23 UTC 2020

On Sunday, 2 August 2020 at 16:38:30 UTC, Paul Backus wrote:
> On Sunday, 2 August 2020 at 04:08:00 UTC, Bruce Carneal wrote:
>> I was thinking more about gaining access to a mutable form 
>> which could be converted to/from concrete types as represented 
>> by the compiler under the hood rather than the current methods 
>> of creating types in the source.  Note that "mixin" reduces to 
>> the others above and the others, of course, reduce to the 
>> compiler's internal form.
>> ...
>> Yes, unrestricted type mutation capability is a non goal. So 
>> today we have a large and growing zoo of forms that we can 
>> utilize to work with types.  A mutable class convertible 
>> to/from whatever the compiler is using "under the hood" might 
>> be a better way.  It might be used to implement the zoo while 
>> limiting further special casing.  Switching metaphors, we'd 
>> have less unsprung weight going forward.
> Correct me if I'm wrong, but it sounds to me like what you have 
> in mind is something like this:
> // type function
> alias Tuple(Ts...)
> {
>     TypeBuilder b;
>     b.kind = Kind.struct;
>     foreach (T; Ts)
>         b.addMember(T, ""); // anonymous member
>     return b.toType;
> }
> That is, we have some mutable representation of a type, which 
> we can manipulate via some compiler-defined API, and once we're 
> done, we convert the result to a "real", immutable type, which 
> can be used in other parts of the program.

Yes.  That was the idea.  As sketched the "mutable" form would 
initially only allow locally verifiable mutations IOW an 
attempted mutation would either error out or leave you with a 
valid type.  After thinking about it a little more, and reading 
about LLVM's woes wrt a more generally mutable type 
representation, I'd say such mutation constraints would be very 
useful if not essential long term.

> I can see how this sort of thing might be useful. Indeed, if 
> you generalize this design from just types to *all* kinds of 
> AST nodes (FunctionBuilder, ExpressionBuilder, etc.), what you 
> end up with is essentially a procedural macro system.
> The problem is that D already has features for performing these 
> kinds of AST manipulations: static if, static foreach, and 
> mixins. From a language-design perspective, adding new features 
> that duplicate the functionality of existing ones is generally 
> not a good idea.
> Rather that attempt to *replace* D's existing metaprogramming 
> features with something entirely new, I think it would be much 
> better to *extend* them with language features that allow us to 
> overcome their current limitations.

I think that the metric to use here is capability/complexity 
going forward.  Legacy "dead weight" is an issue but hopefully 
the new capabilities can help us there, in a big way.

For me, "complexity" equates almost perfectly to readability.  If 
performant code written using a new capability isn't more 
readable, more directly comprehensible, then it's a no-go.  If a 
new capability doesn't admit a performant readable implementation 
it's also a no-go.

>> Factoring out naming from the "anonymous" structural aspects 
>> of types seems like a good way to go.  If people want to match 
>> on type structure for some reason, great.  If they want to 
>> create ginormous names, well, OK.
> I don't understand what structural vs. nominal typing has to do 
> with the rest of your post.

It was just in the context of "if we're introducing this new 
form, what all should it enable?".  There are some times when you 
care which names refer to an underlying "anonymous" type and 
other times when working with the factored form is the focus.

Attributes and linkage directives might also be factored 
explicitly but I think those would better be handled using 
filter/set operations.

Obviously I'm winging it here so I appreciate the feedback.  
Better/cheaper to weed out bad ideas early.

More information about the Digitalmars-d mailing list