a more consistent const syntax

Reiner Pope some at address.com
Tue Aug 7 23:57:48 PDT 2007


Bill Baxter wrote:
> Or maybe just allow alias to use either syntax:
> 
> alias x = 1;
> alias 1 x;
> alias myInt = some_complex_expr_to_compute_a_type!(int);
> alias some_complex_expr_to_compute_a_type!(int) myInt;
> 
> In my opinion it's a lot easier to read the assignment syntax (alias 
> sym=thing) than the current alias syntax (alias thing sym).  Mainly 
> because, as you see above, often the 'thing' is really long, but usually 
> the 'sym' is something very short.  It makes it easier to see the thing 
> you care about in the end which is the sym that comes out of the 
> statement that you'll be using in subsequent code.
> 
> --bb

I think that would be just great. I hate having to write two templates, 
one for values and one for aliases. It's quite un-generic. A good 
example is the identity function that Andrei is keen on. It's a fair bit 
of work to write with templates, so that it works with types, values, 
and expression aliases:

template Identity(T...)
{
     static if (!is(T[0]))
         const Identity = T[0];
     else
         alias T[0] Identity;
}

// testing
static assert(is(Identity!(int) == int));
static assert(Identity!(5) == 5);

int x;
void main()
{
     Identity!(x) = Identity!(5);
     assert(x == 5);
}

This currently works, but I'm not sure why[1], and it is annoying to 
require that. I would like to be able to write

template Identity(T...)
{
     alias T[0] Identity;
}

but that currently doesn't work when T[0] is a value parameter.

This does actually cause problems with writing compile-time util 
templates, like FoldR:

template FoldR(alias Fn, T...)
{
     static if (T.length == 0)
         static assert(false, "Must have starting case for FoldR");
     else static if (T.length == 1)
     {
         static if (is(T[0]))
             alias T[0] FoldR;
         else
             const FoldR = T[0];
     }
     else
     {
       // I have to repeat this ugly recursive instantiation 3 times
       // because I can't keep the result -- do I alias it or use const?
         static if (is(FoldR!(Fn, Fn!(T[0], T[1]).val, T[2..$])))
             alias FoldR!(Fn, Fn!(T[0], T[1]).val, T[2..$]) FoldR;
         else
             const FoldR = FoldR!(Fn, Fn!(T[0], T[1]).val, T[2..$]);
     }
}

So I think having alias work for values as well as types/symbols would 
be great. I'm not so fussed either way about

    alias x = int;

I can see it reads better in some situations, though, and I don't see it 
causing any problems if both were allowed.


    -- Reiner

[1] Here's what's confusing me (I expect it's a bug). In the first code 
snippet I posted, the !is(T[0]) means that types are aliased, which is 
good, but the call to Identity!(x) doesn't use the alias, it uses the 
const Identity = T[0]; part. So what is happening is effectively this:

// in the instantiation of Identity!(x)
const Identity = x;

// in main()
Identity!(x).Identity = 5;

We're reassigning a constant -- how does that work? -- but somehow that 
causes x to change... it's oddly doing the alias itself...



More information about the Digitalmars-d mailing list