Discussion:
Really in need of help with std.container.array.d
"Nordlöw" via Digitalmars-d-learn
2014-10-12 20:17:36 UTC
Permalink
I'm trying to figure out how to add complete support for
constness in std.container.array.Array at

https://github.com/D-Programming-Language/phobos/commit/703305f0bfb1cc22eff3e44e351cc3db3e03f94f#commitcomment-8114056

My current solution (which currently fails) at

https://github.com/nordlow/phobos/commit/5c57cb18c2b9d340a19d19207deca5af0339cf7e#diff-0

tries to solve the problem by making wrapper struct Range a
template that captures the constness of parenting Array. My
current implementation of array.d at

https://github.com/nordlow/phobos/blob/inout-array-range/std/container/array.d#L221

however fails its unittests as

array.d(223,19): Error: variable
std.container.array.Array!int.Array.Range!(inout(Array!int)).Range._outer
only parameters or stack based variables can be inout
array.d(430,5): Error: template instance
std.container.array.Array!int.Array.Range!(inout(Array!int))
error instantiating
array.d(833,5): instantiated from here: Array!int
array.d(862,5): Error: static assert (!true) is false

and I have no clue how to proceed with this. Please help, me and
at least one other D developer is hindered by this.
"Nordlöw" via Digitalmars-d-learn
2014-10-12 20:26:25 UTC
Permalink
On Sunday, 12 October 2014 at 20:17:38 UTC, Nordlöw wrote:
https://github.com/nordlow/phobos/commit/5c57cb18c2b9d340a19d19207deca5af0339cf7e#diff-0
Made some corrections

https://github.com/nordlow/phobos/compare/inout-array-range

but gives a similar error

array.d(223,19): Error: variable
std.container.array.Array!int.Array.Range!(inout(Array!int)).Range._outer
only parameters or stack based variables can be inout
array.d(430,5): Error: template instance
std.container.array.Array!int.Array.Range!(inout(Array!int))
error instantiating
array.d(833,5): instantiated from here: Array!int
array.d(816,5): Error: template instance
std.container.array.Array!int.Array.Range!(Array!int) error
instantiating
array.d(833,5): instantiated from here: Array!int
array.d(862,5): Error: static assert (!true) is false
Robert burner Schadek via Digitalmars-d-learn
2014-10-13 13:46:54 UTC
Permalink
hm, the problems seams to be that "inout Array" is not becoming
"const Array" and friends.

A blunt force solution would be to create a range as
Range!(ReturnType!Array...)(cast(Array!T)this, low, high);
and then do the correct casts in Range.
The ReturnType would be the ReturnType of opIndex of the Range
type and the Array would be stored as plain array without any
qualifier.

other than that I'm not sure how to go about this.
"Nordlöw" via Digitalmars-d-learn
2014-10-14 12:41:21 UTC
Permalink
On Monday, 13 October 2014 at 13:46:56 UTC, Robert burner Schadek
Post by Robert burner Schadek via Digitalmars-d-learn
other than that I'm not sure how to go about this.
I tried replace inout with a C++-style member duplication at

https://github.com/nordlow/phobos/commit/b2a4ca28bf25bf7c6149566d066cbb54118b36b4

Now it instead errors as

Error: mutable method
std.container.array.Array!int.Array.__fieldPostBlit is not
callable using a const object
array.d(252,26): Error:
cast(inout(int))this._outer.opIndex(this._a) is not an lvalue
array.d(258,26): Error:
cast(inout(int))this._outer.opIndex(this._b - 1LU) is not an
lvalue
../../std/algorithm.d(2364,9): Error: cannot modify const
expression result
array.d(276,24): Error: template instance
std.algorithm.move!(const(int)) error instantiating
array.d(439,5): instantiated from here:
Range!(const(Array!int))
array.d(851,5): instantiated from here: Array!int
array.d(294,26): Error:
cast(inout(int))this._outer.opIndex(this._a + i) is not an lvalue
Error: mutable method std.container.array.Array!int.Array.~this
is not callable using a const object
array.d(320,30): Error: None of the overloads of 'opSliceAssign'
are callable using a const object, candidates are:
array.d(507,10):
std.container.array.Array!int.Array.opSliceAssign(int value)
array.d(514,10):
std.container.array.Array!int.Array.opSliceAssign(int value,
ulong i, ulong j)
array.d(326,38): Error: None of the overloads of 'opSliceAssign'
are callable using a const object, candidates are:
array.d(507,10):
std.container.array.Array!int.Array.opSliceAssign(int value)
array.d(514,10):
std.container.array.Array!int.Array.opSliceAssign(int value,
ulong i, ulong j)
array.d(299,32): Error: mutable method
std.container.array.Array!int.Array.Range!(Array!int).Range.this
is not callable using a const object
array.d(309,32): Error: mutable method
std.container.array.Array!int.Array.Range!(Array!int).Range.this
is not callable using a const object
array.d(443,5): Error: template instance
std.container.array.Array!int.Array.Range!(Array!int) error
instantiating
array.d(851,5): instantiated from here: Array!int
../../std/typecons.d(3889,17): Error: template instance
object.destroy!(Payload) error instantiating
array.d(169,26): instantiated from here:
RefCounted!(Payload, cast(RefCountedAutoInitialize)0)
array.d(851,5): instantiated from here: Array!int
array.d(880,5): Error: static assert (!true) is false

Ideas?
"Nordlöw" via Digitalmars-d-learn
2014-10-14 12:51:27 UTC
Permalink
On Monday, 13 October 2014 at 13:46:56 UTC, Robert burner Schadek
Post by Robert burner Schadek via Digitalmars-d-learn
A blunt force solution would be to create a range as
Range!(ReturnType!Array...)(cast(Array!T)this, low, high);
and then do the correct casts in Range.
The ReturnType would be the ReturnType of opIndex of the Range
type and the Array would be stored as plain array without any
Do you mean a mutable array containing references to inout data?
Post by Robert burner Schadek via Digitalmars-d-learn
qualifier.
Could you please give me a code example? I'm not skilled enough
in D to follow this description.
Robert burner Schadek via Digitalmars-d-learn
2014-10-14 16:08:30 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
Could you please give me a code example? I'm not skilled enough
in D to follow this description.
struct Range(T) {
Array!S array;
T opIndex(size_t i) {
return cast(T)array[i];
}
}

struct Array(T) {
Range!(const(T)) opSlice() const {
return Range!(const(T))(cast(Array!T)array, 0, length);
}

Range!(T) opSlice() const {
return Range!(T)(cast(Array!T)array, 0, length);
}
}
"Nordlöw" via Digitalmars-d-learn
2014-10-15 21:15:13 UTC
Permalink
On Tuesday, 14 October 2014 at 16:08:31 UTC, Robert burner
Post by Robert burner Schadek via Digitalmars-d-learn
Post by "Nordlöw" via Digitalmars-d-learn
Could you please give me a code example? I'm not skilled
enough in D to follow this description.
struct Range(T) {
Array!S array;
T opIndex(size_t i) {
return cast(T)array[i];
}
}
struct Array(T) {
Range!(const(T)) opSlice() const {
return Range!(const(T))(cast(Array!T)array, 0, length);
}
Range!(T) opSlice() const {
return Range!(T)(cast(Array!T)array, 0, length);
}
}
I tried that at

https://github.com/nordlow/phobos/commit/9daf235d7091f76cd941e29e3c167d559bf56a94

but that triggers a new interesting suite of errors

Error: mutable method
std.container.array.Array!int.Array.__fieldPostBlit is not
callable using a const object
array.d(252,26): Error:
cast(inout(int))this._outer.opIndex(this._a) is not an lvalue
array.d(258,26): Error:
cast(inout(int))this._outer.opIndex(this._b - 1LU) is not an
lvalue
../../std/algorithm.d(2364,9): Error: cannot modify const
expression result
array.d(276,24): Error: template instance
std.algorithm.move!(const(int)) error instantiating
array.d(444,5): instantiated from here:
Range!(const(Array!int))
array.d(856,5): instantiated from here: Array!int
array.d(299,26): Error: cast(int)this._outer.opIndex(this._a + i)
is not an lvalue
Error: mutable method std.container.array.Array!int.Array.~this
is not callable using a const object
array.d(325,30): Error: None of the overloads of 'opSliceAssign'
are callable using a const object, candidates are:
array.d(512,10):
std.container.array.Array!int.Array.opSliceAssign(int value)
array.d(519,10):
std.container.array.Array!int.Array.opSliceAssign(int value,
ulong i, ulong j)
array.d(331,38): Error: None of the overloads of 'opSliceAssign'
are callable using a const object, candidates are:
array.d(512,10):
std.container.array.Array!int.Array.opSliceAssign(int value)
array.d(519,10):
std.container.array.Array!int.Array.opSliceAssign(int value,
ulong i, ulong j)
array.d(304,32): Error: mutable method
std.container.array.Array!int.Array.Range!(Array!int).Range.this
is not callable using a const object
array.d(314,32): Error: mutable method
std.container.array.Array!int.Array.Range!(Array!int).Range.this
is not callable using a const object
array.d(448,5): Error: template instance
std.container.array.Array!int.Array.Range!(Array!int) error
instantiating
array.d(856,5): instantiated from here: Array!int
../../std/typecons.d(3889,17): Error: template instance
object.destroy!(Payload) error instantiating
array.d(169,26): instantiated from here:
RefCounted!(Payload, cast(RefCountedAutoInitialize)0)
array.d(856,5): instantiated from here: Array!int
array.d(885,5): Error: static assert (!true) is false

Comint exited abnormally with code 1 at Wed Oct 15 23:14:37

I'm stuck. Need help.
Robert burner Schadek via Digitalmars-d-learn
2014-10-16 13:56:16 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
Comint exited abnormally with code 1 at Wed Oct 15 23:14:37
I'm stuck. Need help.
I will give it a try
"Nordlöw" via Digitalmars-d-learn
2014-10-16 16:25:40 UTC
Permalink
On Thursday, 16 October 2014 at 13:56:18 UTC, Robert burner
Post by Robert burner Schadek via Digitalmars-d-learn
Post by "Nordlöw" via Digitalmars-d-learn
I'm stuck. Need help.
I will give it a try
Thank you.
anonymous via Digitalmars-d-learn
2014-10-19 15:21:01 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
https://github.com/nordlow/phobos/commit/9daf235d7091f76cd941e29e3c167d559bf56a94
but that triggers a new interesting suite of errors
Error: mutable method
std.container.array.Array!int.Array.__fieldPostBlit is not
callable using a const object
[...]
Post by "Nordlöw" via Digitalmars-d-learn
Error: mutable method std.container.array.Array!int.Array.~this
is not callable using a const object
[...]
Post by "Nordlöw" via Digitalmars-d-learn
I'm stuck. Need help.
I reduced it to this:
----
struct RefCounted
{
this(this) /* const doesn't help */ {}
~this() /* const doesn't help */ {}
}
struct Array
{
RefCounted _data;
}
void main() {const Array a; const copy = a;} /* works */
struct RangeM {Array a;} /* works */
struct RangeC {const Array a;} /* error */
----

Looks like a compiler bug to me.

And here's a workaround:
----
struct RangeC
{
const Array[1] a_;
@property ref const(Array) a() {return a_[0];}
}
----

Using it in std.container.array:
----
static struct Range(A)
{
private A[1] _outer_;
private @property ref const(A) _outer() const {return
_outer_[0];}
private @property ref A _outer() {return _outer_[0];}
/* ... */
private this(ref A data, size_t a, size_t b)
{
version(none) _outer = data; /* "Error: mutable
method
[...].Array.opAssign is not callable using a
const object" */
else version(none) _outer_[0] = data; /* Errors about
postblit. */
else _outer_ = data; /* works */
/* ... */
}
----

Then you also have to disable any methods/overloads that would
return mutable data when A isn't mutable, e.g.:
----
static if (isMutable!A) @property ref T front() {/* ...
*/}
----

Related: `front` and `back` cannot be inout, because the
constness depends not on Range's constness, but on Array's.
"Nordlöw" via Digitalmars-d-learn
2014-10-19 18:58:48 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
version(none) _outer = data; /* "Error: mutable
method
[...].Array.opAssign is not callable using a
const object" */
What do these comments containing Error messages mean? Doesn't
this code compile?
anonymous via Digitalmars-d-learn
2014-10-19 19:13:32 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
Post by anonymous via Digitalmars-d-learn
version(none) _outer = data; /* "Error: mutable
method
[...].Array.opAssign is not callable using a
const object" */
What do these comments containing Error messages mean? Doesn't
this code compile?
Yes, they don't compile. It's three slightly different versions
of initializing _outer.

The first one, `_outer = data;`, is the original one. It's
understandable that it doesn't work anymore with the workaround
in place.

I don't know why the second one, `_outer_[0] = data;`, doesn't
work. Maybe it triggers the same (or a related) postblit compiler
bug again. It's essentially the same as the third one, `_outer_ =
data;`, which happens to work.
"Nordlöw" via Digitalmars-d-learn
2014-10-19 19:30:39 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
Yes, they don't compile. It's three slightly different versions
of initializing _outer.
The first one, `_outer = data;`, is the original one. It's
understandable that it doesn't work anymore with the workaround
in place.
I don't know why the second one, `_outer_[0] = data;`, doesn't
work. Maybe it triggers the same (or a related) postblit
compiler
bug again. It's essentially the same as the third one, `_outer_ =
data;`, which happens to work.
So there's currently no complete solution to this problem yet,
then?
anonymous via Digitalmars-d-learn
2014-10-19 19:36:46 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
Post by anonymous via Digitalmars-d-learn
Yes, they don't compile. It's three slightly different versions
of initializing _outer.
The first one, `_outer = data;`, is the original one. It's
understandable that it doesn't work anymore with the workaround
in place.
I don't know why the second one, `_outer_[0] = data;`, doesn't
work. Maybe it triggers the same (or a related) postblit
compiler
bug again. It's essentially the same as the third one,
`_outer_ =
data;`, which happens to work.
So there's currently no complete solution to this problem yet,
then?
The last variant works: `_outer_ = data;`.

And that one is enabled in my code, while the other two are
`version(none)`-ed away.
"Nordlöw" via Digitalmars-d-learn
2014-10-19 20:10:32 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
Post by "Nordlöw" via Digitalmars-d-learn
Post by anonymous via Digitalmars-d-learn
Yes, they don't compile. It's three slightly different
versions
of initializing _outer.
The first one, `_outer = data;`, is the original one. It's
understandable that it doesn't work anymore with the
workaround
in place.
I don't know why the second one, `_outer_[0] = data;`, doesn't
work. Maybe it triggers the same (or a related) postblit
compiler
bug again. It's essentially the same as the third one,
`_outer_ =
data;`, which happens to work.
So there's currently no complete solution to this problem yet,
then?
The last variant works: `_outer_ = data;`.
And that one is enabled in my code, while the other two are
`version(none)`-ed away.
Used your ideas here

https://github.com/nordlow/phobos/commit/be6b5f8c4d428a9708a52757a3f31aab6878d379

but unittests now fails as

array.d(234,13): Error: mutable method
std.container.array.Array!int.Array.opAssign is not callable
using a const object
../../std/algorithm.d(2364,9): Error: cannot modify const
expression result
array.d(297,24): Error: template instance
std.algorithm.move!(const(int)) error instantiating
array.d(465,5): instantiated from here:
Range!(const(Array!int))
array.d(877,5): instantiated from here: Array!int
array.d(320,26): Error: cast(int)__dop1738.opIndex(this._a + i)
is not an lvalue
array.d(346,30): Error: None of the overloads of 'opSliceAssign'
are callable using a const object, candidates are:
array.d(533,10):
std.container.array.Array!int.Array.opSliceAssign(int value)
array.d(540,10):
std.container.array.Array!int.Array.opSliceAssign(int value,
ulong i, ulong j)
array.d(352,38): Error: None of the overloads of 'opSliceAssign'
are callable using a const object, candidates are:
array.d(533,10):
std.container.array.Array!int.Array.opSliceAssign(int value)
array.d(540,10):
std.container.array.Array!int.Array.opSliceAssign(int value,
ulong i, ulong j)
array.d(325,32): Error: mutable method
std.container.array.Array!int.Array.Range!(Array!int).Range.this
is not callable using a const object
array.d(335,32): Error: mutable method
std.container.array.Array!int.Array.Range!(Array!int).Range.this
is not callable using a const object
array.d(469,5): Error: template instance
std.container.array.Array!int.Array.Range!(Array!int) error
instantiating
array.d(877,5): instantiated from here: Array!int
../../std/typecons.d(3889,17): Error: template instance
object.destroy!(Payload) error instantiating
array.d(169,26): instantiated from here:
RefCounted!(Payload, cast(RefCountedAutoInitialize)0)
array.d(877,5): instantiated from here: Array!int
array.d(906,5): Error: static assert (!true) is false

Comint exited abnormally with code 1 at Sun Oct 19 22:06:48
anonymous via Digitalmars-d-learn
2014-10-19 20:39:17 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
Used your ideas here
https://github.com/nordlow/phobos/commit/be6b5f8c4d428a9708a52757a3f31aab6878d379
but unittests now fails as
array.d(234,13): Error: mutable method
std.container.array.Array!int.Array.opAssign is not callable
using a const object
You didn't make the change we just discussed.

Change line 234 from `_outer = data;` to `_outer_ = data;`.

You also need to guard much more with `static if (isMutable!A)`:
* everything that returns (non-const) T,
* everything that returns Range!A,
* everything that mutates elements (e.g. opSliceAssign).

And you can't do `return typeof(this)(...);` when the return type
is `Range!(const(A))`, because `typeof(this)` can be
`const(Range!A)` which is not the same. Spell the type out or use
`typeof(result)`.
anonymous via Digitalmars-d-learn
2014-10-19 20:41:18 UTC
Permalink
Spell the type out or use `typeof(result)`.
Should be `typeof(return)`.
"Nordlöw" via Digitalmars-d-learn
2014-10-19 22:19:04 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
Post by "Nordlöw" via Digitalmars-d-learn
array.d(234,13): Error: mutable method
std.container.array.Array!int.Array.opAssign is not callable
using a const object
You didn't make the change we just discussed.
Change line 234 from `_outer = data;` to `_outer_ = data;`.
* everything that returns (non-const) T,
* everything that returns Range!A,
* everything that mutates elements (e.g. opSliceAssign).
And you can't do `return typeof(this)(...);` when the return
type
is `Range!(const(A))`, because `typeof(this)` can be
`const(Range!A)` which is not the same. Spell the type out or
use
`typeof(result)`.
New response at

https://github.com/nordlow/phobos/commit/ce6b9e9ae600b7c28ecddd1e3af7b1516247fb33

now errors as

array.d(927,15): Error: None of the overloads of 'opSlice' are
callable using a const object, candidates are:
array.d(472,25):
std.container.array.Array!int.Array.opSlice()
array.d(495,25):
std.container.array.Array!int.Array.opSlice(ulong i, ulong j)
anonymous via Digitalmars-d-learn
2014-10-20 10:56:42 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
https://github.com/nordlow/phobos/commit/ce6b9e9ae600b7c28ecddd1e3af7b1516247fb33
now errors as
array.d(927,15): Error: None of the overloads of 'opSlice' are
std.container.array.Array!int.Array.opSlice()
std.container.array.Array!int.Array.opSlice(ulong i, ulong j)
The error is because of this (lines 470 through 483):
----
static if (isMutable!T)
{
Range!(Array!T) opSlice()
{
return typeof(return)(this, 0, length);
}
}
else
{
Range!(const(Array!T)) opSlice() const
{
return typeof(return)(this, 0, length);
}
}
----

You're disabling the const version when T is mutable. Consider
const(Array!int): T is int is mutable, so there is no const
opSlice. But the Array itself is const, so the non-const version
can't be used. Do not disable the const versions of the methods.
Only ever disable the non-const ones.

Also, the opSlice we're looking at here is Array's, not
Array.Range's. You don't need to touch Array's methods at all.
Only Array.Range's non-const methods need special treatment,
because you need to catch the special case when the Range is
mutable, but the referenced Array is not.

And it's really `isMutableA!`, not `isMutable!T`. I guess you
went for that because `A` is only defined in Array.Range, not in
Array itself. But T's mutability isn't of interest.

For example, Array.Range.opSlice should look like this:
----
static if (isMutable!A) /* !A, not !T */
{
Range!(A) opSlice() {/* ... */}
Range!(A) opSlice(size_t i, size_t j) {/* ... */}
}
/* No `else`, the const versions should always be
available. */
Range!(const(A)) opSlice() const {/* ... */}
Range!(const(A)) opSlice(size_t i, size_t j) const {/*
... */}
----

Then there are still various methods of Array.Range left to be
`static if(isMutable!A)` guarded:
* move*
* opIndex
* opSlice*

By the way, since we're in D.learn, I'm assuming you want to do
this yourself. But if you'd like, I could make a pull request
with my suggestions to your branch.
"Nordlöw" via Digitalmars-d-learn
2014-10-20 11:20:30 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
By the way, since we're in D.learn, I'm assuming you want to do
this yourself. But if you'd like, I could make a pull request
with my suggestions to your branch.
Yes, please! That would be very kind of you.

/Thx
anonymous via Digitalmars-d-learn
2014-10-20 18:01:10 UTC
Permalink
Post by "Nordlöw" via Digitalmars-d-learn
Post by anonymous via Digitalmars-d-learn
By the way, since we're in D.learn, I'm assuming you want to do
this yourself. But if you'd like, I could make a pull request
with my suggestions to your branch.
Yes, please! That would be very kind of you.
Forgot to mention it here, not sure if you noticed it:
https://github.com/nordlow/phobos/pull/1
"Nordlöw" via Digitalmars-d-learn
2014-10-20 19:22:28 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
https://github.com/nordlow/phobos/pull/1
Superb.
thedeemon via Digitalmars-d-learn
2014-10-21 04:22:35 UTC
Permalink
Speaking of this module, since I cannot currently login to
bugtracker, I'd like to note here that there are two major bugs
in one little function: Array.Payload.length setter. One is this
https://issues.dlang.org/show_bug.cgi?id=13619

and the other is reallocating without notifying GC of the
pointers, which leads to having dangling pointers in the array
after a GC cycle.
thedeemon via Digitalmars-d-learn
2014-10-21 06:13:52 UTC
Permalink
Post by thedeemon via Digitalmars-d-learn
Speaking of this module, since I cannot currently login to
bugtracker, I'd like to note here that there are two major bugs
in one little function: Array.Payload.length setter. One is this
https://issues.dlang.org/show_bug.cgi?id=13619
and the other is reallocating without notifying GC of the
pointers, which leads to having dangling pointers in the array
after a GC cycle.
Submitted the second one here:
https://issues.dlang.org/show_bug.cgi?id=13642

anonymous via Digitalmars-d-learn
2014-10-19 21:06:34 UTC
Permalink
Post by anonymous via Digitalmars-d-learn
----
struct RefCounted
{
this(this) /* const doesn't help */ {}
~this() /* const doesn't help */ {}
}
struct Array
{
RefCounted _data;
}
void main() {const Array a; const copy = a;} /* works */
struct RangeM {Array a;} /* works */
struct RangeC {const Array a;} /* error */
----
Looks like a compiler bug to me.
Has already been filed:
https://issues.dlang.org/show_bug.cgi?id=13629
Continue reading on narkive:
Loading...