Re: Mutable ForwardRange save() method not callable using const object

2018-09-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, September 4, 2018 9:22:26 AM MDT Timoses via Digitalmars-d-learn 
wrote:
> On Tuesday, 4 September 2018 at 14:26:44 UTC, Steven
>
> Schveighoffer wrote:
> > [...]
> > As general advice, I wouldn't expect const to work well with
> > Ranges anyway -- const ranges are useless (you can't iterate
> > them). So not much code is expecting to handle const, including
> > the wrappers that Phobos provides.
>
> Thanks, that sounds like some good advice. I've actually bumped
> into this right after when I had an immutable range which was
> supposed to fill in its cache when being iterated.
> My argument for why this should work is that "from the outside of
> the range" it is immutable, since accessing via opIndex will
> always give the same value.
> ... In the end, that'll lead nowhere. The immutable attribute
> would become a "promise" rather than an enforcement (or too hard
> for the compiler to enforce).

That's simply not how const or immutable work in D though. They're actual
compiler guarantees, and it's undefined behavior to ever cast away const or
immutable and mutate the object. D's const is fundamentally different from
C++'s const in this regard. Not only is a const that doesn't provide
compiler guarantees useless according to Walter (though that's obviously
debatable), but the nature of immutable pretty much requires it. immutable
objects are implicitly shared, and in principle, they could end up in ROM.
So, even if your object is const, there's no guarantee that it's actually
mutable underneath the hood. The rigidness of D's const and immutable are
both a blessing and a curse. But the net result is we really can't have a
range API that works with them without more of a head/tail model (whereas
the current API mutates in place), and even if we had a head/tail model, it
would still get pretty hairy thanks to issues like reference counting.

So, as Steven points out, const and ranges don't go together at all. The
result is that a number of us use stuff like const and inout pretty
sparingly (at least outside of primitive types):

http://jmdavisprog.com/articles/why-const-sucks.html

- Jonathan M Davis





Re: Mutable ForwardRange save() method not callable using const object

2018-09-04 Thread Timoses via Digitalmars-d-learn
On Tuesday, 4 September 2018 at 14:26:44 UTC, Steven 
Schveighoffer wrote:

[...]
As general advice, I wouldn't expect const to work well with 
Ranges anyway -- const ranges are useless (you can't iterate 
them). So not much code is expecting to handle const, including 
the wrappers that Phobos provides.


Thanks, that sounds like some good advice. I've actually bumped 
into this right after when I had an immutable range which was 
supposed to fill in its cache when being iterated.
My argument for why this should work is that "from the outside of 
the range" it is immutable, since accessing via opIndex will 
always give the same value.
... In the end, that'll lead nowhere. The immutable attribute 
would become a "promise" rather than an enforcement (or too hard 
for the compiler to enforce).



Thanks for the clarification, Steve!


Re: Mutable ForwardRange save() method not callable using const object

2018-09-04 Thread Steven Schveighoffer via Digitalmars-d-learn

On 9/4/18 9:53 AM, Timoses wrote:

Hey,

I'm fiddling around with ranges a bit and am wondering why save is not 
callable on a const object:

...
I could imagine that save is not marked as const because it is uncertain 
whether any indirections are part of the content..? But couldn't the 
compiler check that?


But you have eliminated any visibility into the range itself -- you 
stuck it behind an interface.


Could anybody explain what exactly is going on? Is there a reason the 
`save()` is not working on const objects?


The trivial reason is because the method is not marked const:

https://github.com/dlang/phobos/blob/master/std/range/interfaces.d#L153

The real reason is that given a const interface, everything inside it 
must be const as well. Making a copy of that makes a const copy, which 
by definition couldn't be assigned back to the original range (which is 
likely not const).


At the very least, it should be inout. But in either case, the function 
needs to be properly marked.


As general advice, I wouldn't expect const to work well with Ranges 
anyway -- const ranges are useless (you can't iterate them). So not much 
code is expecting to handle const, including the wrappers that Phobos 
provides.


-Steve


Mutable ForwardRange save() method not callable using const object

2018-09-04 Thread Timoses via Digitalmars-d-learn

Hey,

I'm fiddling around with ranges a bit and am wondering why save 
is not callable on a const object:


class Range
{
ForwardRange!(const uint) offsets;

this(const S s)
{
this.offsets = s.s.map!(e => e.i).inputRangeObject;
}

this(const Range a) // ERROR line 22
{
this.offsets = a.offsets.save;
}

Range save()
{
return new Range(this);
}
}
struct I
{
uint i;
}
struct S
{
I[] s = [I(1), I(2), I(3)];
}

unittest
{
S s;
auto a = new Range(s);
}

onlineapp.d(22): Error: mutable method 
std.range.interfaces.ForwardRange!(const(uint)).ForwardRange.save 
is not callable using a const object
onlineapp.d(22):Consider adding const or inout to 
std.range.interfaces.ForwardRange!(const(uint)).ForwardRange.save



In this case the Forwardrange Offsets is a
ForwardRange of MapResult(I => uint) of I[]

Since the type of MapResult.front is uint, the ForwardRange is 
essentially a uint[] array.


I could imagine that save is not marked as const because it is 
uncertain whether any indirections are part of the content..? But 
couldn't the compiler check that?


Could anybody explain what exactly is going on? Is there a reason 
the `save()` is not working on const objects?



Given that I haven't done much with ranges yet, any feedback on 
the above implementation is also greatly appreciated (it's just a 
reduced example).