View mode: basic / threaded / horizontal-split · Log in · Help
May 28, 2007
Reference to an object disregarding mutation - what's the trick?
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
Re: Reference to an object disregarding mutation - what's the trick?
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
Re: Reference to an object disregarding mutation - what's the trick?
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
Re: Reference to an object disregarding mutation - what's the trick?
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 29, 2007
Re: Reference to an object disregarding mutation - what's the trick?
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 29, 2007
Re: Reference to an object disregarding mutation - what's the trick?
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 29, 2007
Re: Reference to an object disregarding mutation - what's the trick?
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
Re: Reference to an object disregarding mutation - what's the trick?
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
Re: Reference to an object disregarding mutation - what's the trick?
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 30, 2007
Re: Reference to an object disregarding mutation - what's the trick?
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
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home