Comment #0 by qs.il.paperinik — 2019-01-25T19:52:58Z
When a class/struct has alias-this and a (different) member is accessed, but accessing fails, e.g. the the member is a function (i.e. a method) with no overload viable with the given argument types, the alias-this member is not being tried.
struct Test1
{
// Note: No arguments
int member() { return 0; }
}
struct Test2
{
Test1 field;
alias field this;
// Note: One argument
int member(int n) { return n; }
}
void main()
{
Test2 test;
static assert(!__traits(compiles, {
int i1 = test.member();
}));
int i2 = test.field.member();
}
Removing member from Test2 makes the static assert fail, i.e. the alias-this access valid.
In this minimal example, it can be helped adding a trivial overload of member to Test2. This is not always viable, e.g. if the alias-this references something that cannot be returned by a function: An AliasSeq.
struct Test(bool hasIndex, Types...)
{
Types fields;
alias fields this;
static if (hasIndex)
{
int[] opIndex()
{
return [ ];
}
}
}
void main()
{
Test!(false, int) testF;
int[] iF = testF[]; // fails: no opIndex (intended)
testF[0] = 1; // ok: equivalent to `testF.fields[0] = 1` by alias this
Test!(true, int) testT;
int[] iT = testT[]; // ok: equivalent to `testT.opIndex()`
testT[0] = 1; // fails: testT.opIndex not callable with one argument.
}
There is no way to have slice obj[] and type-safe access to the fields with obj[index] at the same time.
This can be resolved, too, by letting the compiler not rewrite obj[0] to obj.opIndex(0) if the call does not compile.
Comment #1 by razvan.nitu1305 — 2019-01-28T13:15:06Z
I don't think this issue is valid. Alias this should be viewed as inheritance, so your example should behave exactly as:
class Test1
{
int member() { return 0; }
}
class Test2 : Test1
{
int member(int n) { return n; }
}
void main()
{
Test2 a;
a.member(); // error : function test.Test2.member(int n) is not callable using argument types ()
}
Currently, in dmd if you want to include an overload in the baseclass overload set you have to use alias (alias member = typeof(super).member), then the example compiles. I suggest you use this technique in your code.
I suggest we close this as invalid.
Comment #2 by qs.il.paperinik — 2019-01-30T15:41:03Z
In the case of classes, this works. For structs, it does not.
If not
alias member = field.member;
or
alias member = Test1.member;
in Test2, what kind of alias do you think of? I know none. Both don't work.
And for the second example, this is not even slightly possible. The built-in index operator for alias sequences cannot be rebuilt by means of the language, i.e. opIndex with statically known argument.
The spec [1] is very vague about alias this, when it works etc. Technically, by the spec, alias this to a built-in type field need not work: It only includes structs, classes, and property member function with no parameters. It does not mention alias sequences at all! One could even argue that it is a bug that alias this to an alias sequence even works.
[1]: https://dlang.org/spec/class.html#AliasThis
Comment #3 by robert.schadek — 2024-12-13T19:02:10Z