October 19, 2009
Andrei Alexandrescu, el 19 de octubre a las 11:16 me escribiste:
> >>>I'm missing something? Why this shouldn't work?
> >>It may work, but I was unable to pull it off reasonably well.
> >
> >What problems did you find?
> 
> I thought I explained that above and in several other posts. I have the feeling this is going in circles, but let me add one more thing. People would want to have a reasonable way of choosing between T[new] and T[]. The differences between them are subtle (I have two tables showing the primitives of T[] and T[new], which are very similar).

If T[new] is "array" and T[] is "slice" as I described them, I see no subtlety, they are huge differences, one is a dynamic array, the other is a view on somebody else's memory.

I know you probably hate when people says this (that's what I avoided
doing it before :):
I works very well in Python. You have arrays (well, lists, but the
interface is the same as an array) and slices. I never heard anybody
complaining about that being confusing.

> That static decision concerns future appends to the array,
> which doesn't strike me as something you know from the get-go
> through future iterations of a design. Use of "auto" messes up
> things further: a nice function may choose to return T[new] because
> it just created an array (an implementation detail), but clients may
> find that unexpected.

I don't see much problem. You should always return an array (T[new]) if
you have one, because you can get an slice from it (the inverse is not
true). Because of this, implicit conversion from array to slice can be
a good idea, so people expecting a slice when an array is returned will
never know an array was returned anyways. If you need to keep appending to
the array, you can have the original array and keep appending to it
without any performance hit (no copying, no new allocations).

What's wrong with that?

-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
Cuando intenté arrimarle mi brazo
Se puso a hablar de Miller, de Anais Nin y Picasso
Y si osaba intentar robarle un beso
Se ponía a leer de Neruda unos versos
Me hizo mucho mal la cumbiera intelectual
October 19, 2009
Denis Koroskin wrote:
> On Mon, 19 Oct 2009 20:16:50 +0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> 
>> I thought I explained that above and in several other posts. I have the feeling this is going in circles, but let me add one more thing. People would want to have a reasonable way of choosing between T[new] and T[]. The differences between them are subtle (I have two tables showing the primitives of T[] and T[new], which are very similar). That static decision concerns future appends to the array, which doesn't strike me as something you know from the get-go through future iterations of a design. Use of "auto" messes up things further: a nice function may choose to return T[new] because it just created an array (an implementation detail), but clients may find that unexpected.
>>
>>
> 
> Put it simple: T[] is a range, and T[new] is a container. They belong to different leagues.

Define ranges and define containers.

> Yes, there is a lot common between them, because T[] supports some subset of operations that T[new] support.

No. You see, even you who have a close perspective on the issue have gotten confused. T[new] does not support assignment from range. So T[] and T[new] are not in a subtyping relationship. They support subtly different primitives.

> We are going in circles because you couldn't convince anyone that we don't need dynamic array type in language core. Not unless library types are usable in CTFE (and have nice syntax).

"Anyone" is a bit assuming I think.


Andrei
October 19, 2009
Johan Granberg wrote:
> I think you are seeing a larger problem than their is. But consider this,
> who is D a language for, is it for beginers only? advanced users only? or
> everyone, if it is a language for everyone don't complicate the language
> for the advanced users by rejecting nice syntax just because it is hard to
> explain.

It's not the nice syntax that's hard to explain.

We all have the same goal - make the language easy to acquire, easy to use, and reasonably efficient. What I can say is that T[new] is not a good step towards achieving those goals.


Andrei
October 19, 2009
Leandro Lucarella wrote:
> Andrei Alexandrescu, el 19 de octubre a las 11:16 me escribiste:
>>>>> I'm missing something? Why this shouldn't work?
>>>> It may work, but I was unable to pull it off reasonably well.
>>> What problems did you find?
>> I thought I explained that above and in several other posts. I have
>> the feeling this is going in circles, but let me add one more thing.
>> People would want to have a reasonable way of choosing between
>> T[new] and T[]. The differences between them are subtle (I have two
>> tables showing the primitives of T[] and T[new], which are very
>> similar).
> 
> If T[new] is "array" and T[] is "slice" as I described them, I see no
> subtlety, they are huge differences, one is a dynamic array, the other is
> a view on somebody else's memory.

Their primitives overlap 90% in syntax and semantics.

> I know you probably hate when people says this (that's what I avoided
> doing it before :):
> I works very well in Python. You have arrays (well, lists, but the
> interface is the same as an array) and slices. I never heard anybody
> complaining about that being confusing.

Python lists and slices are quite different from D arrays.

>> That static decision concerns future appends to the array,
>> which doesn't strike me as something you know from the get-go
>> through future iterations of a design. Use of "auto" messes up
>> things further: a nice function may choose to return T[new] because
>> it just created an array (an implementation detail), but clients may
>> find that unexpected.
> 
> I don't see much problem. You should always return an array (T[new]) if
> you have one, because you can get an slice from it (the inverse is not
> true). Because of this, implicit conversion from array to slice can be
> a good idea, so people expecting a slice when an array is returned will
> never know an array was returned anyways. If you need to keep appending to
> the array, you can have the original array and keep appending to it
> without any performance hit (no copying, no new allocations).
> 
> What's wrong with that?

People expecting a slice and using "auto" or templates are in for a rude awakening.


Andrei
October 19, 2009
Denis Koroskin wrote:
> On Mon, 19 Oct 2009 18:57:45 +0400, Leandro Lucarella <llucax@gmail.com> wrote:
> 
>> Andrei Alexandrescu, el 18 de octubre a las 20:16 me escribiste:
>>> Here's what I wrote to Walter:
>>>
>>> ====================
>>> I'm going to suggest something terrible - let's get rid of T[new]. I
>>> know it's difficult to throw away work you've already done, but
>>> really things with T[new] start to look like a Pyrrhic victory. Here
>>> are some issues:
>>>
>>> * The abstraction doesn't seem to come off as crisp and clean as we
>>> both wanted;
>>>
>>> * There are efficiency issues, such as the two allocations that you
>>> valiantly tried to eliminate in a subset of cases;
>>>
>>> * Explaining two very similar but subtly different types to
>>> newcomers is excruciatingly difficult (I'll send you a draft of the
>>> chapter - it looks like a burn victim who didn't make it);
>>>
>>> * Furthermore, explaining people when to use one vs. the other is
>>> much more difficult than it seems. On the surface, it goes like
>>> this: "If you need to append stuff, use T[new]. If not, use T[]."
>>> Reality is much more subtle. For one thing, T[new] does not allow
>>> contraction from the left, whereas T[] does. That puts T[] at an
>>> advantage. So if you want to append stuff and also contract from the
>>> left, there's nothing our abstractions can help you with.
>>
>> I think this is getting overcomplicated. I don't see it as complex, I see
>> it like this:
>>
>> 2 types should be provided: array and slice.
>>
>> array is a *real* type, storing and owning memory, it should be something
>> like this (conceptually):
>>
>> class array(T)
>> {
>>     size_t length;
>>     size_t capacity;
>>     T[capacity] elements;
>> }
>>
>> 1) a pure reference type.
>> 2) 1 allocation only (interior pointers are not a problem, the GC have to
>>    support them anyways).
>> 3) easily appendable (capacity field).
>>
>> slice should be something like this:
>>
>> struct slice(T)
>> {
>>     size_t length;
>>     T* ptr;
>> }
>>
>> 1) a pure value type.
>> 2) no allocation at all, *ever*.
>> 3) not appendable at all.
>> 4) You can change both ptr and length, and you can mutate the elements (if
>>    not immutable).
>>
>> So a slice is a window to peek a chunk of data.
>>
>> Then you have the syntax. In this discussion, T[new] is array and T[] is
>> slice. I find that syntax very confusing. I think it could be even better
>> to just put those 2 types in object.d (well, do public imports of those
>> 2 types in object.d) and let the people write:
>>
>> array!T a;
>> slice!T s;
>>
>> The array literals should be immutable chunks of memory in the static
>> memory, as ClassInfo.init. The type of [1,2,3] should be, for example,
>> slice!(immutable int), so:
>> auto s = [1,2,3];
>> should create a slice!(immutable int) with length 3 and ptr pointing to
>> the static memory where the [1,2,3] was stored (this is what happens with
>> strings, right? So no surprises here, they are consistent).
>>
>> slice.dup should return an array. If you want to just copy the length and
>> ptr members, use assignment (it's a value type, remember)?
>>
>> auto s = [1,2,3];
>> auto t = s;
>> assert(s.length == t.length);
>> assert(s.ptr == t.ptr);
>> assert(&s != &t);
>>
>> Assignment of arrays is just a pointer assignment (is a reference type):
>>
>> auto a = [1,2,3].dup;
>> auto b = a;
>> assert(a is b);
>>
>> array.dup returns another array. array[] returns a slice though (you can
>> allow implicit casting from array to slice but I don't see the point as
>> array[] is short enough and more explicit). slices should not be
>> convertible to arrays (use slice.dup for that).
>>
>>
>> Back to the syntax, I think T[new] is *really* confusing. It tell me
>> nothing about the type, it provides the same information as calling it
>> it wazzzaaap!T for me. I *really* think it would be better to call it
>> array!T. But if we have both types, T[] is not clear anymore that is
>> a slice, again, you can't figure that out. So maybe T[] should be used for
>> arrays, not slices; if you want some syntax sugar I think T[] is more
>> guessable to be an array than a slice, and it would be a little more
>> backward compatible. Maybe slices can be T[..], but I'm not sure is clear
>> enough, again I think we could live with something more explicit like
>> array!T and slice!T. But at least slices should be part of the language,
>> because that should be the type of "array literals" (damn! that didn't
>> sound right =P).
>>
>>
>> I'm missing something? Why this shouldn't work?
>>
> 
> That's what was initially planned (except some nuances).
> 
> I also think we need a precedent of mapping built-in language type to a library type, starting with Array!(T) and Range!(T). We could then map V[K] to AArray!(K,V), T? to Nullable!(T) etc.
> 
> There is one big issue, though: classes and allocations via 'new' don't work with CTFE. I believe this is something that is planned (Walter once said that an entire subset of D called SafeD should work with CTFE), but it is *very* hard to implement, not feasible in a nearest future for sure.

Don't worry. It's not hugely difficult to implement, though it'll be a while before all the bugs are ironed out. Most of the difficult stuff is already in place. (The CTFE memory bug is the difficult one).
October 19, 2009
Andrei Alexandrescu, el 19 de octubre a las 12:40 me escribiste:
> Leandro Lucarella wrote:
> >Andrei Alexandrescu, el 19 de octubre a las 11:16 me escribiste:
> >>>>>I'm missing something? Why this shouldn't work?
> >>>>It may work, but I was unable to pull it off reasonably well.
> >>>What problems did you find?
> >>I thought I explained that above and in several other posts. I have the feeling this is going in circles, but let me add one more thing. People would want to have a reasonable way of choosing between T[new] and T[]. The differences between them are subtle (I have two tables showing the primitives of T[] and T[new], which are very similar).
> >
> >If T[new] is "array" and T[] is "slice" as I described them, I see no subtlety, they are huge differences, one is a dynamic array, the other is a view on somebody else's memory.
> 
> Their primitives overlap 90% in syntax and semantics.

So what? Ranges and slices too.

> >I know you probably hate when people says this (that's what I avoided
> >doing it before :):
> >I works very well in Python. You have arrays (well, lists, but the
> >interface is the same as an array) and slices. I never heard anybody
> >complaining about that being confusing.
> 
> Python lists and slices are quite different from D arrays.

Not the API.

> >I don't see much problem. You should always return an array (T[new]) if
> >you have one, because you can get an slice from it (the inverse is not
> >true). Because of this, implicit conversion from array to slice can be
> >a good idea, so people expecting a slice when an array is returned will
> >never know an array was returned anyways. If you need to keep appending to
> >the array, you can have the original array and keep appending to it
> >without any performance hit (no copying, no new allocations).
> >
> >What's wrong with that?
> 
> People expecting a slice and using "auto" or templates are in for a rude awakening.

Ok, you are in one of those days when you don't listen to reasons. I give up! =)

-- 
Leandro Lucarella (AKA luca)                     http://llucax.com.ar/
----------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------
Si ella es el sol, yo soy la luna
Si ella es el mar, soy el desierto
Y estamos en eclipse total
Y estamos en eclipse total
October 19, 2009
Walter Bright wrote:
> The purpose of T[new] was to solve the problems T[] had with passing T[] to a function and then the function resizes the T[]. What happens with the original?
> 
> The solution we came up with was to create a third array type, T[new], which was a reference type.
> 
> Andrei had the idea that T[new] could be dispensed with by making a "builder" library type to handle creating arrays by doing things like appending, and then delivering a finished T[] type. This is similar to what std.outbuffer and std.array.Appender do, they just need a bit of refining.
> 
> The .length property of T[] would then become an rvalue only, not an lvalue, and ~= would no longer be allowed for T[].
> 
> We both feel that this would simplify D, make it more flexible, and remove some awkward corner cases like the inability to say a.length++.
> 
> What do you think?

Since noone else seems to have said it: The fact that you're both willing to let it go, after having already invested a lot of time in it, is a good sign for the language. Well done.
October 19, 2009
Leandro Lucarella wrote:
>>> I don't see much problem. You should always return an array (T[new]) if
>>> you have one, because you can get an slice from it (the inverse is not
>>> true). Because of this, implicit conversion from array to slice can be
>>> a good idea, so people expecting a slice when an array is returned will
>>> never know an array was returned anyways. If you need to keep appending to
>>> the array, you can have the original array and keep appending to it
>>> without any performance hit (no copying, no new allocations).
>>>
>>> What's wrong with that?
>> People expecting a slice and using "auto" or templates are in for a
>> rude awakening.
> 
> Ok, you are in one of those days when you don't listen to reasons. I give
> up! =)

At least in that case I had an objective point! I'd agree many others are subjective.

Andrei
October 19, 2009
Don wrote:
> Walter Bright wrote:
>> The purpose of T[new] was to solve the problems T[] had with passing T[] to a function and then the function resizes the T[]. What happens with the original?
>>
>> The solution we came up with was to create a third array type, T[new], which was a reference type.
>>
>> Andrei had the idea that T[new] could be dispensed with by making a "builder" library type to handle creating arrays by doing things like appending, and then delivering a finished T[] type. This is similar to what std.outbuffer and std.array.Appender do, they just need a bit of refining.
>>
>> The .length property of T[] would then become an rvalue only, not an lvalue, and ~= would no longer be allowed for T[].
>>
>> We both feel that this would simplify D, make it more flexible, and remove some awkward corner cases like the inability to say a.length++.
>>
>> What do you think?
> 
> Since noone else seems to have said it: The fact that you're both willing to let it go, after having already invested a lot of time in it, is a good sign for the language. Well done.

I'm relieved that somebody mentioned that :o). As soon as we gave up with T[new], people started to sell it to us. We should preemptively post about eliminating feature plans before actually implementing them.

By the way: implementation of @property has been canceled.


Andrei
October 19, 2009
Andrei Alexandrescu wrote:
> Leandro Lucarella wrote:
>> Andrei Alexandrescu, el 19 de octubre a las 11:16 me escribiste:
>>>>>> I'm missing something? Why this shouldn't work?
>>>>> It may work, but I was unable to pull it off reasonably well.
>>>> What problems did you find?
>>> I thought I explained that above and in several other posts. I have
>>> the feeling this is going in circles, but let me add one more thing.
>>> People would want to have a reasonable way of choosing between
>>> T[new] and T[]. The differences between them are subtle (I have two
>>> tables showing the primitives of T[] and T[new], which are very
>>> similar).
>>
>> If T[new] is "array" and T[] is "slice" as I described them, I see no
>> subtlety, they are huge differences, one is a dynamic array, the other is
>> a view on somebody else's memory.
> 
> Their primitives overlap 90% in syntax and semantics.
> 
>> I know you probably hate when people says this (that's what I avoided
>> doing it before :):
>> I works very well in Python. You have arrays (well, lists, but the
>> interface is the same as an array) and slices. I never heard anybody
>> complaining about that being confusing.
> 
> Python lists and slices are quite different from D arrays.
> 
>>> That static decision concerns future appends to the array,
>>> which doesn't strike me as something you know from the get-go
>>> through future iterations of a design. Use of "auto" messes up
>>> things further: a nice function may choose to return T[new] because
>>> it just created an array (an implementation detail), but clients may
>>> find that unexpected.
>>
>> I don't see much problem. You should always return an array (T[new]) if
>> you have one, because you can get an slice from it (the inverse is not
>> true). Because of this, implicit conversion from array to slice can be
>> a good idea, so people expecting a slice when an array is returned will
>> never know an array was returned anyways. If you need to keep appending to
>> the array, you can have the original array and keep appending to it
>> without any performance hit (no copying, no new allocations).
>>
>> What's wrong with that?
> 
> People expecting a slice and using "auto" or templates are in for a rude awakening.
> 
> 
> Andrei

I would argue that, if they truly *needed* a slice and are relying on "auto" then they implicitly accept responsibility for putting the [] in place to guarantee that.  In other words:
auto foo = someFunc()[];

Or T[]'s and T[new]'s could have an alternative to .dup that does the same thing (return self for T[], and return self[] for T[new]).  Either way, it would be something to point out in the book as a best practice: when expecting a slice, guarantee a slice with []'s.

-- Chris Nicholson-Sauls