June 09, 2013
On Sunday, 9 June 2013 at 10:49:17 UTC, Jonathan M Davis wrote:
> The other big problem which is related is how to deal with tail-const and
> ranges. It's currently very difficult right now (if it's even possible), which
> makes it so that you should pretty much never mix const and ranges. I know
> that this is one of Steven Schveighoffer's pet peeves, and he's working on some
> sort of proposal to fix it, but he hasn't finished it yet.
>
> - Jonathan M Davis

My pet peeve is how phobos casts away the constness of ranges all over the place, as if it was a trivial and legal operation.
June 09, 2013
On Sunday, June 09, 2013 13:03:16 monarch_dodra wrote:
> My pet peeve is how phobos casts away the constness of ranges all over the place, as if it was a trivial and legal operation.

It definitely shouldn't do that, and I would argue that any place that it's doing it is a bug.

- Jonathan M Davis
June 09, 2013
On Sunday, June 09, 2013 13:02:09 monarch_dodra wrote:
> On Sunday, 9 June 2013 at 10:49:17 UTC, Jonathan M Davis wrote:
> > I fully expect that copy constructors could be added, and
> > AFAIK, we're going
> > to have to at some point, because postlbit constructors cannot
> > copy const or
> > immutable objects - even to create another const or immutable
> > object. Postblit
> > constructors simply do not work with const or immutable,
> > because what they're
> > trying to do is fundamentally broken with const or immutable.
> > You must create
> > objects as const or immutable, not copy them and then alter
> > them as postblits
> > do. It's come up before, and Andrei and Walter have discussed
> > it and
> > supposedly have some sort of solution, but they've never
> > explained it
> > publicly, and AFIK, nothing has been done to fix the problem.
> > 
> > - Jonathan M Davis
> 
> I don't really see what sets apart a "copy constructor" from a "postblit contructor": They have a different sequence of operations, but it's not like the copy constructor will magically have the object ready for use without ever mutating anything?
> 
> So if your CC looks like this:
> struct S
> {
>      int i = 0;
>      this(typeof(this) other)
>      {
>          i = other.i; //oops! mutable operation!
>      }
> }
> 
> Back to square one, no?
> 
> Just because postblit means "copy the bits over, and then construct", doesn't mean the compiler has to place the actual bits in the immutable area before the object is completly constructed. Which is how a CC would work around the problem, unless I'm mistaken.
> 
> postblit should just be able to modify its own members, as if they were tail const (though there might be a problem for class references...). The problem right now (AFAIK), is that for the compiler, postblit is "just" a function, but it should be more than that.

A copy constructor for const or immutable would be in the same boat as any const or immutable constructor. No portion of the object gets mutated. It's constructed as const or immutable, and anything else is an error. But postblit constructors specifically do a bitwise copy and then start mutating the newly constructed struct, and that violates the type system, because it would mean that it's mutating a const or immutable object. And whereas a const or immutable constructor cannot assign a member variable after that member variable has been read, a postblit constructor _has_ to or it can't look at the state of the original object to copy it, because it doesn't have access to the original object and therefore can only look at the current object (which is a bitwise copy of the original). I just don't see how you can make postblit constructors work with const or immutable without violating the type system.

- Jonathan M Davis
June 09, 2013
On Sunday, June 09, 2013 12:59:33 monarch_dodra wrote:
> On Sunday, 9 June 2013 at 10:49:17 UTC, Jonathan M Davis wrote:
> > On Sunday, June 09, 2013 12:33:39 Peter Alexander wrote:
> >> It looks like the core issue here is that it's simply not possible to create a mutable copy of a const object with
> > 
> >> indirection:
> > Part of my point here (that you seem to have missed) is that
> > there is a cost
> > to making it so that const is stripped from the type even if
> > you can do so. It
> > _forces_ a copy if the value being passed in isn't mutable,
> > whereas if the
> > constness were the same, then the value being passed in could
> > potentially be
> > moved rather than copied. As such, I don't know if we even want
> > to strip the
> > constness even if we can.
> > 
> > - Jonathan M Davis
> 
> Well, these are primitives we are talking about. I'm not sure passing an int by value instead of by ref is much more expansive. We already do the same for slices/pointers, so really, all we are doing is making things consistent.
> 
> I agree with your point for structs though. Given any struct, even if POD without indirections, const means const.
> 
> But for built-in primitives, I don't think it is a problem.

It probably would be fine for primitives, but it's nowhere near as clearcut for structs, and it would arguably make things _less_ consistent if IFTI took the tail-const version of all primitives but not for structs. So, I don't know if it's a good idea or not for IFTI to take the tail-const type for all primitive types.

- Jonathan M Davis
June 09, 2013
On Sunday, 9 June 2013 at 10:49:17 UTC, Jonathan M Davis wrote:
> On Sunday, June 09, 2013 12:33:39 Peter Alexander wrote:
>> It looks like the core issue here is that it's simply not
>> possible to create a mutable copy of a const object with
>> indirection:
>
> Part of my point here (that you seem to have missed) is that there is a cost
> to making it so that const is stripped from the type even if you can do so. It
> _forces_ a copy if the value being passed in isn't mutable, whereas if the
> constness were the same, then the value being passed in could potentially be
> moved rather than copied. As such, I don't know if we even want to strip the
> constness even if we can.

A full copy is only required if you go from const->mutable, but that's completely expected and unavoidable. Going from const->const or mutable->mutable will preserve the move opportunity.

It's completely a non-issue as far as I'm concerned: if you want a mutable value and you're given a const value then you *must* make a deep copy. This is true in current D.

The difference comes in with how we handle IFTI.

When I see this:

void foo(T)(T x) {}

I read this as explicitly requesting a mutable T, and if you call it with a const(T) then yes you will need a copy (it's unavoidable).

I would suggest that if you do NOT need a mutable T, then you should specifically ask for const:

void foo(T)(const T x) {}

That way, you get the move no matter what.

June 09, 2013
On Sunday, 9 June 2013 at 12:19:13 UTC, Peter Alexander wrote:
> On Sunday, 9 June 2013 at 10:49:17 UTC, Jonathan M Davis wrote:
>> On Sunday, June 09, 2013 12:33:39 Peter Alexander wrote:
>>> It looks like the core issue here is that it's simply not
>>> possible to create a mutable copy of a const object with
>>> indirection:
>>
>> Part of my point here (that you seem to have missed) is that there is a cost
>> to making it so that const is stripped from the type even if you can do so. It
>> _forces_ a copy if the value being passed in isn't mutable, whereas if the
>> constness were the same, then the value being passed in could potentially be
>> moved rather than copied. As such, I don't know if we even want to strip the
>> constness even if we can.
>
> A full copy is only required if you go from const->mutable, but that's completely expected and unavoidable. Going from const->const or mutable->mutable will preserve the move opportunity.
>
> It's completely a non-issue as far as I'm concerned: if you want a mutable value and you're given a const value then you *must* make a deep copy. This is true in current D.
>
> The difference comes in with how we handle IFTI.
>
> When I see this:
>
> void foo(T)(T x) {}
>
> I read this as explicitly requesting a mutable T, and if you call it with a const(T) then yes you will need a copy (it's unavoidable).
>
> I would suggest that if you do NOT need a mutable T, then you should specifically ask for const:
>
> void foo(T)(const T x) {}
>
> That way, you get the move no matter what.

Yeah, as long as it still prefers to match "const" during overload resolution then it's always possible to provide a const version when needed:

void foo(T)(T x) {}
void foo(T)(const T x) {}

const int a = 1;
foo(a);

Clearly T should match "int" rather than "const(int)", and then the second overload called.
June 09, 2013
On 06/09/2013 04:31 PM, Diggory wrote:
> On Sunday, 9 June 2013 at 12:19:13 UTC, Peter Alexander wrote:
>> On Sunday, 9 June 2013 at 10:49:17 UTC, Jonathan M Davis wrote:
>>> On Sunday, June 09, 2013 12:33:39 Peter Alexander wrote:
>>>> It looks like the core issue here is that it's simply not
>>>> possible to create a mutable copy of a const object with
>>>> indirection:
>>>
>>> Part of my point here (that you seem to have missed) is that there is
>>> a cost
>>> to making it so that const is stripped from the type even if you can
>>> do so. It
>>> _forces_ a copy if the value being passed in isn't mutable, whereas
>>> if the
>>> constness were the same, then the value being passed in could
>>> potentially be
>>> moved rather than copied. As such, I don't know if we even want to
>>> strip the
>>> constness even if we can.
>>
>> A full copy is only required if you go from const->mutable, but that's
>> completely expected and unavoidable. Going from const->const or
>> mutable->mutable will preserve the move opportunity.
>>
>> It's completely a non-issue as far as I'm concerned: if you want a
>> mutable value and you're given a const value then you *must* make a
>> deep copy. This is true in current D.
>>
>> The difference comes in with how we handle IFTI.
>>
>> When I see this:
>>
>> void foo(T)(T x) {}
>>
>> I read this as explicitly requesting a mutable T, and if you call it
>> with a const(T) then yes you will need a copy (it's unavoidable).
>>
>> I would suggest that if you do NOT need a mutable T, then you should
>> specifically ask for const:
>>
>> void foo(T)(const T x) {}
>>
>> That way, you get the move no matter what.
>
> Yeah, as long as it still prefers to match "const" during overload
> resolution then it's always possible to provide a const version when
> needed:
>
> void foo(T)(T x) {}
> void foo(T)(const T x) {}
>
> const int a = 1;
> foo(a);
>
> Clearly T should match "int" rather than "const(int)", and then the
> second overload called.

Then clearly DMD is buggy.

June 09, 2013
On Sunday, June 09, 2013 16:36:45 Timon Gehr wrote:
> On 06/09/2013 04:31 PM, Diggory wrote:
> > Yeah, as long as it still prefers to match "const" during overload resolution then it's always possible to provide a const version when needed:
> > 
> > void foo(T)(T x) {}
> > void foo(T)(const T x) {}
> > 
> > const int a = 1;
> > foo(a);
> > 
> > Clearly T should match "int" rather than "const(int)", and then the
> > second overload called.
> 
> Then clearly DMD is buggy.

It's clearly as in that's the way that he thinks that it should clearly work, not as in that's how it's actually supposed to work. IFTI itself _never_ strips constness. The only place where anything close to that happens is with arrays, and what happens there is that IFTI takes the type of the _slice_ of the array, which is tail-const, so that layer of constness is effectively stripped, but IFTI doesn't do it directly. If the slice had been const like the original, then IFTI would have inferred the type as const.

It would be a definite design change to make it so that IFTI stripped constness. Whether that change should be made is debatable and most definitely _not_ clear. Maybe it should; maybe it shouldn't. The side effects of such a change would have to be examined in great detail.

- Jonathan M Davis
June 09, 2013
On 06/10/2013 12:56 AM, Jonathan M Davis wrote:
> On Sunday, June 09, 2013 16:36:45 Timon Gehr wrote:
>> On 06/09/2013 04:31 PM, Diggory wrote:
>>> Yeah, as long as it still prefers to match "const" during overload
>>> resolution then it's always possible to provide a const version when
>>> needed:
>>>
>>> void foo(T)(T x) {}
>>> void foo(T)(const T x) {}
>>>
>>> const int a = 1;
>>> foo(a);
>>>
>>> Clearly T should match "int" rather than "const(int)", and then the
>>> second overload called.
>>
>> Then clearly DMD is buggy.
>
> It's clearly as in that's the way that he thinks that it should clearly work,
> not as in that's how it's actually supposed to work.  ...

Yes, that's clear.

1 2
Next ›   Last »