November 09, 2012
On Friday, November 09, 2012 14:52:20 deadalnix wrote:
> So my question is, how this duplication can be avoided ? If it can, .peekFront is definitively the way to go. But if it can't, this seems like a really problematic point.

In most cases, it still won't be a problem. How much in the way of code is generally in front? Almost none. It's popFront which generally has the complicated logic. And if you do end up with a more abnormal range which requires a bunch of work in front, depending on what it does, it can just pass the result of front or peekFront to another function which does the work, or worst case, it can mixin the code. Mostly though, I wouldn't expect much code duplication to actually be required.

- Jonathan M Davis
November 09, 2012
On Friday, 9 November 2012 at 20:22:10 UTC, Jonathan M Davis wrote:
> On Friday, November 09, 2012 14:52:20 deadalnix wrote:
>> So my question is, how this duplication can be avoided ? If it can,
>> .peekFront is definitively the way to go. But if it can't, this seems
>> like a really problematic point.
>
> In most cases, it still won't be a problem. How much in the way of code is generally in front?


Quite a ton, if it's calculated lazily.
November 12, 2012
Now I finally see that deepDup/deepCopy/clone is not a (good) solution, because it would be inefficient in a lot of situations. This whole mess makes me wish that D was designed so that all types had value semantics (by convention, since it's probably not possible to enforce by the language).

That would mean:
1) No classes. Just duck-typing based polymorphism à la go language.
2) Dynamic arrays of mutable types would have had to been implemented as copy-on-write types à la Qt containers.

Don't know about the performance implications of COW though.
November 12, 2012
On Monday, 12 November 2012 at 08:37:20 UTC, Tommi wrote:
> This whole mess makes me wish that D was designed so that all types had value semantics (by convention, since it's probably not possible to enforce by the language).
>
> That would mean:
> 1) No classes. Just duck-typing based polymorphism à la go language.
> 2) Dynamic arrays of mutable types would have had to been implemented as copy-on-write types à la Qt containers.

...forgot to add how this relates to this issue:

Then you'd solve this issue by specifying range concept so that front should return by value if it's transient, and front should return by reference or const reference if it's persistent. Then you'd capture front by const reference à la C++. If front returns reference or const reference, then const reference simply references that persistent data. If front returns by value (that's an rvalue from caller's point of view), then this C++ style const reference that we use for capture would extend the lifetime of this temporary rvalue to the const reference variable's scope. And, just to have some code in a post:

ref const auto saved = range.front;


November 12, 2012
On Monday, November 12, 2012 20:51:53 Tommi wrote:
> Then you'd solve this issue by specifying range concept so that front should return by value if it's transient, and front should return by reference or const reference if it's persistent.

That wouldn't work. It's the complete opposite of what a generative range would require if it generates the return value in front. Narrow strings in particularly would be screwed by it, because their front is calculated, and since it's a free function, as is popFront, there's no way to save the return value of front in popFront. It has to be calculated in front, and it's not at all transient.

It also screws with the ability to have sealed containers, since in that case, something like front would never return by ref.

The refness of front's type really shouldn't have anything to do with its transience. They're completely unrelated.

- Jonathan M Davis
November 12, 2012
On Monday, 12 November 2012 at 20:52:07 UTC, Jonathan M Davis wrote:
> That wouldn't work. It's the complete opposite of what a generative range would require if it generates the return value in front. Narrow strings in particularly would be screwed by it, because their front is calculated, and
> since it's a free function, as is popFront, there's no way
> to save the return value of front in popFront. It has to
> be calculated in front, and it's not at all transient.
>
> It also screws with the ability to have sealed containers, since in that case, something like front would never
> return by ref.
>
> The refness of front's type really shouldn't have anything
> to do with its transience. They're completely unrelated.

I didn't understand any of those arguments, so perhaps I still don't fully comprehend this issue.

Persistence
-----------
I thought persistent X means that there's a dedicated storage space for X where it will exist after front returns and X's value will not be tampered with by calling popFront. That notion of persistence led to me into thinking that persistent front could (and really should) return either a reference to X or a const reference if the range doesn't want to allow mutation through front.

Transience
----------
The other side of the coin in my thinking was that transient means that X doesn't have a dedicated storage space. So transient X could be a variable that's local to function front, or it could be that X is stored in a buffer and will exist there after front returns, but the buffer would be overwritten by a call to popFront. And that notion of transience led me into thinking that transient front could never return a reference.

NOTE: All of the above assumes that D were designed so that all types had value semantics.
November 12, 2012
On Monday, November 12, 2012 23:01:22 Tommi wrote:
> On Monday, 12 November 2012 at 20:52:07 UTC, Jonathan M Davis
> 
> wrote:
> > That wouldn't work. It's the complete opposite of what a
> > generative range would require if it generates the return value
> > in front. Narrow strings in particularly would be screwed by
> > it, because their front is calculated, and
> > since it's a free function, as is popFront, there's no way
> > to save the return value of front in popFront. It has to
> > be calculated in front, and it's not at all transient.
> > 
> > It also screws with the ability to have sealed containers,
> > since in that case, something like front would never
> > return by ref.
> > 
> > The refness of front's type really shouldn't have anything to do with its transience. They're completely unrelated.
> 
> I didn't understand any of those arguments, so perhaps I still don't fully comprehend this issue.
> 
> Persistence
> -----------
> I thought persistent X means that there's a dedicated storage space for X where it will exist after front returns and X's value will not be tampered with by calling popFront. That notion of persistence led to me into thinking that persistent front could (and really should) return either a reference to X or a const reference if the range doesn't want to allow mutation through front.
> 
> Transience
> ----------
> The other side of the coin in my thinking was that transient means that X doesn't have a dedicated storage space. So transient X could be a variable that's local to function front, or it could be that X is stored in a buffer and will exist there after front returns, but the buffer would be overwritten by a call to popFront. And that notion of transience led me into thinking that transient front could never return a reference.

With regards to this discussion, transience means that front is a reference type which gets overwritten when popFront is called. So, when popFront is called any references to the return value of front which the caller has kept will change rather than staying the same as they were before popFront. That has _nothing_ to do with returning by ref.

It's perfectly possible for a front which is non-transient to return by ref. front for arrays does that. On the other hand, front on narrow strings doesn't and _can't_ return by ref, because front is calculated on every call. There is no persistent storage for it. But it's _not_ transient like ByLine is. A range like ByLine _could_ return its front by ref. There's nothing stopping it, and it could work just fine. It's just that it doesn't benefit it any, and it would have to make sure that the retun value was still usable on each call to popFront (e.g. if ByLine returned by ref, it would have to worry about whether the buffer was then non-null or sufficiently large or whatever - but it could still work). So, it's unlikely that a range with a transient front would ever return by ref, but it can if it really wants to.

> NOTE: All of the above assumes that D were designed so that all types had value semantics.

Which will never happen. So, any discussion based on that premise is pretty pointless. And this discussion would never have happened in the first place if D had no reference types, because you'll never have a transient front with a value type.

- Jonathan M Davis
November 12, 2012
On Monday, 12 November 2012 at 22:44:22 UTC, Jonathan M Davis wrote:
> On Monday, November 12, 2012 23:01:22 Tommi wrote:
>> NOTE: All of the above assumes that D were designed so that all
>> types had value semantics.
>
> Which will never happen. So, any discussion based on that premise is pretty pointless. And this discussion would
> never have happened in the first place if D had no reference types, because you'll never have a transient front with a value type.

Oh, it was just a matter of miscommunication then. I bet you missed the following post of mine, which made it clear that I wasn't suggesting a solution, but simply dreaming of a better language design (like I usually am):

On Monday, 12 November 2012 at 08:37:20 UTC, Tommi wrote:
> Now I finally see that deepDup/deepCopy/clone is not a (good) solution, because it would be inefficient in a lot of situations. This whole mess makes me wish that D was designed so that all types had value semantics (by convention, since it's probably not possible to enforce by the language).
>
> That would mean:
> 1) No classes. Just duck-typing based polymorphism à la go language.
> 2) Dynamic arrays of mutable types would have had to been implemented as copy-on-write types à la Qt containers.
>
> Don't know about the performance implications of COW though.

I may throw these wild ideas around, but I don't do it in order to have them implemented by D, but so that some-one could crush those ideas with counter-arguments. But yeah, this would be a wrong thread to have that discussion anyway.
November 13, 2012
On Monday, 12 November 2012 at 08:37:20 UTC, Tommi wrote:
> This whole mess makes me wish that D was designed so that all types had value semantics (by convention, since it's probably not possible to enforce by the language).

"..so that all types had value semantics". That's a bit too harsh. Rather there would need to two kinds of types:

1) struct:  own their data, value semantics
2) referer: don't own their data, reference semantics

Dynamic arrays would fall into the first category; owns their data, have value semantics.

Slices of dynamic arrays would be a separate type, falling into the second category; don't own the data, reference semantics.

Range could be of either kind of type.

You'd need two kinds of pointers too: the kind that owns its data, and the kind that references data that someone else owns.

And you'd be able to differentiate between these two kinds of types at compile-time.

Disclaimer: I promise not to spam this thread with this idea any further.
1 2 3 4 5 6 7 8 9 10 11
Next ›   Last »