Fix issue 15645 - Tuple.slice() causes memory corruption#3975
Fix issue 15645 - Tuple.slice() causes memory corruption#3975saurabhdas wants to merge 3 commits intodlang:masterfrom saurabhdas:fix_issue_15645
Conversation
This approach fixes the issue without changing the layout of the tuple. Changes that need consideration: 1. Return type of Tuple.slice - 'ref' removed. Does this affect how Tuple.slice() is expected to behave?
|
|
I have no idea how many people would actually care, but this is a breaking change, mostly because: Tuple!(string) foo = tuple("FOO");
writeln(foo._0);
foo.slice!(0, 1)()._0 = "BAR";
writeln(foo._0);The last line prints Aside from that, I see the following trade-offs:
For a clean-sheet design, your way might be a little better. But, I don't think it's worth potentially breaking valid code over. (Mine is not a breaking change, because its runtime behaviour should only differ from the current version in cases where the current version is wrong.) Nevertheless, I recommend that you leave this PR open until we see what independent reviewers have to say. EDIT: I should probably link to my earlier PR here: #3973 |
std/typecons.d
Outdated
| static assert(is(typeof(s) == Tuple!(string, float))); | ||
| assert(s[0] == "abc" && s[1] == 4.5); | ||
|
|
||
| // Phobos issue #15645 |
There was a problem hiding this comment.
This must be moved to a separate unittest block, because the /// at the head of this one indicates that it is an example for the documentation.
Ideally, your test should be in a unittest block outside the Tuple template entirely, because otherwise many redundant instantiations may be generated.
There was a problem hiding this comment.
Thanks @tsbockman
I was not aware. I shall move it into a separate block if there's interest in this approach.
|
Having a import std.stdio, std.typecons;
@safe:
class A {
int x;
this(int x) {
this.x = x; }
override string toString() const {
import std.conv : to;
return x.to!string();
}
}
void main()
{
Tuple!(A) foo = tuple(new A(1));
writeln(foo[0]);
foo.slice!(0, 1)()[0] = new A(2);
writeln(foo[0]);
}The above code works as intended with my PR or the current implementation, but with yours it will generate a compiler error at |
|
Does |
EDIT: |
|
I've updated the PR to make slice() work with As suggested by Marco Leise in http://forum.dlang.org/post/20160205201611.14216605@gmx.de have removed |
Sadly, it's not that simple: class A
{
int x;
}
Tuple!(A) foo;
foo.slice!(0, 1);The above will not compile with your PR. |
|
Thinking about this more, if you want to strip the Otherwise, this could silently change the behaviour of previously working, valid programs in a most frustrating fashion. |
|
I posted a poll on dlang's "General" forum to help us decide which fix to use: http://forum.dlang.org/post/inswmiscuqirkhfqlhtd@forum.dlang.org |
|
Since there seem to be people actually using the |
|
I will be withdrawing this PR - given the difference in the function signature, it should be resubmitted with a new function name. Are there any suggestions for a name? Also some help with the |
Here you go: // The constructor around line 530 must be modified to accept inout parameters
static if (Types.length > 0)
{
this(staticMap!(InOut, Types) values) inout @trusted
{
field[] = values[];
}
private alias InOut(T) = inout(T);
}
// Likewise for slice() :
@property
inout(Tuple!(sliceSpecs!(from, to))) sliceVal(size_t from, size_t to)() inout
if (from <= to && to <= Types.length)
{
return typeof(return)(expand[from .. to]);
}Assuming that my PR is accepted, a little bit of further work will be required to make the two compatible with each other. |
This approach fixes the issue without changing the layout of the tuple.
Changes that need consideration:
Tuple.slice() is expected to behave?