November 15, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rushton Wakeling | 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
|
November 15, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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.
|
November 15, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 11/15/2012 10:48 AM, Ali Çehreli wrote: > assert(foo.a[0] == 42); > a[0] = 43; > assert(foo.a[1] == 43); // <-- if compiled, this would be a bug Of course I meant foo.a[0] on the last line above as well. Ali |
November 15, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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?
|
November 16, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rushton Wakeling | 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
|
November 16, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kenji Hara | 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 |
November 16, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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?) |
November 16, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
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.
|
November 27, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli Attachments: | 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 |
November 27, 2012 Re: Calls to struct methods and immutable | ||||
---|---|---|---|---|
| ||||
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.
|
Copyright © 1999-2021 by the D Language Foundation