On 11/16/2012 05:51 AM, Ali Çehreli wrote:
If makeFoo() were not pure, and in general, Foo may need to provide an .idup
member function:

I've been trying this out and ran into some problems with the to!()() 
conversion.

Here's a concrete example. Suppose I have a couple of structs which are designed respectively to represent nodes in a network, and a collection of those nodes:

///////////////////////////////////////////////////////////////////////
alias Tuple!(uint, "id") Link;

struct Node
{
      uint id;
      Link[] links;

      void addLink(uint l)
      {
            links ~= Link(l);
      }

      immutable(Node) idup() pure const @property
      {
            auto linkCopy = to!(Link[])(links);
            immutable ilinks = assumeUnique(linkCopy);
            return immutable(Node)(id, ilinks);
      }
}


struct Network
{
      Node[uint] nodes;

      void add(uint i, uint j)
      {
            if((i in nodes) is null)
                  nodes[i] = Node(i);
            if((j in nodes) is null)
                  nodes[j] = Node(j);

            nodes[i].addLink(j);
            nodes[j].addLink(i);
      }

      void print()
      {
            foreach(k; nodes.keys)
            {
                  write("[", k, "]");
                  foreach(l; nodes[k].links)
                        write(" ", l.id);
                  writeln();
            }
            writeln();
      }
}
///////////////////////////////////////////////////////////////////////

Now, the idup() command for Node works just fine:

      auto n1 = Node(1);

      n1.addLink(5);
      n1.addLink(6);
      writeln(n1.links);

      immutable n2 = n1.idup;
      writeln(n2.links);

...  but if I try to introduce a similar function for the Network struct,

      immutable(Network) idup() pure const @property
      {
            auto nodeCopy = to!(Node[uint])(nodes);
            immutable imnodes = assumeUnique(nodeCopy);
            return immutable(Network)(imnodes);
      }

it fails to compile with an error relating to the to!(Node[uint])() conversion:

---------------------------------------------------------------------------------
/opt/dmd/include/d2/std/conv.d(269): Error: template std.conv.toImpl does not match any function template declaration. Candidates are: /opt/dmd/include/d2/std/conv.d(325): std.conv.toImpl(T, S)(S value) if (isImplicitlyConvertible!(S, T) && !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) /opt/dmd/include/d2/std/conv.d(431): std.conv.toImpl(T, S)(ref S s) if (isRawStaticArray!(S)) /opt/dmd/include/d2/std/conv.d(445): std.conv.toImpl(T, S)(S value) if (is(S : Object) && !is(T : Object) && !isSomeString!(T) && hasMember!(S, "to") && is(typeof(S.init.to!(T)()) : T)) /opt/dmd/include/d2/std/conv.d(466): std.conv.toImpl(T, S)(S value) if (is(typeof(S.init.opCast!(T)()) : T) && !(isSomeString!(T) && !is(T == enum) && !isAggregateType!(T))) /opt/dmd/include/d2/std/conv.d(497): std.conv.toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && is(T == struct) && is(typeof(T(value))))
/opt/dmd/include/d2/std/conv.d(269):        ... (16 more, -v to show) ...
/opt/dmd/include/d2/std/conv.d(325): Error: template std.conv.toImpl cannot deduce template function from argument types !(Node)(const(Node)) /opt/dmd/include/d2/std/conv.d(269): Error: template instance toImpl!(Node) errors instantiating template /opt/dmd/include/d2/std/conv.d(1387): Error: template instance std.conv.to!(Node).to!(const(Node)) error instantiating /opt/dmd/include/d2/std/conv.d(269): instantiated from here: toImpl!(Node[uint], const(Node[uint]))
inodes.d(41):        instantiated from here: to!(const(Node[uint]))
/opt/dmd/include/d2/std/conv.d(269): Error: template instance std.conv.toImpl!(Node[uint], const(Node[uint])) error instantiating
inodes.d(41):        instantiated from here: to!(const(Node[uint]))
inodes.d(41): Error: template instance std.conv.to!(Node[uint]).to!(const(Node[uint])) error instantiating
---------------------------------------------------------------------------------

I'm guessing this means I have to define a custom opCast (for Node, I guess) but the documentation on how to do so seems sparse -- can you advise?

Full code example attached.

Thanks & best wishes,

     -- Joe
import std.conv, std.exception, std.stdio, std.typecons;

alias Tuple!(uint, "id") Link;

struct Node
{
	uint id;
	Link[] links;

	void addLink(uint l)
	{
		links ~= Link(l);
	}

	immutable(Node) idup() pure const @property
	{
		auto linkCopy = to!(Link[])(links);
		immutable ilinks = assumeUnique(linkCopy);
		return immutable(Node)(id, ilinks);
	}
}

struct Network
{
	Node[uint] nodes;

	void add(uint i, uint j)
	{
		if((i in nodes) is null)
			nodes[i] = Node(i);
		if((j in nodes) is null)
			nodes[j] = Node(j);

		nodes[i].addLink(j);
		nodes[j].addLink(i);
	}

	// Won't compile
	immutable(Network) idup() pure const @property
	{
		auto nodeCopy = to!(Node[uint])(nodes);
		immutable imnodes = assumeUnique(nodeCopy);
		return immutable(Network)(imnodes);
	}

	void print()
	{
		foreach(k; nodes.keys)
		{
			write("[", k, "]");
			foreach(l; nodes[k].links)
				write(" ", l.id);
			writeln();
		}
		writeln();
	}
}


void main()
{
	auto n1 = Node(1);

	n1.addLink(5);
	n1.addLink(6);
	writeln(n1.links);

	immutable n2 = n1.idup;
	writeln(n2.links);

	Network net1;
	net1.add(1, 7);
	net1.add(1, 8);
	net1.add(2, 9);
	net1.print();
}

Reply via email to