digitalmars.D - T[new] misgivings
- Andrei Alexandrescu (49/49) Oct 15 2009 I talked to Walter about T[new] today and it seems we are having a
- Rainer Deyke (14/20) Oct 15 2009 This question can be rephrased as, "should 'int[new]' be a reference
- Andrei Alexandrescu (7/29) Oct 15 2009 Well Walter and I agreed they should be pass-by-reference. That doesn't
- Rainer Deyke (14/26) Oct 15 2009 Given that D already has both value types and reference types, the
- Andrei Alexandrescu (4/30) Oct 15 2009 There is a pernicious issue with ~= and slices. T[new] aims at fixing th...
- Rainer Deyke (17/22) Oct 15 2009 Without new syntax, there's no way to distinguish between assignment and
- Walter Bright (2/11) Oct 15 2009 Error. T[] cannot be implicitly converted to T[new]
- Robert Jacques (3/12) Oct 15 2009 I agree.
- Andrei Alexandrescu (12/24) Oct 15 2009 Then your argument building on similarity between the two is weakened.
- Rainer Deyke (5/17) Oct 15 2009 Actually [1, 2, 3] looks more like an array than a slice to me. Arrays
- Andrei Alexandrescu (3/19) Oct 15 2009 My point exactly.
- Jeremie Pelletier (9/38) Oct 15 2009 Simple, assignment to a fails 'cannot cast T[3] to T[new]'.
- Andrei Alexandrescu (4/46) Oct 15 2009 I'd be _very_ unhappy to have to explain to people how in the world we
- Jeremie Pelletier (13/61) Oct 15 2009 I agree it can be confusing, the first time i tried to assign a string
- Andrei Alexandrescu (5/70) Oct 15 2009 Speaking of which, a funny fallout of this a = [1, 2, 3] thing is that
- Sergey Gromov (4/74) Oct 17 2009 How about this specification: [1, 2, 3] is an array literal which
- Robert Jacques (6/55) Oct 15 2009 I like (and have used) the opSliceAssign syntax to represent by value/co...
- Andrei Alexandrescu (4/8) Oct 15 2009 I could. Walter doesn't wanna. He says he wants a[] = b[] to generate an...
- Jason House (6/48) Oct 15 2009 Allocate an array
- Jeremie Pelletier (22/88) Oct 15 2009 I agree with the container model, it should work the way
- dsimcha (16/30) Oct 15 2009 But isn't part of the point of T[new] that you're supposed to only have ...
- Lutger (7/7) Oct 16 2009 Just to understand it:
- Andrei Alexandrescu (9/19) Oct 16 2009 Well no.
- Denis Koroskin (27/43) Oct 16 2009 So, the real question is, what's the type of an array literal?
- Don (15/29) Oct 16 2009 If we made array literals immutable, it'd be obvious.
- Walter Bright (4/5) Oct 16 2009 I see the question as, is T[new] a value type or a reference type? I see...
- Fawzi Mohamed (14/20) Oct 16 2009 I also see T[new] as a reference type.
- Andrei Alexandrescu (8/14) Oct 16 2009 I understand that, but to me that's an example of the good intentions
- Steven Schveighoffer (8/13) Oct 20 2009 Andrei says you think arrays are like slices with some extra
- Andrei Alexandrescu (4/17) Oct 20 2009 I might have misrepresented his position. We both think T[new] is a
- Steven Schveighoffer (5/22) Oct 20 2009 Yeah, I haven't looked at the newsgroup since Thursday, and I had 500 ne...
- Max Samukha (18/20) Oct 16 2009 I'd prefer Walter's way with a provision that array literals are
- Don (6/30) Oct 16 2009 This makes perfect sense to me. The rule would be:
- Walter Bright (5/17) Oct 16 2009 Right. Assignment of a reference type does not copy the values of what
- Max Samukha (17/34) Oct 16 2009 By "true reference type", I meant:
- Fawzi Mohamed (6/48) Oct 16 2009 Yes exactly his is the most logically pleasing handling of resizable
- Don (9/63) Oct 16 2009 Yes, but you could allocate the data immediately after the Array
- Max Samukha (5/13) Oct 16 2009 Great! And if the length later exceeds the capacity, try to reallocate
- Andrei Alexandrescu (4/20) Oct 16 2009 That's the idea. The only problem that Walter pointed out was that
- Leandro Lucarella (13/33) Oct 16 2009 GC have to support internal pointers anyways, I don't see how this chang...
- Andrei Alexandrescu (3/5) Oct 16 2009 T[] is not a reference type.
- Jason House (2/9) Oct 16 2009 While true, normal use will be the same as if it was a reference type. A...
- Andrei Alexandrescu (10/41) Oct 16 2009 It makes sense to make array literals immutable. The trouble is you
- Don (6/53) Oct 16 2009 But you can simply define:
- Don (5/63) Oct 16 2009 In case this isn't clear:
- Andrei Alexandrescu (3/9) Oct 16 2009 static?
- Don (6/17) Oct 16 2009 That's still not compile time. They're initialized in the module
- Max Samukha (7/48) Oct 16 2009 Ok. But it is unacceptable to allocate the literal on heap if all its
- Sergey Gromov (7/22) Oct 17 2009 To me a is an array, a reference type. Therefore assignment here means
- Kagamin (3/11) Oct 19 2009 a = new Appender!int([1,2,3]);
I talked to Walter about T[new] today and it seems we are having a disagreement. The problem is that I believe T[new] is a container, whereas Walter believes T[new] is nothing but a slice with a couple of extra operations. Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do? Walter: T[new] is a slice with benefits, assignment for slices rebinds the slice, therefore the assignment must do the same. In this case, the assignments allocate a new array and make a refer to that array. Whatever old array a referred to will continue to live wherever it was. Me: T[new] is a container, therefore the assignment must resize the container from whatever size it had to 3 and then write 1, 2, 3 to its three slots. I guess each of us has a point, but this is a setup for an increasingly unpleasant situation. Here's the dialog as it happened. A: Ok, then how do I say the common operation "I want to overwrite whatever the array had with 1, 2, 3"? I can only presume there must be an obvious and simple way to do so, and I thought a = [1, 2, 3] was the obvious syntax to achieve that. W: No, you must write a[] = [1, 2, 3]; A: But that only works if the container already had length 3. So what I need to do is this: a.length = 3; a[] = [1, 2, 3]; A: But that is inefficient if the array had length less than 3 because it means double assignment W: Nobody complained about it with slices. A: So if I do want something that does the obvious operation "Whatever that array had, make it now have 1, 2, 3 as it contents" at a reasonable cost I need to call an elaborate function that is highly nontrivial to write? W: Looks like so. assignment to arrays. Call the assign() function"? W: Nobody complained about it with slices. =============== This goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do? Andrei
Oct 15 2009
Andrei Alexandrescu wrote:int[new] a; .... a = [1, 2, 3]; What should that do?This question can be rephrased as, "should 'int[new]' be a reference type or a value type (or something else)?" If 'int[new]' is a reference type, then it must rebind, because that's what assignment does for reference types. If 'int[new]' is a value type, then it must modify the array in place, because that's all it can do. If 'int[new]' is neither a reference type nor a value type, then we're back to (some of) the problems with slices. To answer the rephrased question: 'int[new]' should be a value type.W: Nobody complained about it with slices.FWIW, I found arrays in D1 so completely broken that I didn't it worth the effort to complain about every little detail. Everything about them was wrong. I consider them a textbook example of what not to do. -- Rainer Deyke - rainerd eldwood.com
Oct 15 2009
Rainer Deyke wrote:Andrei Alexandrescu wrote:Well Walter and I agreed they should be pass-by-reference. That doesn't mean they must be references, and the fact that the simplest syntax has the worst efficiency reminds me of iostreams.int[new] a; .... a = [1, 2, 3]; What should that do?This question can be rephrased as, "should 'int[new]' be a reference type or a value type (or something else)?" If 'int[new]' is a reference type, then it must rebind, because that's what assignment does for reference types. If 'int[new]' is a value type, then it must modify the array in place, because that's all it can do. If 'int[new]' is neither a reference type nor a value type, then we're back to (some of) the problems with slices. To answer the rephrased question: 'int[new]' should be a value type.My perception is that you're in a minority. Anyway, if there's something that T[new] can help with, let us know. AndreiW: Nobody complained about it with slices.FWIW, I found arrays in D1 so completely broken that I didn't it worth the effort to complain about every little detail. Everything about them was wrong. I consider them a textbook example of what not to do.
Oct 15 2009
Andrei Alexandrescu wrote:Rainer Deyke wrote:Given that D already has both value types and reference types, the addition of types that are passed by reference but otherwise act as value types actually seems reasonable. It make the language more orthogonal. Classes have one set of attributes. Structs have another. If the language absolutely needs to support both sets of attributes, I should at least be able to mix and match between them. So, what's the syntax for user-defined value types that are passed by reference going to be? ref struct? opPass?To answer the rephrased question: 'int[new]' should be a value type.Well Walter and I agreed they should be pass-by-reference. That doesn't mean they must be references, and the fact that the simplest syntax has the worst efficiency reminds me of iostreams.I was under the impression that arrays were generally considered broken, which is why 'T[new]' is now being introduced. -- Rainer Deyke - rainerd eldwood.comFWIW, I found arrays in D1 so completely broken that I didn't it worth the effort to complain about every little detail. Everything about them was wrong. I consider them a textbook example of what not to do.My perception is that you're in a minority. Anyway, if there's something that T[new] can help with, let us know.
Oct 15 2009
Rainer Deyke wrote:Andrei Alexandrescu wrote:No need for new syntax. T[new] is a struct that has a pointer inside.Rainer Deyke wrote:Given that D already has both value types and reference types, the addition of types that are passed by reference but otherwise act as value types actually seems reasonable. It make the language more orthogonal. Classes have one set of attributes. Structs have another. If the language absolutely needs to support both sets of attributes, I should at least be able to mix and match between them. So, what's the syntax for user-defined value types that are passed by reference going to be? ref struct? opPass?To answer the rephrased question: 'int[new]' should be a value type.Well Walter and I agreed they should be pass-by-reference. That doesn't mean they must be references, and the fact that the simplest syntax has the worst efficiency reminds me of iostreams.There is a pernicious issue with ~= and slices. T[new] aims at fixing that. AndreiI was under the impression that arrays were generally considered broken, which is why 'T[new]' is now being introduced.FWIW, I found arrays in D1 so completely broken that I didn't it worth the effort to complain about every little detail. Everything about them was wrong. I consider them a textbook example of what not to do.My perception is that you're in a minority. Anyway, if there's something that T[new] can help with, let us know.
Oct 15 2009
Andrei Alexandrescu wrote:Rainer Deyke wrote:Without new syntax, there's no way to distinguish between assignment and argument passing. Either 'T[new]' is a value type or 'T[new]' is a reference type. Or 'T[new]' is a messy hybrid, like arrays in D1. There is no way to create a *clean* hybrid with the language facilities in D2. If 'T[new]' has reference semantics, then assignment rebinds the reference. This actually works out fairly well, except for the problem that 'T[new]' has reference semantics. Preferred syntax: assert(is(typeof([1, 2, 3]) == int[new])); int[new] a = [1, 2, 3]; // Rebinds. Syntax for people who insist that array literals should be constant: assert(is(typeof(create_array(1, 2, 3)) == int[new])); int[new] a = create_array(1, 2, 3); // Rebinds. -- Rainer Deyke - rainerd eldwood.comSo, what's the syntax for user-defined value types that are passed by reference going to be? ref struct? opPass?No need for new syntax. T[new] is a struct that has a pointer inside.
Oct 15 2009
Andrei Alexandrescu wrote:This goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
On Thu, 15 Oct 2009 23:16:56 -0400, Walter Bright <newshound1 digitalmars.com> wrote:Andrei Alexandrescu wrote:I agree.This goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
Walter Bright wrote:Andrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; ... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away. AndreiThis goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
Andrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; .... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away.Actually [1, 2, 3] looks more like an array than a slice to me. Arrays can be assigned to slices, no? -- Rainer Deyke - rainerd eldwood.com
Oct 15 2009
Rainer Deyke wrote:Andrei Alexandrescu wrote:My point exactly. AndreiThen your argument building on similarity between the two is weakened. T[new] a; T[] b; .... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away.Actually [1, 2, 3] looks more like an array than a slice to me. Arrays can be assigned to slices, no?
Oct 15 2009
Andrei Alexandrescu wrote:Walter Bright wrote:Simple, assignment to a fails 'cannot cast T[3] to T[new]'. It's already consistent with slices of different types: char[] a = "foo"; // error, cannot cast immutable(char)[] to char[] int[new] b = [1, 2, 3]; // error, cannot cast int[3] to int[new] you have to do: char[] a = "foo".dup; int[new] b = [1, 2, 3].dup; JeremieAndrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; ... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away. AndreiThis goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
Jeremie Pelletier wrote:Andrei Alexandrescu wrote:I'd be _very_ unhappy to have to explain to people how in the world we managed to make the most intuitive syntax not work at all. AndreiWalter Bright wrote:Simple, assignment to a fails 'cannot cast T[3] to T[new]'. It's already consistent with slices of different types: char[] a = "foo"; // error, cannot cast immutable(char)[] to char[] int[new] b = [1, 2, 3]; // error, cannot cast int[3] to int[new] you have to do: char[] a = "foo".dup; int[new] b = [1, 2, 3].dup; JeremieAndrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; ... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away. AndreiThis goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
Andrei Alexandrescu wrote:Jeremie Pelletier wrote:I agree it can be confusing, the first time i tried to assign a string literal to a char[] in D2 I had to pause for a second to understand what was happening :) But what I don't like is that assigning memory from the static data segment to a resizable array isn't safe. Unless the GC can detect that the memory it is trying to resize isn't part of the heap and automatically create a new allocation for it, you're gonna have nasty side effects. The compiler could also implicitly copy the slice, but then it should also automatically copy a "foo" literal when assigned to char[] to keep consistent. JeremieAndrei Alexandrescu wrote:I'd be _very_ unhappy to have to explain to people how in the world we managed to make the most intuitive syntax not work at all. AndreiWalter Bright wrote:Simple, assignment to a fails 'cannot cast T[3] to T[new]'. It's already consistent with slices of different types: char[] a = "foo"; // error, cannot cast immutable(char)[] to char[] int[new] b = [1, 2, 3]; // error, cannot cast int[3] to int[new] you have to do: char[] a = "foo".dup; int[new] b = [1, 2, 3].dup; JeremieAndrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; ... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away. AndreiThis goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
Jeremie Pelletier wrote:Andrei Alexandrescu wrote:Speaking of which, a funny fallout of this a = [1, 2, 3] thing is that we, while striving to avoid all hidden allocations, ended up doing the worst hidden allocation with the simplest and most intuitive syntax. AndreiJeremie Pelletier wrote:I agree it can be confusing, the first time i tried to assign a string literal to a char[] in D2 I had to pause for a second to understand what was happening :) But what I don't like is that assigning memory from the static data segment to a resizable array isn't safe. Unless the GC can detect that the memory it is trying to resize isn't part of the heap and automatically create a new allocation for it, you're gonna have nasty side effects. The compiler could also implicitly copy the slice, but then it should also automatically copy a "foo" literal when assigned to char[] to keep consistent. JeremieAndrei Alexandrescu wrote:I'd be _very_ unhappy to have to explain to people how in the world we managed to make the most intuitive syntax not work at all. AndreiWalter Bright wrote:Simple, assignment to a fails 'cannot cast T[3] to T[new]'. It's already consistent with slices of different types: char[] a = "foo"; // error, cannot cast immutable(char)[] to char[] int[new] b = [1, 2, 3]; // error, cannot cast int[3] to int[new] you have to do: char[] a = "foo".dup; int[new] b = [1, 2, 3].dup; JeremieAndrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; ... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away. AndreiThis goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 15 2009
Thu, 15 Oct 2009 23:18:22 -0500, Andrei Alexandrescu wrote:Jeremie Pelletier wrote:How about this specification: [1, 2, 3] is an array literal which *allocates* an array but the allocation can be optimized away if assigned to a slice.Andrei Alexandrescu wrote:Speaking of which, a funny fallout of this a = [1, 2, 3] thing is that we, while striving to avoid all hidden allocations, ended up doing the worst hidden allocation with the simplest and most intuitive syntax.Jeremie Pelletier wrote:I agree it can be confusing, the first time i tried to assign a string literal to a char[] in D2 I had to pause for a second to understand what was happening :) But what I don't like is that assigning memory from the static data segment to a resizable array isn't safe. Unless the GC can detect that the memory it is trying to resize isn't part of the heap and automatically create a new allocation for it, you're gonna have nasty side effects. The compiler could also implicitly copy the slice, but then it should also automatically copy a "foo" literal when assigned to char[] to keep consistent. JeremieAndrei Alexandrescu wrote:I'd be _very_ unhappy to have to explain to people how in the world we managed to make the most intuitive syntax not work at all. AndreiWalter Bright wrote:Simple, assignment to a fails 'cannot cast T[3] to T[new]'. It's already consistent with slices of different types: char[] a = "foo"; // error, cannot cast immutable(char)[] to char[] int[new] b = [1, 2, 3]; // error, cannot cast int[3] to int[new] you have to do: char[] a = "foo".dup; int[new] b = [1, 2, 3].dup; JeremieAndrei Alexandrescu wrote:Then your argument building on similarity between the two is weakened. T[new] a; T[] b; ... a = [1, 2, 3]; b = [1, 2, 3]; Central to your argument was that the two must do the same thing. Since now literals are in a whole new league (they aren't slices because slices can't be assigned to arrays), the cornerstone of your argument goes away. AndreiThis goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Error. T[] cannot be implicitly converted to T[new]
Oct 17 2009
On Thu, 15 Oct 2009 22:55:07 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I talked to Walter about T[new] today and it seems we are having a disagreement. The problem is that I believe T[new] is a container, whereas Walter believes T[new] is nothing but a slice with a couple of extra operations. Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do? Walter: T[new] is a slice with benefits, assignment for slices rebinds the slice, therefore the assignment must do the same. In this case, the assignments allocate a new array and make a refer to that array. Whatever old array a referred to will continue to live wherever it was. Me: T[new] is a container, therefore the assignment must resize the container from whatever size it had to 3 and then write 1, 2, 3 to its three slots. I guess each of us has a point, but this is a setup for an increasingly unpleasant situation. Here's the dialog as it happened. A: Ok, then how do I say the common operation "I want to overwrite whatever the array had with 1, 2, 3"? I can only presume there must be an obvious and simple way to do so, and I thought a = [1, 2, 3] was the obvious syntax to achieve that. W: No, you must write a[] = [1, 2, 3]; A: But that only works if the container already had length 3. So what I need to do is this: a.length = 3; a[] = [1, 2, 3]; A: But that is inefficient if the array had length less than 3 because it means double assignment W: Nobody complained about it with slices. A: So if I do want something that does the obvious operation "Whatever that array had, make it now have 1, 2, 3 as it contents" at a reasonable cost I need to call an elaborate function that is highly nontrivial to write? W: Looks like so. assignment to arrays. Call the assign() function"? W: Nobody complained about it with slices. =============== This goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do? AndreiI like (and have used) the opSliceAssign syntax to represent by value/copy assignment as opposed to opAssign's by reference syntax. You could always define T[new] auto-resize in the case of a[] = b, but then you'd have to decide if that behavior should be extended to slices.
Oct 15 2009
Robert Jacques wrote:I like (and have used) the opSliceAssign syntax to represent by value/copy assignment as opposed to opAssign's by reference syntax. You could always define T[new] auto-resize in the case of a[] = b, but then you'd have to decide if that behavior should be extended to slices.I could. Walter doesn't wanna. He says he wants a[] = b[] to generate an unchecked memcpy in release mode. Andrei
Oct 15 2009
Andrei Alexandrescu Wrote:I talked to Walter about T[new] today and it seems we are having a disagreement. The problem is that I believe T[new] is a container, whereas Walter believes T[new] is nothing but a slice with a couple of extra operations. Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do?Allocate an arrayWalter: T[new] is a slice with benefits, assignment for slices rebinds the slice, therefore the assignment must do the same. In this case, the assignments allocate a new array and make a refer to that array. Whatever old array a referred to will continue to live wherever it was. Me: T[new] is a container, therefore the assignment must resize the container from whatever size it had to 3 and then write 1, 2, 3 to its three slots. I guess each of us has a point, but this is a setup for an increasingly unpleasant situation. Here's the dialog as it happened. A: Ok, then how do I say the common operation "I want to overwrite whatever the array had with 1, 2, 3"? I can only presume there must be an obvious and simple way to do so, and I thought a = [1, 2, 3] was the obvious syntax to achieve that. W: No, you must write a[] = [1, 2, 3];That matches my expectationA: But that only works if the container already had length 3. So what I need to do is this: a.length = 3; a[] = [1, 2, 3]; A: But that is inefficient if the array had length less than 3 because it means double assignmentThe optimizer should be able to make that efficient.
Oct 15 2009
Andrei Alexandrescu wrote:I talked to Walter about T[new] today and it seems we are having a disagreement. The problem is that I believe T[new] is a container, whereas Walter believes T[new] is nothing but a slice with a couple of extra operations.I agree with the container model, it should work the way std.array.Appender does right now. T[new] would be used when you need to grow the array, and t[] when the size is final.Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do? Walter: T[new] is a slice with benefits, assignment for slices rebinds the slice, therefore the assignment must do the same. In this case, the assignments allocate a new array and make a refer to that array. Whatever old array a referred to will continue to live wherever it was. Me: T[new] is a container, therefore the assignment must resize the container from whatever size it had to 3 and then write 1, 2, 3 to its three slots.I think Walter wants to keep the syntax consistent with slices, even if T[new] is a container, it would just mean "assign this new slice to the container".I guess each of us has a point, but this is a setup for an increasingly unpleasant situation. Here's the dialog as it happened. A: Ok, then how do I say the common operation "I want to overwrite whatever the array had with 1, 2, 3"? I can only presume there must be an obvious and simple way to do so, and I thought a = [1, 2, 3] was the obvious syntax to achieve that. W: No, you must write a[] = [1, 2, 3]; A: But that only works if the container already had length 3. So what I need to do is this: a.length = 3; a[] = [1, 2, 3]; A: But that is inefficient if the array had length less than 3 because it means double assignmentIf the array is of type T[new] then the runtime implementation (_d_array_new_assign?) would take care of resizing the array. As opposed to slices which can't add/remove memory from arrays anymore. You therefore wouldn't need to set the length before assignments.W: Nobody complained about it with slices. A: So if I do want something that does the obvious operation "Whatever that array had, make it now have 1, 2, 3 as it contents" at a reasonable cost I need to call an elaborate function that is highly nontrivial to write? W: Looks like so.Why would you need a nontrivial function? It's all hidden in the compiler runtime implementation, which would just get uninitialized memory if needed and then copy the assignment, its fairly simple.assignment to arrays. Call the assign() function"? W: Nobody complained about it with slices. =============== This goes into something more interesting that I thought of after the conversation. Consider: T[new] a; T[] b; ... a = b; What should that do?Raise a compiler error, its unsafe because its unknown of b is an entire array (so .ptr is a valid GC root) or a slice. T[new] would implicitly cast to T[] but the opposite requires a cast. T[new] a; T[] b; a = cast(T[new])b; // safe because we assume b.ptr is a valid gc root a = b.dup; // safe because the compiler can infer its a gc root Jeremie
Oct 15 2009
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleI talked to Walter about T[new] today and it seems we are having a disagreement. The problem is that I believe T[new] is a container, whereas Walter believes T[new] is nothing but a slice with a couple of extra operations. Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do? Walter: T[new] is a slice with benefits, assignment for slices rebinds the slice, therefore the assignment must do the same. In this case, the assignments allocate a new array and make a refer to that array. Whatever old array a referred to will continue to live wherever it was.But isn't part of the point of T[new] that you're supposed to only have one T[new] pointing to any given block of memory? If you can bind a slice to a T[new], then you can bind a slice to multiple T[new]s. Then you get back to having weird bugs like: immutable(int)[new] foo; foreach(i; 0..5) { foo ~= i; } immutable(int)[] bar = foo[0..4]; immutable(int)[new] baz = bar; // References the same memory as foo baz ~= 666; writeln(foo); // prints [1 2 3 4 666]. The only way around this would be something like COW semantics, i.e. you can assign a slice to a T[new] w/o copying, but when you try to do anything with it that couldn't be done w/ a slice, then it copies.
Oct 15 2009
Just to understand it: int[new] a; int[new] b; a = [1,2,3]; b = a; In your book, the last statement would copy contents of a into b and b.ptr != a.ptr while according to walter, b would rebind to a?
Oct 16 2009
Lutger wrote:Just to understand it: int[new] a; int[new] b; a = [1,2,3]; b = a; In your book, the last statement would copy contents of a into b and b.ptr != a.ptr while according to walter, b would rebind to a?Well no. In the case above b would rebind to a, which is consistent with: int[new] a = [1, 2, 3]; void fun(int[new] b) { ... } fun(a); // does not copy a I am not concerned about assigning one array to another. I'm more concerned about assigning an array literal to an array. Andrei
Oct 16 2009
On Fri, 16 Oct 2009 18:30:24 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Lutger wrote:So, the real question is, what's the type of an array literal? If it's T[new] then you must reassign a reference to be consistent: int[new] a = arrayLiteral; int[new] b = a; // reassign reference foo(arrayLiteral); // a reference passed Else, invoke opAssign. And its semantics is not clear. I'm in favor of removing hidden allocations and making compile-time literals immutable: immutable(int)[] a1 = [1, 2, 3]; In case of compile-time literal assignment you can't just re-assign a reference (because it's immutable), so opAssign should take care of it: int[new] a2; a2 = [1, 2, 3]; // rewritten as a2.opAssign([1, 2, 3]); Since there should be now hidden allocation, values should be overwritten. And there are two options: 1) Strict assignment: 2) Auto-expand (but not shrink!): Why not shrink? Because I believe the following test should be valid: a2 = [1, 2, 3]; assert(a2 == [1, 2, 3]); // they must match if the statement above succeedsJust to understand it: int[new] a; int[new] b; a = [1,2,3]; b = a; In your book, the last statement would copy contents of a into b and b.ptr != a.ptr while according to walter, b would rebind to a?Well no. In the case above b would rebind to a, which is consistent with: int[new] a = [1, 2, 3]; void fun(int[new] b) { ... } fun(a); // does not copy a I am not concerned about assigning one array to another. I'm more concerned about assigning an array literal to an array. Andrei
Oct 16 2009
Andrei Alexandrescu wrote:I talked to Walter about T[new] today and it seems we are having a disagreement. The problem is that I believe T[new] is a container, whereas Walter believes T[new] is nothing but a slice with a couple of extra operations. Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do?If we made array literals immutable, it'd be obvious. There are two sensible options: (1) An error. a = [1, 2, 3].dup; should have the semantics Walter describes. (2) Be equivalent to a.length = 3; a[] = [1,2,3]; (Andrei semantics) But in case (2), char[new] x = "abc"; should also compile (without a .dup). But I don't understand how the whole thing works. int[new] a = [1,2,3,4].dup; int[] b = a[0..3]; a.length = 1; int c = b[2]; How can this be legal in Safe D ? Without reference counting, the only option I can think of is to make it illegal to reduce the length of a T[new] array: you need to reallocate if you want to shrink it.
Oct 16 2009
Don wrote:There are two sensible options:I see the question as, is T[new] a value type or a reference type? I see it as a reference type, and so assignment should act like a reference assignment, not a value assignment.
Oct 16 2009
On 2009-10-16 11:49:12 +0200, Walter Bright <newshound1 digitalmars.com> said:Don wrote:I also see T[new] as a reference type. Unfortunately this precludes some optimizations like putting size and capacity directly at the start of the allocated array, avoiding a redirection to access data: The caller object would miss the changes if the block is reallocated. T[new] a; T[new] b; b.length=LongLength; a.length=? But as putting them at the start of the array might have an adverse effect on optimizations that expect special alignment (vector operations) maybe not everything is bad. FawziThere are two sensible options:I see the question as, is T[new] a value type or a reference type? I see it as a reference type, and so assignment should act like a reference assignment, not a value assignment.
Oct 16 2009
Walter Bright wrote:Don wrote:I understand that, but to me that's an example of the good intentions that pave the way to hell. All of a sudden we have the best syntax there is either being surreptitiously inefficient, or not work at all. Why not see arrays as what they really are? They are a struct with a pointer inside it. The struct has opAssign. Period. Why "see" the arrays in a way that's ungainful? AndreiThere are two sensible options:I see the question as, is T[new] a value type or a reference type? I see it as a reference type, and so assignment should act like a reference assignment, not a value assignment.
Oct 16 2009
On Fri, 16 Oct 2009 05:49:12 -0400, Walter Bright <newshound1 digitalmars.com> wrote:Don wrote:Andrei says you think arrays are like slices with some extra functionality, but slices are *not* a reference type, they are hybrids. Do you think T[new] arrays should be fully reference types? (I do) Otherwise, if you keep the "length is a value type" semantic, you get the same crappy appending behavior we have now. -SteveThere are two sensible options:I see the question as, is T[new] a value type or a reference type? I see it as a reference type, and so assignment should act like a reference assignment, not a value assignment.
Oct 20 2009
Steven Schveighoffer wrote:On Fri, 16 Oct 2009 05:49:12 -0400, Walter Bright <newshound1 digitalmars.com> wrote:I might have misrepresented his position. We both think T[new] is a reference type, and it was implemented that way in the now defunct feature. AndreiDon wrote:Andrei says you think arrays are like slices with some extra functionality, but slices are *not* a reference type, they are hybrids. Do you think T[new] arrays should be fully reference types? (I do)There are two sensible options:I see the question as, is T[new] a value type or a reference type? I see it as a reference type, and so assignment should act like a reference assignment, not a value assignment.
Oct 20 2009
On Tue, 20 Oct 2009 09:09:46 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:Yeah, I haven't looked at the newsgroup since Thursday, and I had 500 new messages to read. Sorry for responding to this dead thread :) -SteveOn Fri, 16 Oct 2009 05:49:12 -0400, Walter Bright <newshound1 digitalmars.com> wrote:I might have misrepresented his position. We both think T[new] is a reference type, and it was implemented that way in the now defunct feature.Don wrote:Andrei says you think arrays are like slices with some extra functionality, but slices are *not* a reference type, they are hybrids. Do you think T[new] arrays should be fully reference types? (I do)There are two sensible options:I see the question as, is T[new] a value type or a reference type? I see it as a reference type, and so assignment should act like a reference assignment, not a value assignment.
Oct 20 2009
On Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I talked to Walter about T[new] today and it seems we are having a disagreement.I'd prefer Walter's way with a provision that array literals are immutable and allocated statically: immutable(int)[] a = [1, 2, 3]; // no allocation here int[new] b = [1, 2]; // new storage is allocated and the literal is copied there int[] a = [1, 2, 3]; // error. dup needed auto c = [1, 2, 3]; // c is of type immutable(int)[] b[] = c; //b's length is changed and c's contents copied to b's storage auto d = [1, 2, 3].dup; // d is of type int[new] auto e = [1, 2, 3].idup; // e is of type immutable(int)[new] // arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);
Oct 16 2009
Max Samukha wrote:On Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].I talked to Walter about T[new] today and it seems we are having a disagreement.I'd prefer Walter's way with a provision that array literals are immutable and allocated statically: immutable(int)[] a = [1, 2, 3]; // no allocation here int[new] b = [1, 2]; // new storage is allocated and the literal is copied there int[] a = [1, 2, 3]; // error. dup needed auto c = [1, 2, 3]; // c is of type immutable(int)[] b[] = c; //b's length is changed and c's contents copied to b's storage auto d = [1, 2, 3].dup; // d is of type int[new] auto e = [1, 2, 3].idup; // e is of type immutable(int)[new] // arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);
Oct 16 2009
Don wrote:Max Samukha wrote:Right. Assignment of a reference type does not copy the values of what is referred to. Only the reference is copied. I think it would be very strange to have T[] behave like a reference type (which it does now) and T[new] to behave like a value type.// arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].
Oct 16 2009
On Fri, 16 Oct 2009 02:53:20 -0700, Walter Bright <newshound1 digitalmars.com> wrote:Don wrote:By "true reference type", I meant: struct ArrayRef { Array* ptr; } struct Array { void* data; size_t length; // size_t capacity; } The fat reference approach for arrays has sucked from day one (IMHO). I think performance-critical code will use slices (read - ranges) anyway, so the additional allocation and indirection is not a big issue.Max Samukha wrote:Right. Assignment of a reference type does not copy the values of what is referred to. Only the reference is copied. I think it would be very strange to have T[] behave like a reference type (which it does now) and T[new] to behave like a value type.// arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].
Oct 16 2009
On 2009-10-16 13:54:03 +0200, Max Samukha <spambox d-coding.com> said:On Fri, 16 Oct 2009 02:53:20 -0700, Walter Bright <newshound1 digitalmars.com> wrote:Yes exactly his is the most logically pleasing handling of resizable array, a resizable array is a ArrayRef (and the capacity there should not be commented out). Obviously this has a cost (extra indirection to access data). FawziDon wrote:By "true reference type", I meant: struct ArrayRef { Array* ptr; } struct Array { void* data; size_t length; // size_t capacity; } The fat reference approach for arrays has sucked from day one (IMHO). I think performance-critical code will use slices (read - ranges) anyway, so the additional allocation and indirection is not a big issue.Max Samukha wrote:Right. Assignment of a reference type does not copy the values of what is referred to. Only the reference is copied. I think it would be very strange to have T[] behave like a reference type (which it does now) and T[new] to behave like a value type.// arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].
Oct 16 2009
Fawzi Mohamed wrote:On 2009-10-16 13:54:03 +0200, Max Samukha <spambox d-coding.com> said:Yes, but you could allocate the data immediately after the Array structure, so you only have one allocation. And in the common case, where it never exceeds the original capacity, they stay together and preserve cache locality. void *data; // = &raw_data; size_t length; size_t capacity; // = 512 ubyte[512] raw_data;On Fri, 16 Oct 2009 02:53:20 -0700, Walter Bright <newshound1 digitalmars.com> wrote:Yes exactly his is the most logically pleasing handling of resizable array, a resizable array is a ArrayRef (and the capacity there should not be commented out). Obviously this has a cost (extra indirection to access data). FawziDon wrote:By "true reference type", I meant: struct ArrayRef { Array* ptr; } struct Array { void* data; size_t length; // size_t capacity; } The fat reference approach for arrays has sucked from day one (IMHO). I think performance-critical code will use slices (read - ranges) anyway, so the additional allocation and indirection is not a big issue.Max Samukha wrote:Right. Assignment of a reference type does not copy the values of what is referred to. Only the reference is copied. I think it would be very strange to have T[] behave like a reference type (which it does now) and T[new] to behave like a value type.// arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].
Oct 16 2009
On Fri, 16 Oct 2009 14:25:44 +0200, Don <nospam nospam.com> wrote:Yes, but you could allocate the data immediately after the Array structure, so you only have one allocation. And in the common case, where it never exceeds the original capacity, they stay together and preserve cache locality. void *data; // = &raw_data; size_t length; size_t capacity; // = 512 ubyte[512] raw_data;Great! And if the length later exceeds the capacity, try to reallocate in place. If impossible, allocate a new block, copy the data, adjust the data pointer and shrink the original block to the size of the Array struct. Right?
Oct 16 2009
Max Samukha wrote:On Fri, 16 Oct 2009 14:25:44 +0200, Don <nospam nospam.com> wrote:That's the idea. The only problem that Walter pointed out was that moving GCs may have a problem with internal pointers. AndreiYes, but you could allocate the data immediately after the Array structure, so you only have one allocation. And in the common case, where it never exceeds the original capacity, they stay together and preserve cache locality. void *data; // = &raw_data; size_t length; size_t capacity; // = 512 ubyte[512] raw_data;Great! And if the length later exceeds the capacity, try to reallocate in place. If impossible, allocate a new block, copy the data, adjust the data pointer and shrink the original block to the size of the Array struct. Right?
Oct 16 2009
Andrei Alexandrescu, el 16 de octubre a las 09:12 me escribiste:Max Samukha wrote:GC have to support internal pointers anyways, I don't see how this changes anything... -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- We're rotten fruit We're damaged goods What the hell, we've got nothing more to lose One gust and we will probably crumble We're backdriftersOn Fri, 16 Oct 2009 14:25:44 +0200, Don <nospam nospam.com> wrote:That's the idea. The only problem that Walter pointed out was that moving GCs may have a problem with internal pointers.Yes, but you could allocate the data immediately after the Array structure, so you only have one allocation. And in the common case, where it never exceeds the original capacity, they stay together and preserve cache locality. void *data; // = &raw_data; size_t length; size_t capacity; // = 512 ubyte[512] raw_data;Great! And if the length later exceeds the capacity, try to reallocate in place. If impossible, allocate a new block, copy the data, adjust the data pointer and shrink the original block to the size of the Array struct. Right?
Oct 16 2009
Walter Bright wrote:I think it would be very strange to have T[] behave like a reference type (which it does now) and T[new] to behave like a value type.T[] is not a reference type. Andrei
Oct 16 2009
Andrei Alexandrescu Wrote:Walter Bright wrote:While true, normal use will be the same as if it was a reference type. All legal changes to a slice impact all copies of the slice.I think it would be very strange to have T[] behave like a reference type (which it does now) and T[new] to behave like a value type.T[] is not a reference type. Andrei
Oct 16 2009
Don wrote:Max Samukha wrote:It makes sense to make array literals immutable. The trouble is you won't be able to create arrays of most interesting types that way. class Widget { ... } Widget w1, w2, w3; auto arr = [ w1, w2, w3 ]; // error! Walter brought up the same argument at some point. He compared array literals with string literals. No! String literals only contain statically-known characters. Array literals may contain anything. AndreiOn Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].I talked to Walter about T[new] today and it seems we are having a disagreement.I'd prefer Walter's way with a provision that array literals are immutable and allocated statically: immutable(int)[] a = [1, 2, 3]; // no allocation here int[new] b = [1, 2]; // new storage is allocated and the literal is copied there int[] a = [1, 2, 3]; // error. dup needed auto c = [1, 2, 3]; // c is of type immutable(int)[] b[] = c; //b's length is changed and c's contents copied to b's storage auto d = [1, 2, 3].dup; // d is of type int[new] auto e = [1, 2, 3].idup; // e is of type immutable(int)[new] // arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);
Oct 16 2009
Andrei Alexandrescu wrote:Don wrote:But you can simply define: T[] makeArray(T)(T[] vars...) { return vars; } auto arr = makeArray(w1, w2, w3); Unless we make arrays immutable, I don't know how we can define an array of compile-time constants.Max Samukha wrote:It makes sense to make array literals immutable. The trouble is you won't be able to create arrays of most interesting types that way. class Widget { ... } Widget w1, w2, w3; auto arr = [ w1, w2, w3 ]; // error! Walter brought up the same argument at some point. He compared array literals with string literals. No! String literals only contain statically-known characters. Array literals may contain anything. AndreiOn Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].I talked to Walter about T[new] today and it seems we are having a disagreement.I'd prefer Walter's way with a provision that array literals are immutable and allocated statically: immutable(int)[] a = [1, 2, 3]; // no allocation here int[new] b = [1, 2]; // new storage is allocated and the literal is copied there int[] a = [1, 2, 3]; // error. dup needed auto c = [1, 2, 3]; // c is of type immutable(int)[] b[] = c; //b's length is changed and c's contents copied to b's storage auto d = [1, 2, 3].dup; // d is of type int[new] auto e = [1, 2, 3].idup; // e is of type immutable(int)[new] // arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);
Oct 16 2009
Don wrote:Andrei Alexandrescu wrote:In case this isn't clear: real [] sinsTable = [ sin(1.0), sin(2.0), sin(3.0), sin(4.0) ]; How do you do this so that the entries in the table are calculated at compile time?Don wrote:But you can simply define: T[] makeArray(T)(T[] vars...) { return vars; } auto arr = makeArray(w1, w2, w3); Unless we make arrays immutable, I don't know how we can define an array of compile-time constants.Max Samukha wrote:It makes sense to make array literals immutable. The trouble is you won't be able to create arrays of most interesting types that way. class Widget { ... } Widget w1, w2, w3; auto arr = [ w1, w2, w3 ]; // error! Walter brought up the same argument at some point. He compared array literals with string literals. No! String literals only contain statically-known characters. Array literals may contain anything. AndreiOn Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].I talked to Walter about T[new] today and it seems we are having a disagreement.I'd prefer Walter's way with a provision that array literals are immutable and allocated statically: immutable(int)[] a = [1, 2, 3]; // no allocation here int[new] b = [1, 2]; // new storage is allocated and the literal is copied there int[] a = [1, 2, 3]; // error. dup needed auto c = [1, 2, 3]; // c is of type immutable(int)[] b[] = c; //b's length is changed and c's contents copied to b's storage auto d = [1, 2, 3].dup; // d is of type int[new] auto e = [1, 2, 3].idup; // e is of type immutable(int)[new] // arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);
Oct 16 2009
Don wrote:In case this isn't clear: real [] sinsTable = [ sin(1.0), sin(2.0), sin(3.0), sin(4.0) ]; How do you do this so that the entries in the table are calculated at compile time?static? Andrei
Oct 16 2009
Andrei Alexandrescu wrote:Don wrote:That's still not compile time. They're initialized in the module constructor. If you make them an enum array, they're at compile time, but then you shouldn't be able to index the array at runtime (the whole point of 'enum' was that it doesn't get stored).In case this isn't clear: real [] sinsTable = [ sin(1.0), sin(2.0), sin(3.0), sin(4.0) ]; How do you do this so that the entries in the table are calculated at compile time?static? Andrei
Oct 16 2009
On Fri, 16 Oct 2009 09:00:27 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Don wrote:Ok. But it is unacceptable to allocate the literal on heap if all its elements are statically known. I'd rather have a library function than the current situation. Why not: auto arr = array(w1, w2, w3)? This is an important issue. Please don't leave it unaddressed.Max Samukha wrote:It makes sense to make array literals immutable. The trouble is you won't be able to create arrays of most interesting types that way. class Widget { ... } Widget w1, w2, w3; auto arr = [ w1, w2, w3 ]; // error! Walter brought up the same argument at some point. He compared array literals with string literals. No! String literals only contain statically-known characters. Array literals may contain anything. AndreiOn Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:This makes perfect sense to me. The rule would be: If 'x' is T[new], then: x = y; _always_ copies y into a {length, capacity-specified block}, unless it already is one. x is given a pointer to the start of that block. x[] = y[]; does a memcpy, regardless of whether y is a T[new] or a T[].I talked to Walter about T[new] today and it seems we are having a disagreement.I'd prefer Walter's way with a provision that array literals are immutable and allocated statically: immutable(int)[] a = [1, 2, 3]; // no allocation here int[new] b = [1, 2]; // new storage is allocated and the literal is copied there int[] a = [1, 2, 3]; // error. dup needed auto c = [1, 2, 3]; // c is of type immutable(int)[] b[] = c; //b's length is changed and c's contents copied to b's storage auto d = [1, 2, 3].dup; // d is of type int[new] auto e = [1, 2, 3].idup; // e is of type immutable(int)[new] // arrays are true reference types int[new] a = [1, 2, 3]; b = a; a.length = 22; assert (a.length == b.length);
Oct 16 2009
Thu, 15 Oct 2009 21:55:07 -0500, Andrei Alexandrescu wrote:int[new] a; ... a = [1, 2, 3]; What should that do?To me a is an array, a reference type. Therefore assignment here means rebinding a to a new array created from a literal.A: Ok, then how do I say the common operation "I want to overwrite whatever the array had with 1, 2, 3"? I can only presume there must be an obvious and simple way to do so, and I thought a = [1, 2, 3] was the obvious syntax to achieve that.I'd say a.replace([1, 2, 3]);T[new] a; T[] b; ... a = b; What should that do?Error: type mismatch. Use a = b.dup;
Oct 17 2009
Andrei Alexandrescu Wrote:Paradoxically this seems to be conducive to subtle efficiency issues. For example, consider: int[new] a; ... a = [1, 2, 3]; What should that do?a = new Appender!int([1,2,3]); What you describe is more like StringBuilder, and, yes, things like that require full-blown API.
Oct 19 2009