Calls to struct methods and immutable

2012-11-15 Thread Joseph Rushton Wakeling

The following code refuses to compile:

///
import std.math;

struct Foo
{
  int a;
  int b;

  this(int a, int b)
  {
this.a = a;
this.b = b;
  }

  void check()
  {
real c = (a ^^ 2 + b ^^ 2) ^^ 0.5;
assert(c < 10);
  }
}


void main()
{
  auto foo = cast(immutable) Foo(3, 4);
  foo.check();
}
///

... producing an error message: immustruct.d(25): Error: function 
immustruct.Foo.check () is not callable using argument types () immutable


The reason seems pretty evident -- making the instance immutable means that the 
temporary internal variable c in check() can't be (over)written.  At the same 
time, this feels a bit daft -- you're talking about a transient value that is 
never seen outside the function scope.


Is there any way of getting round this constraint so such temporary, transient 
variables are still permitted within methods of an immutable instance?


As a workaround, if I write a function external to Foo, e.g.

void check2(Foo foo)
{
  real c = (foo.a ^^ 2 + foo.b ^^ 2) ^^ 0.5;
  assert(c < 10);
}

... then calling foo.check2() runs without problem.  I'm just curious as to 
whether it can be done within a struct method too.


Re: Calls to struct methods and immutable

2012-11-15 Thread Dan
On Thursday, 15 November 2012 at 13:54:10 UTC, Joseph Rushton 
Wakeling wrote:


Make 'void check()' be 'void check() const'
Thanks
Dan

The following code refuses to compile:

///
import std.math;

struct Foo
{
  int a;
  int b;

  this(int a, int b)
  {
this.a = a;
this.b = b;
  }

  void check()
  {
real c = (a ^^ 2 + b ^^ 2) ^^ 0.5;
assert(c < 10);
  }
}


void main()
{
  auto foo = cast(immutable) Foo(3, 4);
  foo.check();
}
///

... producing an error message: immustruct.d(25): Error: 
function immustruct.Foo.check () is not callable using argument 
types () immutable


The reason seems pretty evident -- making the instance 
immutable means that the temporary internal variable c in 
check() can't be (over)written.  At the same time, this feels a 
bit daft -- you're talking about a transient value that is 
never seen outside the function scope.


Is there any way of getting round this constraint so such 
temporary, transient variables are still permitted within 
methods of an immutable instance?


As a workaround, if I write a function external to Foo, e.g.

void check2(Foo foo)
{
  real c = (foo.a ^^ 2 + foo.b ^^ 2) ^^ 0.5;
  assert(c < 10);
}

... then calling foo.check2() runs without problem.  I'm just 
curious as to whether it can be done within a struct method too.





Re: Calls to struct methods and immutable

2012-11-15 Thread bearophile

Joseph Rushton Wakeling:


  auto foo = cast(immutable) Foo(3, 4);


Strive to write D code as much cast-free as possible, because
they are dangerous.


The reason seems pretty evident -- making the instance 
immutable means that the temporary internal variable c in 
check() can't be (over)written.


You are wrong. A version of your code:


import std.math;

struct Foo {
 int a, b;

/*
 this(int a, int b) {
 this.a = a;
 this.b = b;
 }
*/

 void check() const pure nothrow {
 immutable real p = a ^^ 2 + b ^^ 2;
 assert(sqrt(p) < 10);
 }
}

void main() {
 auto foo = immutable(Foo)(3, 4);
 // immutable foo = Foo(3, 4); // simpler alternative
 foo.check();
}


Bye,
bearophile


Re: Calls to struct methods and immutable

2012-11-15 Thread bearophile

/*
 this(int a, int b) {
 this.a = a;
 this.b = b;
 }
*/

 void check() const pure nothrow {
 immutable real p = a ^^ 2 + b ^^ 2;
 assert(sqrt(p) < 10);
 }
}


If you keep the constructor, then it's probably better to replace 
check() with an invariant().


Bye,
bearophile


Re: Calls to struct methods and immutable

2012-11-15 Thread Joseph Rushton Wakeling

On 11/15/2012 03:06 PM, bearophile wrote:

  void check() const pure nothrow {
  immutable real p = a ^^ 2 + b ^^ 2;
  assert(sqrt(p) < 10);
  }


Is it appropriate to have 'nothrow' given that the assert could fail?


Strive to write D code as much cast-free as possible, because
they are dangerous.


The practical situation I'm dealing with is that the a struct gets built inside 
a function, based on data read from files.  Once the data has been written to 
the struct, it should never be changed again.


i.e.

struct Foo
{
 // contains a few different arrays of data
 void add( /* adds new data points to collection */) { ... }
}

auto makeFoo()
{
Foo foo;
foreach( /* lots of data */ )
foo.add( /* new data point */ );
return foo;
}

So, in practice, it seems like that function should cast it to immutable as it 
returns -- and this would be safe, no?


By the way, I should add -- I recognize I'm deluging the list with a bunch of 
questions in these last days, and I'm very grateful for the amount of advice you 
and others have been giving.  I hope it's not becoming too overwhelming or annoying!


Re: Calls to struct methods and immutable

2012-11-15 Thread bearophile

Joseph Rushton Wakeling:

Is it appropriate to have 'nothrow' given that the assert could 
fail?


Failing asserts produce errors, not exceptions. "nothrow" only 
deals with exceptions. And thankfully in this case your D code 
doesn't need to be "appropriate", because D refuses nothrow if 
the function is able to throw.



So, in practice, it seems like that function should cast it to 
immutable as it returns -- and this would be safe, no?


Try to avoid casts as much as possible in D, they are a great 
source for bugs. Take a look at assumeUnique, or better make  
your makeFoo pure so its output is assignable to immutable.



By the way, I should add -- I recognize I'm deluging the list 
with a bunch of questions in these last days, and I'm very 
grateful for the amount of advice you and others have been 
giving.  I hope it's not becoming too overwhelming or annoying!


For me it's not a problem: when I don't have time to answer I 
don't answer :-)


Bye,
bearophile


Re: Calls to struct methods and immutable

2012-11-15 Thread Joseph Rushton Wakeling

On 11/15/2012 03:36 PM, bearophile wrote:

Try to avoid casts as much as possible in D, they are a great source for bugs.
Take a look at assumeUnique, or better make your makeFoo pure so its output is
assignable to immutable.


Thanks for the pointer to assumeUnique -- it will be useful, although AFAICS it 
applies only to arrays, not to structs or other entities, no?


Alas, pure isn't an option, because the makeFoo involves some random procedures 
:-(


Re: Calls to struct methods and immutable

2012-11-15 Thread bearophile

Joseph Rushton Wakeling:

Alas, pure isn't an option, because the makeFoo involves some 
random procedures :-(


http://d.puremagic.com/issues/show_bug.cgi?id=5249
:-)

(But I have to remove its assignment to Andrei, I think I did 
that by mistake, I didn't know how such things work).


Bye,
bearophile


Re: Calls to struct methods and immutable

2012-11-15 Thread Ali Çehreli

On 11/15/2012 06:24 AM, Joseph Rushton Wakeling wrote:

> The practical situation I'm dealing with is that the a struct gets built
> inside a function, based on data read from files. Once the data has been
> written to the struct, it should never be changed again.

If you don't want the callers be able to change, then return 
immutable(Foo). Otherwise, if the caller wants to use the object as 
immutable, then the user should declare immutable:


a) Don't allow users to modify:

immutable(Foo) makeFoo()
{
Foo foo;
foreach (i; 0..10)
foo.add( /* new data point */ );
return foo;
}

b) The user wants to play safe:

auto makeFoo()
{
Foo foo;
foreach (i; 0..10)
foo.add( /* new data point */ );
return foo;
}

void main()
{
immutable foo = makeFoo();
}

Both of those compile with dmd 2.060.

> I'm deluging the list with a
> bunch of questions

Please continue to do so. That is what this forum is for. Your questions 
help us all. :)


Ali



Re: Calls to struct methods and immutable

2012-11-15 Thread Joseph Rushton Wakeling

On 11/15/2012 06:40 PM, Ali Çehreli wrote:

b) The user wants to play safe:

auto makeFoo()
{
 Foo foo;
 foreach (i; 0..10)
 foo.add( /* new data point */ );
 return foo;
}

void main()
{
 immutable foo = makeFoo();
}

Both of those compile with dmd 2.060.


Really?  I'm using from-GitHub dmd, and with the above example I get a "cannot 
implicitly convert expression to immutable" error, e.g.:


Error: cannot implicitly convert expression (testSets(nfRaw,0.1L)) of type 
TestData!(ulong,ulong) to immutable(TestData!(ulong,ulong))




Re: Calls to struct methods and immutable

2012-11-15 Thread Ali Çehreli

On 11/15/2012 10:26 AM, Joseph Rushton Wakeling wrote:

On 11/15/2012 06:40 PM, Ali Çehreli wrote:

b) The user wants to play safe:

auto makeFoo()
{
Foo foo;
foreach (i; 0..10)
foo.add( /* new data point */ );
return foo;
}

void main()
{
immutable foo = makeFoo();
}

Both of those compile with dmd 2.060.


Really? I'm using from-GitHub dmd, and with the above example I get a
"cannot implicitly convert expression to immutable" error, e.g.:

Error: cannot implicitly convert expression (testSets(nfRaw,0.1L)) of
type TestData!(ulong,ulong) to immutable(TestData!(ulong,ulong))



The following program compiles without any errors with dmd 2.060:

struct Foo(T0, T1)
{
T0 t0;
T1 t1;
}

auto testSets(T0, T1)(T0 t0, T1 t1)
{
auto foo = Foo!(T0, T1)(t0, t1);
return foo;
}

void main()
{
ulong nfRaw;
immutable foo = testSets(nfRaw,0.1L);
}

So far it makes sense to me: There shouldn't be any problem with making 
a copy of a value type and marking that copy as immutable.


Unless there exists a member that would make this unsafe. Let's add an 
int[] member to Foo:


struct Foo(T0, T1)
{
T0 t0;
T1 t1;
int[] a;
}

auto testSets(T0, T1)(T0 t0, T1 t1, int[] a)
{
auto foo = Foo!(T0, T1)(t0, t1, a);
return foo;
}

void main()
{
ulong nfRaw;
int[] a = [ 42 ];
immutable foo = testSets(nfRaw, 0.1L, a); // <-- compilation error
assert(foo.a[0] == 42);
a[0] = 43;
assert(foo.a[1] == 43);  // <-- if compiled, this would be a bug
}

Do you have a reference type in your struct?

Ali


Re: Calls to struct methods and immutable

2012-11-15 Thread Joseph Rushton Wakeling

On 11/15/2012 07:48 PM, Ali Çehreli wrote:

Do you have a reference type in your struct?


Yes -- there are associative arrays, and some of those contain dynamic arrays.



Re: Calls to struct methods and immutable

2012-11-15 Thread Joseph Rushton Wakeling

On 11/15/2012 07:48 PM, Ali Çehreli wrote:

Do you have a reference type in your struct?


Assuming I do, what can I do to ensure the struct instance is immutable?  Is 
cast(immutable) now the only option?


Re: Calls to struct methods and immutable

2012-11-15 Thread Kenji Hara
On Thursday, 15 November 2012 at 23:40:16 UTC, Joseph Rushton 
Wakeling wrote:

On 11/15/2012 07:48 PM, Ali Çehreli wrote:

Do you have a reference type in your struct?


Assuming I do, what can I do to ensure the struct instance is 
immutable?  Is cast(immutable) now the only option?


This code works with dmd git head (and might work with dmd 2.060).

struct Foo
{
int a, b;
string[string] aa;
}
immutable(Foo) makeFoo() pure
{
Foo foo;
foo.aa["a"] = "hello";
foo.aa["b"] = "world";
return foo;
// compiler allows this implicit casting from Foo to 
immutable(Foo),
// because compiler can guarantee the instance 'foo' doesn't 
have
// mutable indirections to any global data so makeFoo is a 
pure function.

}
void main()
{
immutable ifoo = makeFoo();
}

Kenji Hara


Re: Calls to struct methods and immutable

2012-11-15 Thread Ali Çehreli

On 11/15/2012 07:43 PM, Kenji Hara wrote:

> This code works with dmd git head (and might work with dmd 2.060).

Yes, it works with dmd 2.060 as well.

> immutable(Foo) makeFoo() pure

I would like to repeate an earlier question: Does makeFoo() want that 
the returned object be immutable? If so, the previous signature is required.


However, if makeFoo() does not care, then it would be better if it 
returned a mutable Foo:


Foo makeFoo() pure

In that case the callers could decide whether they wanted to have the 
returned object as mutable or immutable:


immutable ifoo = makeFoo();
auto mfoo = makeFoo();

The above works because makeFoo() is pure.

If makeFoo() were not pure, and in general, Foo may need to provide an 
.idup member function:


import std.conv;
import std.exception;

struct Foo
{
int a, b;
string[string] aa;
int[] slice;

immutable(Foo) idup() pure const @property
{
auto copy = to!(string[string])(aa);
immutable iaa = assumeUnique(copy);
return immutable(Foo)(a, b, iaa, slice.idup);
}
}

void main()
{
auto foo = Foo(42, 43, [ "a" : "hello", "b" : "world" ], [ 42 ]);
immutable ifoo = foo.idup;
}

Ali



Re: Calls to struct methods and immutable

2012-11-16 Thread Joseph Rushton Wakeling

On 11/16/2012 05:51 AM, Ali Çehreli wrote:

However, if makeFoo() does not care, then it would be better if it returned a
mutable Foo:

Foo makeFoo() pure

In that case the callers could decide whether they wanted to have the returned
object as mutable or immutable:

 immutable ifoo = makeFoo();
 auto mfoo = makeFoo();

The above works because makeFoo() is pure.


Unfortunately in general that's a no-go as some of the generation functions 
involve reading from outside files, and some involve random number generation 
(though I'm curious to see the result of bearophile's pure RNG).



If makeFoo() were not pure, and in general, Foo may need to provide an .idup
member function:

import std.conv;
import std.exception;

struct Foo
{
 int a, b;
 string[string] aa;
 int[] slice;

 immutable(Foo) idup() pure const @property
 {
 auto copy = to!(string[string])(aa);
 immutable iaa = assumeUnique(copy);
 return immutable(Foo)(a, b, iaa, slice.idup);
 }
}


I'll have a look into this.  The trouble is that it's not such a simple 
structure: it's actually more like,


struct Data
{
Node[size_t] nodes;
}

struct Node
{
size_t id;
size_t[];
}

... is it possible to just do

auto copy = to!(Node[size_t])(nodes);
immutable inodes = assumeUnique(copy);

or would I have to go further recursively into Node?  (Or, alternatively, will 
assumeUnique pick up on any idup method I define for Node?)


Re: Calls to struct methods and immutable

2012-11-16 Thread Joseph Rushton Wakeling

On 11/16/2012 12:55 PM, Joseph Rushton Wakeling wrote:

The trouble is that it's not such a simple  structure: it's actually more like,


I should add that I'm not trying to be coy about revealing my code; I'm happy to 
do so, but as it's a rather long file I don't want to oblige anyone to have to 
read through it.




Re: Calls to struct methods and immutable

2012-11-27 Thread Joseph Rushton Wakeling

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])(nod

Re: Calls to struct methods and immutable

2012-11-27 Thread Joseph Rushton Wakeling

On 11/27/2012 01:16 PM, Joseph Rushton Wakeling wrote:

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


Actually I'm being overly complicated here as with dynamic arrays I can simply 
do,

immutable(Node) idup() pure const @property
{
  return immutable(Node)(id, links.idup);
}

... so the real issue here seems to be that there's no canonical way (that I can 
find) to idup an _associative_ array.


Re: Calls to struct methods and immutable

2012-11-27 Thread Dan
On Tuesday, 27 November 2012 at 14:05:37 UTC, Joseph Rushton 
Wakeling wrote:

On 11/27/2012 01:16 PM, Joseph Rushton Wakeling wrote:
... so the real issue here seems to be that there's no 
canonical way (that I can find) to idup an _associative_ array.


I'm using a custom gdup that recursively copies fields and 
requires no support from nested structs. If a dup is provided by 
a struct it will be called. No guarantees, but have a look. 
https://github.com/patefacio/d-help/blob/master/d-help/opmix/mix.d


The following runs:

--
import std.stdio;
import std.typecons;
import std.conv;
import std.exception;
import opmix.mix;

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;

  immutable(Network) idup() pure const @property
  {
auto nodeCopy = nodes.gdup;
immutable imnodes = assumeUnique(nodeCopy);
return immutable(Network)(imnodes);
  }

  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();
  }
}

unittest {
  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,2);
  immutable Network net2 = net1.idup;
  writeln(net1);
  writeln(net2);
}



Re: Calls to struct methods and immutable

2012-11-29 Thread Joseph Rushton Wakeling

On 11/27/2012 05:31 PM, Dan wrote:

I'm using a custom gdup that recursively copies fields and requires no support
from nested structs. If a dup is provided by a struct it will be called. No
guarantees, but have a look.
https://github.com/patefacio/d-help/blob/master/d-help/opmix/mix.d


Thanks for that -- I'll look through it carefully.

My one caveat here is that in general I'm reluctant to rely too strongly on 
3rd-party libraries at this stage of D's development.  That's particularly true 
where stuff like this is concerned -- which might well be best placed in the 
standard library itself.  Generic, broadly-applicable .dup and .idup commands 
would seem to be something that should be available in Phobos ...


... anyway, back to the specifics -- even though I could use opmix, I'd still 
really like to understand for myself how to solve the problems described in my 
previous emails -- in particular, how to effectively idup my struct containing 
the Node[uint] associative array _without_ relying on some external library.  My 
feeling is I'll learn more about D this way ... :-)




Re: Calls to struct methods and immutable

2012-11-29 Thread Dan
On Thursday, 29 November 2012 at 16:28:42 UTC, Joseph Rushton 
Wakeling wrote:
My one caveat here is that in general I'm reluctant to rely too 
strongly on 3rd-party libraries at this stage of D's 
development.  That's particularly true where stuff like this is 
concerned -- which might well be best placed in the standard 
library itself.  Generic, broadly-applicable .dup and .idup 
commands would seem to be something that should be available in 
Phobos ...


... anyway, back to the specifics -- even though I could use 
opmix, I'd still really like to understand for myself how to 
solve the problems described in my previous emails -- in 
particular, how to effectively idup my struct containing the 
Node[uint] associative array _without_ relying on some external 
library.  My feeling is I'll learn more about D this way ... :-)


I feel the same way - as I said there are no guarantees, I'm 
using it but it may not cover the majority of cases and it may be 
obviated by whatever solution Walter is cooking up for copy 
construction and copying of const reference types. Doing it 
yourself is the best way to learn. What I really like about D is 
that you can have what seems like a crippling issue (no way to 
copy const objects) and use features like mixin compile time 
recursion to have a potentially nice general solution. I also 
think the dup should be formalized, maybe not as a keyword but a 
strong convention supported by the language, maybe phobos. For 
example, in your code you have already written 2 idup functions. 
The code below works as well with no need to write those custom 
functions. Besides, it should be safer (assuming it works ;-) 
because you can add new fields and have less to update. BTW: if 
you are still working on this be aware you may eventually have 
some (unwanted?) data sharing going on since there are no 
postblits and you have reference types with aliasing.


Some descriptions of the code and its intentions are:

https://github.com/patefacio/d-help/blob/master/doc/canonical.pdf

Thanks
Dan


import std.stdio;
import std.typecons;
import std.conv;
import std.exception;
import opmix.mix;

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

struct Node
{
  uint id;
  Link[] links;

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


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();
  }
}

unittest {
  auto n1 = Node(1);

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

  immutable n2 = cast(immutable)n1.gdup;
  writeln(n2.links);

  Network net1;
  net1.add(1,2);
  immutable Network net2 = cast(immutable)net1.gdup;
  writeln(net1);
  writeln(net2);
}




Re: Calls to struct methods and immutable

2012-11-29 Thread Ali Çehreli

On 11/27/2012 06:05 AM, Joseph Rushton Wakeling wrote:

On 11/27/2012 01:16 PM, Joseph Rushton Wakeling wrote:

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


Actually I'm being overly complicated here as with dynamic arrays I can
simply do,

immutable(Node) idup() pure const @property
{
return immutable(Node)(id, links.idup);
}

... so the real issue here seems to be that there's no canonical way
(that I can find) to idup an _associative_ array.


I've forced it pretty hard: :D

immutable(Network) idup() pure const @property
{
Node[uint] nodesCopy;

foreach (key, node; nodes) {
immutable(Node) nodeCopy = node.idup;
nodesCopy[key] = cast(Node)nodeCopy;
}

immutable imnodes = assumeUnique(nodesCopy);
return immutable(Network)(imnodes);
}

I hope it is safe. :p

Ali


Re: Calls to struct methods and immutable

2012-12-05 Thread Joseph Rushton Wakeling

On 11/30/2012 05:45 AM, Ali Çehreli wrote:

I've forced it pretty hard: :D

 immutable(Network) idup() pure const @property
 {
 Node[uint] nodesCopy;

 foreach (key, node; nodes) {
 immutable(Node) nodeCopy = node.idup;
 nodesCopy[key] = cast(Node)nodeCopy;
 }

 immutable imnodes = assumeUnique(nodesCopy);
 return immutable(Network)(imnodes);
 }

I hope it is safe. :p


You know, now I'm embarrassed, because I really should have come up with this 
myself. :-P


Actually, I think I did, but I was concerned that the returned result wouldn't 
actually be identical to the original, inasmuch as e.g. inserting the nodes one 
by one might cause everything to be in a different order to the original.  So I 
didn't have the confidence to try it out.


Of course, I could always test these things ...

Thanks very much for the suggestion!