uint[3] foo;
alias foo[0] bar;
Error:
test8.d(2): Error: alias test8.bar cannot alias an expression foo[0]
Since foo is a static array and 0 is a compile time constant, there is no reason this shouldn't work. It works with tuples, and static arrays really should offer a superset of tuple functionality because they are implemented the same way as tuples with all the same type.
Comment #1 by manuelk89 — 2010-10-11T12:57:33Z
I second that. You can even do that with some template magic, so it would be nice if the compiler could remove the burden to use such tricks from the developer:
In D1 I do:
template Aliasable(alias arg)
{
alias arg Aliasable;
}
template Aliasable(arg...)
{
static assert(arg.length == 1, "bad usage of Aliasable detected");
alias arg Aliasable;
}
alias Aliasable!("foo") foo;
alias Aliasable!(int) MyInt;
I'm not sure if that handles all cases, and I've found a similar template for D2 in std.typetupl:
/*
* [internal] With the builtin alias declaration, you cannot declare
* aliases of, for example, literal values. You can alias anything
* including literal values via this template.
*/
private
{
// symbols and literal values
template Alias(alias a)
{
static if (__traits(compiles, { alias a x; }))
alias a Alias;
else static if (__traits(compiles, { enum x = a; }))
enum Alias = a;
else
static assert(0, "Cannot alias " ~ a.stringof);
}
// types and tuples
template Alias(a...)
{
alias a Alias;
}
}
unittest
{
enum abc = 1;
static assert(__traits(compiles, { alias Alias!(123) a; }));
static assert(__traits(compiles, { alias Alias!(abc) a; }));
static assert(__traits(compiles, { alias Alias!(int) a; }));
static assert(__traits(compiles, { alias Alias!(1,abc,int) a; }));
}
So this MakeAliasable!(...) template was at least invented twice, which shows there is a need :)
Comment #2 by nick — 2020-06-14T16:54:25Z
> It works with tuples
I was a bit confused how that applied to runtime data until I thought of a type sequence instance:
auto f(T...)(T s)
{
alias a = s[0];
a = 3; // OK, s is an lvalue sequence
return s[0];
}
static assert(f(1) == 3);
This is a bit surprising. So I suppose your example aliasing a compile-time known element of a static array of runtime data could also work. But I noticed aliasing a struct .tupleof doesn't work:
struct S {int i;}
auto f(){
S s;
s.tupleof[0] = 5; // OK, .tupleof appears to be an lvalue sequence
alias seq = s.tupleof; // error
alias a = s.tupleof[0]; // error
alias a = s.i; // OK
a = 4; // Error: need `this` for `i` of type `int`
return s.i;
}
static assert(f(1) == 5);
Comment #3 by nick — 2020-06-14T16:57:13Z
> alias a = s.i; // OK
While this line compiles, even reading `a` triggers the same error:
> Error: need `this` for `i` of type `int`
Comment #4 by b2.temp — 2020-06-14T19:22:13Z
The feature cannot be made using language tricks. What is requested here is really a function, i.e an expression to read or write from an offset. This is simply not supported by AliasDeclaration abd would require to add stuff in AliasDeclaration.
(while simply aliasing a ref getter will give good code gen with LDC2).
Technically the AST node for alias would require to store an additional IntegerExp, do some type check to see if building the IndexExp would work and then replace each use of the aliased symbol by an IndexExp.
When you alias an element of a compile time sequence, the element is solved at compile time and gives a symbol. For the ER, the element is not a symbol, it's an offset + a symbol.
Actually, I think this is feasible but not worth, just use a function. Also it is specified that alias cant give exp. supporting one special case could open the Pandora box...
more funny attempts to make it works with typecons/meta-like stuff:
1. try to turn elements as symbol and to index the new symbol...
---
int[2] sta = [0, 1]; // works for static immutable / enum STC
auto staSeq = aliasSeqOf!sta;
alias sta1 = staSeq[1];
---
2. try to make explicit symbols as member of a union, in parallel of the static array.
---
struct AliasableStaticArray(T)
if (isStaticArray!T)
{
alias E = ElementType!T;
private static string getCodeForElements()
{
string result = "struct {";
static foreach (i; 0 .. T.length)
{
result ~= E.stringof ~ " element" ~ i.to!string ~ "; ";
}
result ~= "} ";
return result;
}
union
{
T array;
mixin(getCodeForElements());
}
alias array this;
}
void main(string[] args)
{
AliasableStaticArray!(int[2]) asa;
alias e00 = asa.element0;
alias e10 = asa.element1;
alias e01 = __traits(getMember, asa, "element0");
alias e11 = __traits(getMember, asa, "element1");
e00 = 42; // error, need this...
e10 = 1337; // error, need this...
e01 = 42; // error, need this...
e11 = 1337; // error, need this...
assert(asa == [42, 1337]);
}
---
verdict: impossible.
Comment #5 by b2.temp — 2020-06-15T07:58:47Z
There's a draft PR for the feature, builtin the compiler
https://github.com/dlang/dmd/pull/11273
you can suggest more tests (or test the feature locally) as the author might be biased toward the fact that this works perfectly ;)
Comment #6 by dlang-bot — 2020-06-16T12:11:53Z
@NilsLankila updated dlang/dmd pull request #11273 "fix issue 3546 - experiment aliasing a symbol with a constant indexer" fixing this issue:
- fix issue 3546 - experiment aliasing a symbol with a constant indexer
An alias allows to reference a variable. When used this variable is then turned into a `VarExp`.
The idea is why not allowing an extra index, as long as the index is for a variable and that it is a compile-time constant ?
https://github.com/dlang/dmd/pull/11273
Comment #7 by robert.schadek — 2024-12-13T17:51:11Z