Jump to page: 1 2
Thread overview
Reference to an object disregarding mutation - what's the trick?
May 28, 2007
Steve Teale
May 28, 2007
BCS
May 29, 2007
Steve Teale
May 29, 2007
Regan Heath
May 29, 2007
Manfred Nowak
May 30, 2007
BCS
May 30, 2007
Steve Teale
May 28, 2007
Manfred Nowak
May 28, 2007
Regan Heath
May 29, 2007
Mike Parker
May 29, 2007
Daniel Keep
May 28, 2007
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
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
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
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
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
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
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
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
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
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