Thread overview
problem with alias this and Tuple
Oct 12, 2021
Johann Lermer
Oct 12, 2021
Paul Backus
Oct 12, 2021
Johann Lermer
Oct 12, 2021
Paul Backus
Oct 13, 2021
Mike Parker
October 12, 2021

Hi all,

I have a problem with Tuples and struct templates that contain an alias this:

import std;

struct Element(T)
{
	T payload;
	alias payload this;

	this (T p)
	{
		payload = p;
	}
}

class Item {}

void main ()
{
	auto e = Element!Item (new Item());
	auto t = tuple(e);
}

dmd generates a warning: Warning: struct Element has method toHash, however it cannot be called with const(Element!(Item)) this.
Element.toHash defined here: /usr/local/include/d/druntime/import/object.d(83)

The culprit seems to be the 'alias payload this'. When I remove that line, the code works. However, in my code, I need that alias. Any ideas, what's wrong or what I could do? Thanks.

October 12, 2021

On Tuesday, 12 October 2021 at 09:30:57 UTC, Johann Lermer wrote:

>

Hi all,

I have a problem with Tuples and struct templates that contain an alias this:

import std;

struct Element(T)
{
	T payload;
	alias payload this;

	this (T p)
	{
		payload = p;
	}
}

class Item {}

void main ()
{
	auto e = Element!Item (new Item());
	auto t = tuple(e);
}

dmd generates a warning: Warning: struct Element has method toHash, however it cannot be called with const(Element!(Item)) this.
Element.toHash defined here: /usr/local/include/d/druntime/import/object.d(83)

The culprit seems to be the 'alias payload this'. When I remove that line, the code works. However, in my code, I need that alias. Any ideas, what's wrong or what I could do? Thanks.

All classes in D inherit from Object, and Object has a toHash method. So what's happening here is (1) your Item class is inheriting toHash from Object, and (2) your Element struct is "inheriting" toHash from Item via alias this. This is why the compiler says, "struct Element has method toHash".

For historical reasons, Object.toHash is not a const method, which means it cannot be called on a const(Object). So if you had a const(Element!Item) and you tried to call .toHash on it, the compiler would rewrite the call to .payload.toHash using alias this, and then it would fail to compile, because payload would be a const(Item) (a subclass of const(Object)). This is why the compiler says, "however, it cannot be called with const(Element!(Item))".

The simplest fix is to define a toHash method for Element using the built-in hashOf function:

size_t toHash() const
{
    return hashOf(payload);
}
October 12, 2021

Thanks, understood. But isn't this a deficiency in the library that should be fixed?

October 12, 2021

On Tuesday, 12 October 2021 at 15:55:40 UTC, Johann Lermer wrote:

>

Thanks, understood. But isn't this a deficiency in the library that should be fixed?

You mean the part about how Object.toHash doesn't work with const? Yes, it is a deficiency in the library. The problem is, it cannot be fixed without breaking backwards compatibility.

October 13, 2021

On Tuesday, 12 October 2021 at 15:55:40 UTC, Johann Lermer wrote:

>

Thanks, understood. But isn't this a deficiency in the library that should be fixed?

The problem extends to more than just toHash. Take a look at this DConf 2019 presentation by Eduard Staniloiu on ProtoObject (as proposed by Andrei Alexandrescu):

https://youtu.be/EcG5mnOzZ0s

Eduard is now mentoring a Symmetry Autumn of Code participant (Robert Aron) whose project is implementing ProtoObject. You can get a summary of the project from Robert's first weekly update thread here:

https://forum.dlang.org/post/wezzcgwbnaguawzfhtpw@forum.dlang.org