www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Reference to an object disregarding mutation - what's the trick?

reply Steve Teale <steve.teale britseyeview.com> writes:
OK, so I'm in a typical tree situation:

int n = node.parent.nodelist.length;
node.parent.nodelist.length = n+1;
   // p.s. why can't I say node.parent.nodelist.length++ - doesn't work
   // other fluff with node.parent.nodelist
node.parent.nodelist[n] = x;

For brevity I want to be able to say:
Node[] t = node.parent.nodelist;
int n = t.length;
t.length = n+1;
.....

But as soon as I modify t it becomes a separate object.

OK, I can use with, but how do I get the semantics I'd get with a plain old
pointer to the object?
May 28 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Steve,

 OK, so I'm in a typical tree situation:
 
 int n = node.parent.nodelist.length;
 node.parent.nodelist.length = n+1;
 // p.s. why can't I say node.parent.nodelist.length++ - doesn't
 work
 // other fluff with node.parent.nodelist
 node.parent.nodelist[n] = x;
 For brevity I want to be able to say:
 Node[] t = node.parent.nodelist;
 int n = t.length;
 t.length = n+1;
 .....
 But as soon as I modify t it becomes a separate object.
 
 OK, I can use with, but how do I get the semantics I'd get with a
 plain old pointer to the object?
 
you may be running into the issue that changing an array length can cause it to reallocate. I'd have to see more implementation to give you more useful information.
May 28 2007
parent reply Steve Teale <steve.teale britseyeview.com> writes:
BCS Wrote:

 Reply to Steve,
 
 OK, so I'm in a typical tree situation:
 
 int n = node.parent.nodelist.length;
 node.parent.nodelist.length = n+1;
 // p.s. why can't I say node.parent.nodelist.length++ - doesn't
 work
 // other fluff with node.parent.nodelist
 node.parent.nodelist[n] = x;
 For brevity I want to be able to say:
 Node[] t = node.parent.nodelist;
 int n = t.length;
 t.length = n+1;
 .....
 But as soon as I modify t it becomes a separate object.
 
 OK, I can use with, but how do I get the semantics I'd get with a
 plain old pointer to the object?
 
you may be running into the issue that changing an array length can cause it to reallocate. I'd have to see more implementation to give you more useful information.
OK, here's the full story. // This is the original, and works Node node = findnode(a); // sets findex to found node if (node == null) return false; Node newnode = clone_node(node); int n = node.parent.nodelist.length; node.parent.nodelist.length = n+1; if (findex == n-1 || findex == -1) { node.parent.nodelist[n] = newnode; } else { for (int i = n; i > findex; i--) node.parent.nodelist[i] = node.parent.nodelist[i-1]; node.parent.nodelist[findex] = newnode; } // But its a pain to type and read. What I wanted to do was // simplify it. My choices appear to be: // This works Node* pnl = &node.parent.nodelist[0]; if (findex == n-1 || findex == -1) { pnl[n] = newnode; } else { for (int i = n; i > findex; i--) pnl[i] = pnl[i-1]; pnl[findex] = newnode; } OR // This works with (node.parent) { int n = nodelist.length; nodelist.length = n+1; if (findex == n-1 || findex == -1) { nodelist[n] = newnode; } else { for (int i = n; i > findex; i--) nodelist[i] = nodelist[i-1]; nodelist[findex] = newnode; } } OR // This won't compile - it compiles with in, out, and lazy void insertNode(ref Node[] nl, Node nn) { int n = nl.length; nl.length = n+1; if (findex == n-1 || findex == -1) { nl[n] = newnode; } else { for (int i = n; i > findex; i--) nl[i] = nl[i-1]; nl[findex] = newnode; } } insertNode(node.parent.nodelist, newnode); OR // Aliasing would be nice, but does not work in this context alias node.parent.nodelist pnl; int n = pnl.length; pnl.length = n+1; if (this.findex == n-1) { pnl[n] = newnode; } else { for (int i = n; i > findex; i--) pnl[i] = pnl[i-1]; pnl[findex] = newnode; } The version with the Node* is the tightest, but I don't reaaly find any of the approaches satisfying.
May 29 2007
next sibling parent Regan Heath <regan netmail.co.nz> writes:
You can replace your for loop with a memmove call, heres some code to chew on:

import std.stdio, std.random;

extern(C) void *memmove(void *,void *,size_t);

struct Node { int x; }

Node[] nodeList;

static this()
{
	nodeList.length = 10;
	foreach(i, ref n; nodeList) n.x = i*2;
	printNodes(nodeList);
}

uint findNode(Node[] nodeList, ref Node nn)
{
	foreach(i, n; nodeList) { if (n.x > nn.x) return i; }	
	return nodeList.length;
}

void insertNode(ref Node[] nodeList, ref Node nn)
{
	int i = findNode(nodeList,nn);
	
	nodeList.length = nodeList.length + 1;
	if (i < nodeList.length-1) {
		memmove(&nodeList[i+1], &nodeList[i], 
			Node.sizeof * (nodeList.length-i-1));
	}
	nodeList[i] = nn;
}

void printNodes(Node[] nodeList)
{
	foreach(i, n; nodeList) {
		writef(n.x,(i<nodeList.length-1)? "," : "\n");
	}
}

void randomNode(ref Node[] nodeList)
{
	Node nn;
	nn.x = rand()%20;
	writefln("ADD:",nn.x);
	insertNode(nodeList,nn);
}

void main()
{
	randomNode(nodeList);
	randomNode(nodeList);
	randomNode(nodeList);
	randomNode(nodeList);
	printNodes(nodeList);
}

Regan Heath
May 29 2007
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Steve Teale wrote

 OK, here's the full story.
What clumsy data structure might be organized by that? That seems to be arr= arr[ 0 .. findex] ~ newnode ~ arr[ findex .. arr.length]; and nothing more. -manfred
May 29 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to Manfred,

 Steve Teale wrote
 
 OK, here's the full story.
 
What clumsy data structure might be organized by that? That seems to be arr= arr[ 0 .. findex] ~ newnode ~ arr[ findex .. arr.length]; and nothing more. -manfred
yes that is what it seems to be, however, it skips the guarantied reallocation of the cat version
May 29 2007
prev sibling parent Steve Teale <steve.teale britseyeview.com> writes:
Manfred Nowak Wrote:

 Steve Teale wrote
 
 OK, here's the full story.
What clumsy data structure might be organized by that? That seems to be arr= arr[ 0 .. findex] ~ newnode ~ arr[ findex .. arr.length]; and nothing more. -manfred
Fair comment - I'm clearly still thinking somewhere back in C!
May 30 2007
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Steve Teale wrote

 how do I get the semantics I'd get with a plain old pointer to the
 object? 
You cannot use?: Node[]* t = &node.parent.nodelist; -manfred
May 28 2007
parent Regan Heath <regan netmail.co.nz> writes:
Manfred Nowak Wrote:
 Steve Teale wrote
 
 how do I get the semantics I'd get with a plain old pointer to the
 object? 
You cannot use?: Node[]* t = &node.parent.nodelist;
Manfreds rather brief reply is exactly what I was going to suggest. The nice thing about D is that a struct, class, pointer, reference, pointer to pointer or reference, pointer to pointer to .. you get the idea; all get de-referenced by the '.' operator, there is no silly '->' operator for pointers. So, by taking a pointer to the reference you should be able to modify the reference via the pointer by saying: int n = t.length; t.length = n+1; or t.length = t.length+1; Regan Heath
May 28 2007
prev sibling next sibling parent Mike Parker <aldacron71 yahoo.com> writes:
Steve Teale wrote:
 
 For brevity I want to be able to say:
 Node[] t = node.parent.nodelist;
 int n = t.length;
 t.length = n+1;
 .....
 
 But as soon as I modify t it becomes a separate object.
No, it doesn't become a separate object when you modify it, it does so when you declare it. Arrays are objects that consist of a length field and a data pointer. Consider this line: Node[] t = node.parent.nodelist; What happens here is that t is, internally, a new array object which has the same length as and points to the same data as node.parent.nodelist. So when you modify t's length, you are modifying the new object and not the original.
 OK, I can use with, but how do I get the semantics I'd get with a plain old
pointer to the object?
Your choices are to either use with as you mention or, as Manfred suggested, use a pointer to the original array object.
May 28 2007
prev sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Your other problem's been addressed, but I just wanted to comment on

Steve Teale wrote:
 OK, so I'm in a typical tree situation:
 
 int n = node.parent.nodelist.length;
 node.parent.nodelist.length = n+1;
    // p.s. why can't I say node.parent.nodelist.length++ - doesn't work
This is probably one of big warts with properties in D. An array's ".length" isn't just a data field. Because assigning to it can cause other things to happen (like a reallocation), it's a property. And because of the way properties are implemented in D, they cannot act as lvalues. Short version: You can't ++, --, op= a property, or pass it by reference. If you're still wondering what the difference is: struct LengthIsAField { size_t length; } struct LengthIsAProperty { size_t length() { ... } size_t length(size_t value) { ... } } Both are accessed using "instance.length", but the latter can't be used as an lvalue. Hope that helps :) -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 28 2007