digitalmars.D - static arrays becoming value types
- Walter Bright (24/24) Oct 19 2009 Currently, static arrays are (as in C) half-value types and
- Jason House (2/36) Oct 19 2009 I've never heard the argument why they should be value types. Can you or...
- grauzone (9/47) Oct 19 2009 Because they are some bastardization now. Neither slice, nor reference
- Robert Jacques (4/29) Oct 19 2009 Thank you. Will the various operators be overloaded? i.e. a = b + c;
- Walter Bright (3/5) Oct 19 2009 Don't know. For now, I'd just leave the a=b+c syntax illegal. We can
- dsimcha (5/29) Oct 19 2009 Vote++. It's funny, I use static arrays so little that I never realized...
- Leandro Lucarella (9/39) Oct 20 2009 It would be the poor men tuple for returning (homogeneous) stuff =P
- language_fan (13/47) Oct 20 2009 It depends on how you define things. Traditionally tuples are seen as a
- Leandro Lucarella (10/61) Oct 20 2009 In what tradition? C++ maybe. I never saw a pair type outside C++, but s...
- language_fan (32/89) Oct 20 2009 Pairs are pretty common actually. You might have applications that have
- Robert Jacques (12/101) Oct 20 2009 Or use a templated opAssign mixin to allow two desperate types to be
- language_fan (12/33) Oct 20 2009 If you have built-in tuple literals, there is no way you can build a
- Robert Jacques (8/41) Oct 21 2009 Unlike C++, D templates don't require a PhD to use. And it's definitely ...
- language_fan (16/67) Oct 21 2009 Why do you insist on using nominal typing for tuples and the library
- Andrei Alexandrescu (7/30) Oct 21 2009 I'm late in this dialog, but I'm not seeing an impediment here. What
- Bill Baxter (4/33) Oct 21 2009 Well, auto-flattening is a colossally bad idea to be sure.
- Andrei Alexandrescu (4/5) Oct 21 2009 Well that I agree with. I wonder if we need to fix it for D2. If we
- language_fan (74/90) Oct 21 2009 Using tuples in D is a major pain in the ass. In fact it has been made s...
- language_fan (4/29) Oct 21 2009 I forgot to say that you need two kinds of tuple "literals" in your
- Andrei Alexandrescu (34/75) Oct 21 2009 Why do you define Tuple instead of using the standard std.typecons.tuple...
- language_fan (30/52) Oct 21 2009 It might be if we use your definition of tuple. But the mighty compiler
- Andrei Alexandrescu (15/86) Oct 21 2009 I don't understand what you are trying to accomplish. As far as I can
- language_fan (27/46) Oct 21 2009 You somehow refuse to see that D has a tuple type which the compiler
- Andrei Alexandrescu (4/6) Oct 21 2009 D has tuples, it doesn't have tuple literals. Tuple attempts to supplant...
- Denis Koroskin (19/90) Oct 21 2009 Well, he could just change the symbol used to denote comma operator to
- grauzone (6/112) Oct 21 2009 Or even:
- Leandro Lucarella (12/21) Oct 21 2009 _ is a regular symbol (variable name in this case), there is nothing
- grauzone (11/26) Oct 21 2009 I didn't even know this. In Python, it doesn't matter anyway, because it...
- Leandro Lucarella (8/31) Oct 21 2009 Using _ is a bad idea if you use gettext though ;)
- language_fan (15/42) Oct 21 2009 Even though not being an expert in Python (have not really used it), as
- Leandro Lucarella (18/70) Oct 21 2009 I think this is an important point too. Maybe tuples are not *that* brok...
- bearophile (17/24) Oct 21 2009 In Python2.x you can also do:
- Leandro Lucarella (12/57) Oct 20 2009 Yes, D support for tuples is way far from ideal.
- Robert Jacques (23/72) Oct 20 2009 How so? I think this is merely the difference between a library type in ...
- Andrei Alexandrescu (4/28) Oct 20 2009 I also don't understand all the argument about structural vs. name
- Robert Jacques (14/37) Oct 20 2009 The original thread stated that D's value tuples (as opposed to type
- Leandro Lucarella (19/45) Oct 20 2009 I wasn't referring to this particular example, even when I agree this is
- Robert Jacques (3/11) Oct 20 2009 Would you happen to know of a language which does tuples well already?
- Yigal Chripun (2/15) Oct 20 2009 pick any functional language.. my favorite is ML
- Leandro Lucarella (10/27) Oct 21 2009 Or Python ;)
- downs (2/36) Oct 19 2009 WOO! Thanks! :D
- Saaa (2/25) Oct 19 2009 Would that be D1&D2 or only D2?
- Walter Bright (2/3) Oct 19 2009 D2 only, as it changes the behavior.
- Chad J (1/1) Oct 19 2009 Yes please!
- Yigal Chripun (2/26) Oct 19 2009 that's good news :)
- bearophile (21/24) Oct 19 2009 If I have generic code, like a templated function, that accepts both a d...
- dsimcha (9/14) Oct 20 2009 and a static array, the function call will change its performance signat...
- Don (3/37) Oct 20 2009 I think this change is mandatory. We need it for SIMD operations. It
- bearophile (4/5) Oct 20 2009 Why? Why the compiler can't optimize things and perform SIMD operations ...
- Don (13/21) Oct 20 2009 Because they are passed by reference. It certainly can't do it on D1:
- Ary Borenszweig (11/45) Oct 20 2009 I don't know why people are agreeing about this. At least I don't
- Kagamin (2/3) Oct 20 2009 Weren't they value types from the start? That's surprise. What do you th...
- Kagamin (2/4) Oct 20 2009 Nothing to agonize about really (except for C compatibility), they're va...
- Max Samukha (5/29) Oct 20 2009 Hooah!
- Steven Schveighoffer (22/47) Oct 20 2009 What happens for IFTI?
- dsimcha (8/65) Oct 20 2009 To me, static arrays are an optimization that you don't use unless you r...
- bearophile (8/13) Oct 24 2009 Or you can also pass a pointer to the first item of the fixed-size array...
Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)
Oct 19 2009
Walter Bright Wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)I've never heard the argument why they should be value types. Can you or Andrei explain why it makes more sense as value types?
Oct 19 2009
Jason House wrote:Walter Bright Wrote:Because they are some bastardization now. Neither slice, nor reference type, nor value type. Somehow, they behave like value type when declared in a struct or a variable. (Because they allocate memory for the contents they point to.) But if you pass them as argument, they behave like reference type (they're just pointers to the actual data). And you can't return them at all from functions for unknown reasons. It's a real WTF. The only clean way to fix them is the as described by Walter.Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)I've never heard the argument why they should be value types. Can you or Andrei explain why it makes more sense as value types?
Oct 19 2009
On Mon, 19 Oct 2009 21:50:46 -0400, Walter Bright <newshound1 digitalmars.com> wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Thank you. Will the various operators be overloaded? i.e. a = b + c; instead of a[] = b[] + c[]; ?
Oct 19 2009
Robert Jacques wrote:Thank you. Will the various operators be overloaded? i.e. a = b + c; instead of a[] = b[] + c[]; ?Don't know. For now, I'd just leave the a=b+c syntax illegal. We can always loosen things up later.
Oct 19 2009
== Quote from Walter Bright (newshound1 digitalmars.com)'s articleCurrently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Vote++. It's funny, I use static arrays so little that I never realized that they weren't passed by value to functions. I'd absolutely love to be able to just return static arrays from functions, and often use structs to do that now, but using structs feels like a really ugly hack.
Oct 19 2009
dsimcha, el 20 de octubre a las 02:44 me escribiste:== Quote from Walter Bright (newshound1 digitalmars.com)'s articleIt would be the poor men tuple for returning (homogeneous) stuff =P -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- La máquina de la moneda, mirá como te queda! -- Sidharta KiwiCurrently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Vote++. It's funny, I use static arrays so little that I never realized that they weren't passed by value to functions. I'd absolutely love to be able to just return static arrays from functions, and often use structs to do that now, but using structs feels like a really ugly hack.
Oct 20 2009
Tue, 20 Oct 2009 10:34:35 -0300, Leandro Lucarella thusly wrote:dsimcha, el 20 de octubre a las 02:44 me escribiste:It depends on how you define things. Traditionally tuples are seen as a generalization of pairs (2 elements -> n elements). Records, on the other hand, are generalization of tuples (simple number index -> named elements). You need couple of additional layers of generalization to come up with structs (subtyping, member functions, generics etc.) One nasty thing about D's structs is that they don't have structural equivalence relation unlike tuples. So you need to use the same container struct type to get the same semantics. To achieve that you would need some kind of STuple on standard library level or other kinds of hacks. What I find unfortunate in D is that your abstractions come in two sizes - either you use the modest tiny construct that does not scale elegantly or the enormous hammer to crush things down theatretically.== Quote from Walter Bright (newshound1 digitalmars.com)'s articleIt would be the poor men tuple for returning (homogeneous) stuff =PCurrently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Vote++. It's funny, I use static arrays so little that I never realized that they weren't passed by value to functions. I'd absolutely love to be able to just return static arrays from functions, and often use structs to do that now, but using structs feels like a really ugly hack.
Oct 20 2009
language_fan, el 20 de octubre a las 13:52 me escribiste:Tue, 20 Oct 2009 10:34:35 -0300, Leandro Lucarella thusly wrote:In what tradition? C++ maybe. I never saw a pair type outside C++, but saw tuples everywhere (even in other structured languages like SQL).dsimcha, el 20 de octubre a las 02:44 me escribiste:It depends on how you define things. Traditionally tuples are seen as a generalization of pairs (2 elements -> n elements). Records, on the other== Quote from Walter Bright (newshound1 digitalmars.com)'s articleIt would be the poor men tuple for returning (homogeneous) stuff =PCurrently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Vote++. It's funny, I use static arrays so little that I never realized that they weren't passed by value to functions. I'd absolutely love to be able to just return static arrays from functions, and often use structs to do that now, but using structs feels like a really ugly hack.hand, are generalization of tuples (simple number index -> named elements). You need couple of additional layers of generalization to come up with structs (subtyping, member functions, generics etc.) One nasty thing about D's structs is that they don't have structural equivalence relation unlike tuples. So you need to use the same container struct type to get the same semantics. To achieve that you would need some kind of STuple on standard library level or other kinds of hacks. What I find unfortunate in D is that your abstractions come in two sizes - either you use the modest tiny construct that does not scale elegantly or the enormous hammer to crush things down theatretically.I don't understand very well what are you saying anyways... -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Fantasy is as important as wisdom
Oct 20 2009
Tue, 20 Oct 2009 12:39:47 -0300, Leandro Lucarella thusly wrote:language_fan, el 20 de octubre a las 13:52 me escribiste:Pairs are pretty common actually. You might have applications that have mappings, functions, or zip (list operation) etc. I admit these are more common in functional languages but the main reason for this is that most mainstream languages do not support the Pair or Tuple types in any way. Even D has broken support (from this point of view).Tue, 20 Oct 2009 10:34:35 -0300, Leandro Lucarella thusly wrote:In what tradition? C++ maybe. I never saw a pair type outside C++, but saw tuples everywhere (even in other structured languages like SQL).dsimcha, el 20 de octubre a las 02:44 me escribiste:It depends on how you define things. Traditionally tuples are seen as a generalization of pairs (2 elements -> n elements). Records, on the other== Quote from Walter Bright (newshound1 digitalmars.com)'s articleIt would be the poor men tuple for returning (homogeneous) stuff =PCurrently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Vote++. It's funny, I use static arrays so little that I never realized that they weren't passed by value to functions. I'd absolutely love to be able to just return static arrays from functions, and often use structs to do that now, but using structs feels like a really ugly hack.Because of the unnecessary nominal typing in D's tuple emulation, redefinitions of Tuples do not have implicit equivalence relation: struct Tuple(T...) { T t; } struct Tuple2(T...) { T t; } void main() { Tuple!(int,int) a; Tuple!(int,int) b; Tuple2!(int,int) c; assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b)) } In some other language: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : [Int,Int] assert(a == b); // ok assert(a != c); // ok Did you get it now? Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.One nasty thing about D's structs is that they don't have structural equivalence relation unlike tuples. So you need to use the same container struct type to get the same semantics. To achieve that you would need some kind of STuple on standard library level or other kinds of hacks. What I find unfortunate in D is that your abstractions come in two sizes - either you use the modest tiny construct that does not scale elegantly or the enormous hammer to crush things down theatretically.I don't understand very well what are you saying anyways...
Oct 20 2009
On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo bar.com.invalid> wrote:Tue, 20 Oct 2009 12:39:47 -0300, Leandro Lucarella thusly wrote:Or use a templated opAssign mixin to allow two desperate types to be assigned to each other. Besides, I think you're comparing apples to oranges. In the SOL example, you use the same declaration for all types. Shouldn't the SOL example be: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : MyCustomTupleType[Int,Int] which would probably generate: assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b))language_fan, el 20 de octubre a las 13:52 me escribiste:Pairs are pretty common actually. You might have applications that have mappings, functions, or zip (list operation) etc. I admit these are more common in functional languages but the main reason for this is that most mainstream languages do not support the Pair or Tuple types in any way. Even D has broken support (from this point of view).Tue, 20 Oct 2009 10:34:35 -0300, Leandro Lucarella thusly wrote:In what tradition? C++ maybe. I never saw a pair type outside C++, but saw tuples everywhere (even in other structured languages like SQL).dsimcha, el 20 de octubre a las 02:44 me escribiste:It depends on how you define things. Traditionally tuples are seen as a generalization of pairs (2 elements -> n elements). Records, on the other== Quote from Walter Bright (newshound1 digitalmars.com)'s articleIt would be the poor men tuple for returning (homogeneous) stuff =PCurrently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Vote++. It's funny, I use static arrays so little that I never realized that they weren't passed by value to functions. I'd absolutely love to be able to just return static arrays from functions, and often use structs to do that now, but using structs feels like a really ugly hack.Because of the unnecessary nominal typing in D's tuple emulation, redefinitions of Tuples do not have implicit equivalence relation: struct Tuple(T...) { T t; } struct Tuple2(T...) { T t; } void main() { Tuple!(int,int) a; Tuple!(int,int) b; Tuple2!(int,int) c; assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b)) } In some other language: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : [Int,Int] assert(a == b); // ok assert(a != c); // ok Did you get it now? Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.One nasty thing about D's structs is that they don't have structural equivalence relation unlike tuples. So you need to use the same container struct type to get the same semantics. To achieve that you would need some kind of STuple on standard library level or other kinds of hacks. What I find unfortunate in D is that your abstractions come in two sizes - either you use the modest tiny construct that does not scale elegantly or the enormous hammer to crush things down theatretically.I don't understand very well what are you saying anyways...
Oct 20 2009
Tue, 20 Oct 2009 16:25:05 -0400, Robert Jacques thusly wrote:On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo bar.com.invalid> wrote:Wow, you need templates to implement == for built-in values types, nice..Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.Or use a templated opAssign mixin to allow two desperate types to be assigned to each other.Besides, I think you're comparing apples to oranges. In the SOL example, you use the same declaration for all types. Shouldn't the SOL example be: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : MyCustomTupleType[Int,Int] which would probably generate: assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b))If you have built-in tuple literals, there is no way you can build a MyCustomTupleType without resorting to other language features. There are no apples and oranges, cause they both are seen as (Int,Int) by the equivalence checker. Do you understand how equivalence works in structural typing system (http://en.wikipedia.org/wiki/ Structural_type_system) vs nominal typing? In structural equivalence there are no names attached to the types (well there might be, but those are omitted in the comparison), only their internal structure matters. Why would anyone want to create two incompatible tuples by default as you still would have 'typedef' and 'struct' for implementing just that.
Oct 20 2009
On Wed, 21 Oct 2009 02:23:09 -0400, language_fan <foo bar.com.invalid> wrote:Tue, 20 Oct 2009 16:25:05 -0400, Robert Jacques thusly wrote:Unlike C++, D templates don't require a PhD to use. And it's definitely better that banging your head against the wall.On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo bar.com.invalid> wrote:Wow, you need templates to implement == for built-in values types, nice..Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.Or use a templated opAssign mixin to allow two desperate types to be assigned to each other.My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Besides, I think you're comparing apples to oranges. In the SOL example, you use the same declaration for all types. Shouldn't the SOL example be: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : MyCustomTupleType[Int,Int] which would probably generate: assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b))If you have built-in tuple literals, there is no way you can build a MyCustomTupleType without resorting to other language features. There are no apples and oranges, cause they both are seen as (Int,Int) by the equivalence checker. Do you understand how equivalence works in structural typing system (http://en.wikipedia.org/wiki/ Structural_type_system) vs nominal typing? In structural equivalence there are no names attached to the types (well there might be, but those are omitted in the comparison), only their internal structure matters. Why would anyone want to create two incompatible tuples by default as you still would have 'typedef' and 'struct' for implementing just that.
Oct 21 2009
Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:On Wed, 21 Oct 2009 02:23:09 -0400, language_fan <foo bar.com.invalid> wrote:Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work. I see opImplicitCast, introspection done with templates and all kinds of other voodoo to be ugly hacks. This is nothing more than one of the basic value types without any special semantics, for $deity's sake. If you like the hacky approach so much, why don't all built-in types (like static arrays etc.) use the same method? Implementation wise tuples are much simpler than D's arrays or AAs, still they are treated like some 2nd class citizen from some notorious 3rd world country. Why is it so damn hard to change the 90% correctly implemented built-in tuples to work like in any other tuple supporting language. Do you somehow fancy verbose syntax for C++ compatibility reasons (ah, the good old std::tr1::make_tuple<int, int>, makes me want to wank every time..) Try Ruby, try python, try *ML etc. They all somehow got it right.Tue, 20 Oct 2009 16:25:05 -0400, Robert Jacques thusly wrote:Unlike C++, D templates don't require a PhD to use. And it's definitely better that banging your head against the wall.On Tue, 20 Oct 2009 15:19:15 -0400, language_fan <foo bar.com.invalid> wrote:Wow, you need templates to implement == for built-in values types, nice..Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.Or use a templated opAssign mixin to allow two desperate types to be assigned to each other.My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Besides, I think you're comparing apples to oranges. In the SOL example, you use the same declaration for all types. Shouldn't the SOL example be: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : MyCustomTupleType[Int,Int] which would probably generate: assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b))If you have built-in tuple literals, there is no way you can build a MyCustomTupleType without resorting to other language features. There are no apples and oranges, cause they both are seen as (Int,Int) by the equivalence checker. Do you understand how equivalence works in structural typing system (http://en.wikipedia.org/wiki/ Structural_type_system) vs nominal typing? In structural equivalence there are no names attached to the types (well there might be, but those are omitted in the comparison), only their internal structure matters. Why would anyone want to create two incompatible tuples by default as you still would have 'typedef' and 'struct' for implementing just that.
Oct 21 2009
language_fan wrote:Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.I see opImplicitCast, introspection done with templates and all kinds of other voodoo to be ugly hacks. This is nothing more than one of the basic value types without any special semantics, for $deity's sake. If you like the hacky approach so much, why don't all built-in types (like static arrays etc.) use the same method? Implementation wise tuples are much simpler than D's arrays or AAs, still they are treated like some 2nd class citizen from some notorious 3rd world country.How and why are they treated badly?Why is it so damn hard to change the 90% correctly implemented built-in tuples to work like in any other tuple supporting language. Do you somehow fancy verbose syntax for C++ compatibility reasons (ah, the good old std::tr1::make_tuple<int, int>, makes me want to wank every time..) Try Ruby, try python, try *ML etc. They all somehow got it right.What exactly didn't D's tuples get right? Andrei
Oct 21 2009
On Wed, Oct 21, 2009 at 8:48 AM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:language_fan wrote:Well, auto-flattening is a colossally bad idea to be sure. --bbWed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.I see opImplicitCast, introspection done with templates and all kinds of other voodoo to be ugly hacks. This is nothing more than one of the basic value types without any special semantics, for $deity's sake. If you like the hacky approach so much, why don't all built-in types (like static arrays etc.) use the same method? Implementation wise tuples are much simpler than D's arrays or AAs, still they are treated like some 2nd class citizen from some notorious 3rd world country.How and why are they treated badly?Why is it so damn hard to change the 90% correctly implemented built-in tuples to work like in any other tuple supporting language. Do you somehow fancy verbose syntax for C++ compatibility reasons (ah, the good old std::tr1::make_tuple<int, int>, makes me want to wank every time..) Try Ruby, try python, try *ML etc. They all somehow got it right.What exactly didn't D's tuples get right?
Oct 21 2009
Bill Baxter wrote:Well, auto-flattening is a colossally bad idea to be sure.Well that I agree with. I wonder if we need to fix it for D2. If we don't, we risk to live with it like with a chronic cough. Andrei
Oct 21 2009
Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:language_fan wrote:Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague. I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.template Tuple(T...) { alias T Tuple; } struct STuple(T...) { T t; } void main() { Tuple!(int,int) a; // typeof(this) *is* the official tuple type STuple!(int,int) b; // this is actually a struct a = Tuple!(1,1); // ok // Tuple!(int,int) a2 = Tuple!(1,1); // WTF? Error: cannot implicitly convert expression (tuple(1,1)) of type (int, int) to int auto a3 = Tuple!(1,1); // ok b = STuple!(int,int)(1,1); // no easier way? make_tuple!(1,1) ? STuple!(int,int) b2 = STuple!(int,int)(1,1); // ok, but very verbose auto e1 = a[0]; // ok //auto e2 = b[0]; // nope auto e3 = b.t[0]; // this is how it works - you could possibly define opIndex but how would it work with different types then writefln("%s", a); // we get.. 1 !? but.. writefln("%s", typeof(a).stringof); // (int, int) writefln("%s", b); // STuple!(int,int)(1, 1) - rather verbose, but suffices //auto retTest() { return STuple!(int,int)(1,1); } // no identifier for declarator retTest STuple!(int,int) retTest2() { return STuple!(int,int)(1,1); }; // ok, but a bit too verbose int d,e; Tuple!(d,e) = Tuple!(10,20); // ok // but how to discard an unnecessary value? e.g. (a, _) = (1, 2) // Tuple!(d,e) = STuple!(10,20); // nope, not interchangeable // b = STuple!(a); // same here a = a; // ok b = b; // ok // a = b; // Error: a is not an lvalue -- interesting! Tuple!(d,b) = Tuple!(1, retTest2()); // awesome, with the Tuple I can even assign Tuples of STuples! //Tuple!(d,a) = Tuple!(1, a); // but Tuples don't help when assigning Tuples of Tuples //test.d(12): Error: expression _a_field_0 is not a valid template value argument //test.d(12): Error: expression _a_field_1 is not a valid template value argument //test.d(47): Error: template instance test.Tuple! (1,_a_field_0,_a_field_1) error instantiating // LET'S MAKE ARRAYS! int[] a1; // ok int[][] a2; // ok auto a1b = [1,2,3]; // ok auto a2b = [[1],[2],[3]]; // ok //Tuple!(int,int)[] a4; // Error: can't have array of (int, int) -- WHY NOT - it's simple, try e.g. ML STuple!(int,int)[] a5; // ok auto a3b = [Tuple!(1,1)]; // works, but hey did you know this is an array of ints! auto a4b = [STuple!(int,int)(1,1)]; // ok // int[Tuple!(int,int)] a6; // Error: can't have associative array key of (int, int) int[STuple!(int,int)] a7; // ok a7[STuple!(int,int)(1,1)] = 5; // ok Tuple!(int,Tuple!(int,int)) a8; // this isn't a (int, (int,int)) tuple - it's (int,int,int) ! STuple!(int,STuple!(int,int)) a9; // ok //auto a10 = [ Tuple!(1,1) : 2 ]; // Error: can't have associative array key of (int, int) -- Why did this work in array literal then?! auto a11 = [ STuple!(int,int)(1,1) : 2 ]; // ok alias Tuple!(int, 5) foo; // alias STuple!(int, 5) foo2; // parameters can only be types }STARTS HERE
Oct 21 2009
Wed, 21 Oct 2009 16:54:22 +0000, language_fan thusly wrote:Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:I forgot to say that you need two kinds of tuple "literals" in your standard library in D: one with value semantics, and one that is a wrapper around the alias tuple since auto-flattening happens.language_fan wrote:Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague. I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.
Oct 21 2009
language_fan wrote:Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:How do you know what "people" do?language_fan wrote:Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague.Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.Why do you define Tuple instead of using the standard std.typecons.tuple?template Tuple(T...) { alias T Tuple; }STARTS HEREstruct STuple(T...) { T t; }Why do you insist on defining another tuple type instead of using the one provided by the standard library?void main() { Tuple!(int,int) a; // typeof(this) *is* the official tuple type STuple!(int,int) b; // this is actually a struct a = Tuple!(1,1); // okThat doesn't work for me at all (with std.typecons.Tuple). I think there is confusion about a couple of things. One is that Tuple!(int, int) is a type that contains two ints, whereas Tuple!(1, 1) is a type that contains two compile-time integral values. So if you write: a = Tuple!(1, 1); that is as good syntactically as: a = int; which I hope you agree shouldn't quite go through. Write this: Tuple!(int,int) a; a = tuple(1, 1); or this: auto a = tuple(1, 1);// Tuple!(int,int) a2 = Tuple!(1,1); // WTF? Error: cannot implicitly convert expression (tuple(1,1)) of type (int, int) to intYeah, WTF that doesn't work either: int a2 = int;auto a3 = Tuple!(1,1); // okNot ok on my machine, nor it should be ok as this is also not ok: auto a3 = int;b = STuple!(int,int)(1,1); // no easier way? make_tuple!(1,1) ?Yeah try tuple(1, 1) in conjunction with std.typecons.Tuple.STuple!(int,int) b2 = STuple!(int,int)(1,1); // ok, but very verboseWell write this: auto stuple(T...)(T args) { return STuple!(T)(args); }auto e1 = a[0]; // okThis doesn't work because of a bug in the compiler, but this does with std.typecons.Tuple: auto e1 = a.field[0]; etc. etc. etc. I'm sure you make a couple of good points, but they are difficult to find. I suggest you peruse std.typecons.Tuple and submit any bugs you find to bugzilla. Andrei
Oct 21 2009
Wed, 21 Oct 2009 12:35:35 -0500, Andrei Alexandrescu thusly wrote:language_fan wrote:It might be if we use your definition of tuple. But the mighty compiler dmd 2.035 himself calls my types constructed with my templatevoid main() { Tuple!(int,int) a; // typeof(this) *is* the official tuple type STuple!(int,int) b; // this is actually a struct a = Tuple!(1,1); // okThat doesn't work for me at all (with std.typecons.Tuple). I think there is confusion about a couple of things. One is that Tuple!(int, int) is a type that contains two ints, whereas Tuple!(1, 1) is a type that contains two compile-time integral values. So if you write: a = Tuple!(1, 1); that is as good syntactically as: a = int;a tuple. How do you explain that? If the resulting type is tuple according to dmd, why do you think it is actually not. If it works like you say, why does this work then?template Tuple(T...) { alias T Tuple; }Here 'a' has a real runtime type (int,int) which is a runtime tuple according to dmd. And I assign a value to the tuple on runtime. I can even test it by printing the values a[0] and a[1] with writefln. So why didn't you just fix this particular tuple type and why did you come up with a library level hack? Show me a better way to achieve this with your tuple system.Tuple!(int,int) a; a = Tuple!(12,13);It's still not clear to me why you don't want to add full syntactic support for built-in tuples. Do you somehow find this kind of code difficult to read or maintain? (int,int) a = (1,1); int e1 = a[0]; writefln(a); (int,int) retTest() { return (1,1); } int d,e; (d,e) = (10,20); (d,_) = (10,20); (int,int) b; (d,b) = (1, retTest()); auto a3b = [ (1,1), (2,2) ]; auto a7 = [ (1,1) : 5 ]; auto a8 = [ 5 : (1,1)]; I want to know what is the rationale behind not accepting this semantics that is so widely used in other languages (and I very well mean the languages that *have* built-in tuple types).int d,e; Tuple!(d,e) = Tuple!(10,20);
Oct 21 2009
language_fan wrote:Wed, 21 Oct 2009 12:35:35 -0500, Andrei Alexandrescu thusly wrote:I don't understand what you are trying to accomplish. As far as I can tell you want to do this: Tuple!(int, int) a; a = tuple(12, 13); int x = a.field[0]; and similar things. I have no idea why you refuse to do it that way.language_fan wrote:It might be if we use your definition of tuple. But the mighty compiler dmd 2.035 himself calls my types constructed with my templatevoid main() { Tuple!(int,int) a; // typeof(this) *is* the official tuple type STuple!(int,int) b; // this is actually a struct a = Tuple!(1,1); // okThat doesn't work for me at all (with std.typecons.Tuple). I think there is confusion about a couple of things. One is that Tuple!(int, int) is a type that contains two ints, whereas Tuple!(1, 1) is a type that contains two compile-time integral values. So if you write: a = Tuple!(1, 1); that is as good syntactically as: a = int;a tuple. How do you explain that? If the resulting type is tuple according to dmd, why do you think it is actually not. If it works like you say, why does this work then?template Tuple(T...) { alias T Tuple; }Here 'a' has a real runtime type (int,int) which is a runtime tuple according to dmd. And I assign a value to the tuple on runtime. I can even test it by printing the values a[0] and a[1] with writefln. So why didn't you just fix this particular tuple type and why did you come up with a library level hack? Show me a better way to achieve this with your tuple system.Tuple!(int,int) a; a = Tuple!(12,13);To effect this, there'd first be a need to eliminate the current semantics of the comma operator. I probably find it as useless as the next guy, and don't take one second to buy into Walter's theory that it makes it easy to generate code (that may as well be his least convincing argument to date), but really there's two parts to your suggestion: (1) eliminate the comma operator, (2) make the comma operator work for tuples. I suspect there are some syntactical issues with (2). AndreiIt's still not clear to me why you don't want to add full syntactic support for built-in tuples. Do you somehow find this kind of code difficult to read or maintain? (int,int) a = (1,1); int e1 = a[0]; writefln(a); (int,int) retTest() { return (1,1); } int d,e; (d,e) = (10,20); (d,_) = (10,20); (int,int) b; (d,b) = (1, retTest()); auto a3b = [ (1,1), (2,2) ]; auto a7 = [ (1,1) : 5 ]; auto a8 = [ 5 : (1,1)]; I want to know what is the rationale behind not accepting this semantics that is so widely used in other languages (and I very well mean the languages that *have* built-in tuple types).int d,e; Tuple!(d,e) = Tuple!(10,20);
Oct 21 2009
Wed, 21 Oct 2009 13:41:50 -0500, Andrei Alexandrescu thusly wrote:I don't understand what you are trying to accomplish. As far as I can tell you want to do this: Tuple!(int, int) a; a = tuple(12, 13); int x = a.field[0];Not only that, but also this:int d,e; Tuple!(d,e) = Tuple!(10,20);and similar things. I have no idea why you refuse to do it that way.You somehow refuse to see that D has a tuple type which the compiler calls a tuple. Run 'strings /path/to/dmd|wc -l' and you'll see 28 instances of the word 'tuple'. If there was no built-in support, why does the executable contain the word then? Here..I did not mention the word tuple, but guess what dmd thinks. If it is not a tuple, why does dmd output 'tuple(_a_field_0,_a_field_1)'? Apparently this does not follow the math book definition of tuple nor is the traditional FPL tuple, but a special D flavor of tuple. Walter decided to build a tuple type, but something happened and he later started restricting its use (IIRC it *was* possible to create an array of these tuples, but now it is disallowed). What is left is a half-working mess mostly useful for compile time meta-programming. It works rather nicely there (except that the auto-flattening is sometimes rather annoying), but its operation is broken on runtime. You discarded this by stating that D does not have a tuple type, you just call it a 'type that contains two ints' in my example. DMD calls it a tuple (see .stringof, error messages etc.) I can see that you try to accomplish the same things with your library provided version of tuple. But if that is the recommended way of using tuples, why there is a bug riddled version in the compiler of the same type. It is extremely exhausting to implement a new compiler for D because the reference implementation is full of bugs I mentioned in previous posts and you cannot really tell how it should work.template Z(T...) { alias T Z; } Z!(int,int) a; pragma(msg,a.stringof);To effect this, there'd first be a need to eliminate the current semantics of the comma operator. I probably find it as useless as the next guy, and don't take one second to buy into Walter's theory that it makes it easy to generate code (that may as well be his least convincing argument to date), but really there's two parts to your suggestion: (1) eliminate the comma operator, (2) make the comma operator work for tuples. I suspect there are some syntactical issues with (2).I know that very well..
Oct 21 2009
language_fan wrote:You somehow refuse to see that D has a tuple type which the compiler calls a tuple.D has tuples, it doesn't have tuple literals. Tuple attempts to supplant that. Andrei
Oct 21 2009
On Wed, 21 Oct 2009 22:41:50 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:language_fan wrote:Well, he could just change the symbol used to denote comma operator to some other character (if he uses it so heavily internally), and don't expose it to a user. I don't use tuples a lot myself, but I would love to have multiple return types without some clumsy syntax. It's possible even now, but the syntax is a bit discouraging: Tuple!(int,float) foo() { return tuple(42, -1.0f); } make_tuple(a, b) = foo(); as opposed to: (int, float) foo() { return (42, -1.0f); } (a, b) = foo();Wed, 21 Oct 2009 12:35:35 -0500, Andrei Alexandrescu thusly wrote:I don't understand what you are trying to accomplish. As far as I can tell you want to do this: Tuple!(int, int) a; a = tuple(12, 13); int x = a.field[0]; and similar things. I have no idea why you refuse to do it that way.language_fan wrote:It might be if we use your definition of tuple. But the mighty compiler dmd 2.035 himself calls my types constructed with my templatevoid main() { Tuple!(int,int) a; // typeof(this) *is* the official tuple type STuple!(int,int) b; // this is actually a struct a = Tuple!(1,1); // okThat doesn't work for me at all (with std.typecons.Tuple). I think there is confusion about a couple of things. One is that Tuple!(int, int) is a type that contains two ints, whereas Tuple!(1, 1) is a type that contains two compile-time integral values. So if you write: a = Tuple!(1, 1); that is as good syntactically as: a = int;a tuple. How do you explain that? If the resulting type is tuple according to dmd, why do you think it is actually not. If it works like you say, why does this work then?template Tuple(T...) { alias T Tuple; }Here 'a' has a real runtime type (int,int) which is a runtime tuple according to dmd. And I assign a value to the tuple on runtime. I can even test it by printing the values a[0] and a[1] with writefln. So why didn't you just fix this particular tuple type and why did you come up with a library level hack? Show me a better way to achieve this with your tuple system.Tuple!(int,int) a; a = Tuple!(12,13);To effect this, there'd first be a need to eliminate the current semantics of the comma operator. I probably find it as useless as the next guy, and don't take one second to buy into Walter's theory that it makes it easy to generate code (that may as well be his least convincing argument to date), but really there's two parts to your suggestion: (1) eliminate the comma operator, (2) make the comma operator work for tuples. I suspect there are some syntactical issues with (2). AndreiIt's still not clear to me why you don't want to add full syntactic support for built-in tuples. Do you somehow find this kind of code difficult to read or maintain? (int,int) a = (1,1); int e1 = a[0]; writefln(a); (int,int) retTest() { return (1,1); } int d,e; (d,e) = (10,20); (d,_) = (10,20); (int,int) b; (d,b) = (1, retTest()); auto a3b = [ (1,1), (2,2) ]; auto a7 = [ (1,1) : 5 ]; auto a8 = [ 5 : (1,1)]; I want to know what is the rationale behind not accepting this semantics that is so widely used in other languages (and I very well mean the languages that *have* built-in tuple types).int d,e; Tuple!(d,e) = Tuple!(10,20);
Oct 21 2009
Denis Koroskin wrote:On Wed, 21 Oct 2009 22:41:50 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Or even: a, b = foo(); or a, _ = foo(); Works in Python (tm)language_fan wrote:Well, he could just change the symbol used to denote comma operator to some other character (if he uses it so heavily internally), and don't expose it to a user. I don't use tuples a lot myself, but I would love to have multiple return types without some clumsy syntax. It's possible even now, but the syntax is a bit discouraging: Tuple!(int,float) foo() { return tuple(42, -1.0f); } make_tuple(a, b) = foo(); as opposed to: (int, float) foo() { return (42, -1.0f); } (a, b) = foo();Wed, 21 Oct 2009 12:35:35 -0500, Andrei Alexandrescu thusly wrote:I don't understand what you are trying to accomplish. As far as I can tell you want to do this: Tuple!(int, int) a; a = tuple(12, 13); int x = a.field[0]; and similar things. I have no idea why you refuse to do it that way.language_fan wrote:It might be if we use your definition of tuple. But the mighty compiler dmd 2.035 himself calls my types constructed with my templatevoid main() { Tuple!(int,int) a; // typeof(this) *is* the official tuple type STuple!(int,int) b; // this is actually a struct a = Tuple!(1,1); // okThat doesn't work for me at all (with std.typecons.Tuple). I think there is confusion about a couple of things. One is that Tuple!(int, int) is a type that contains two ints, whereas Tuple!(1, 1) is a type that contains two compile-time integral values. So if you write: a = Tuple!(1, 1); that is as good syntactically as: a = int;a tuple. How do you explain that? If the resulting type is tuple according to dmd, why do you think it is actually not. If it works like you say, why does this work then?template Tuple(T...) { alias T Tuple; }Here 'a' has a real runtime type (int,int) which is a runtime tuple according to dmd. And I assign a value to the tuple on runtime. I can even test it by printing the values a[0] and a[1] with writefln. So why didn't you just fix this particular tuple type and why did you come up with a library level hack? Show me a better way to achieve this with your tuple system.Tuple!(int,int) a; a = Tuple!(12,13);To effect this, there'd first be a need to eliminate the current semantics of the comma operator. I probably find it as useless as the next guy, and don't take one second to buy into Walter's theory that it makes it easy to generate code (that may as well be his least convincing argument to date), but really there's two parts to your suggestion: (1) eliminate the comma operator, (2) make the comma operator work for tuples. I suspect there are some syntactical issues with (2). AndreiIt's still not clear to me why you don't want to add full syntactic support for built-in tuples. Do you somehow find this kind of code difficult to read or maintain? (int,int) a = (1,1); int e1 = a[0]; writefln(a); (int,int) retTest() { return (1,1); } int d,e; (d,e) = (10,20); (d,_) = (10,20); (int,int) b; (d,b) = (1, retTest()); auto a3b = [ (1,1), (2,2) ]; auto a7 = [ (1,1) : 5 ]; auto a8 = [ 5 : (1,1)]; I want to know what is the rationale behind not accepting this semantics that is so widely used in other languages (and I very well mean the languages that *have* built-in tuple types).int d,e; Tuple!(d,e) = Tuple!(10,20);
Oct 21 2009
grauzone, el 21 de octubre a las 22:12 me escribiste:Or even: a, b = foo(); or a, _ = foo(); Works in Python (tm)_ is a regular symbol (variable name in this case), there is nothing special about the second form, which is exactly the same as the first. And BTW, the trailing ; is not needed ;) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Hey you, standing in the aisles With itchy feet and fading smiles Can you feel me?
Oct 21 2009
Leandro Lucarella wrote:grauzone, el 21 de octubre a las 22:12 me escribiste:I didn't even know this. In Python, it doesn't matter anyway, because it is dynamically typed, and you can assign arbitrary values to the same variable. Apparently, writing foreach (index,_;something) in D isn't a special case either; it just declares a variable named _. Several nested loops using _ are not possible. PS: let's hope Walter recognizes the need of *good* syntax for a simple, basic language construct like tuples. Just look at language_fan's D code and compare it with the corresponding Python code posted afterward. The D code looks so ridiculous.Or even: a, b = foo(); or a, _ = foo(); Works in Python (tm)_ is a regular symbol (variable name in this case), there is nothing special about the second form, which is exactly the same as the first. AndBTW, the trailing ; is not needed ;)
Oct 21 2009
grauzone, el 21 de octubre a las 23:32 me escribiste:Leandro Lucarella wrote:Using _ is a bad idea if you use gettext though ;) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- El techo de mi cuarto lleno de estrellasgrauzone, el 21 de octubre a las 22:12 me escribiste:I didn't even know this. In Python, it doesn't matter anyway, because it is dynamically typed, and you can assign arbitrary values to the same variable. Apparently, writing foreach (index,_;something) in D isn't a special case either; it just declares a variable named _. Several nested loops using _ are not possible.Or even: a, b = foo(); or a, _ = foo(); Works in Python (tm)_ is a regular symbol (variable name in this case), there is nothing special about the second form, which is exactly the same as the first. And
Oct 21 2009
Wed, 21 Oct 2009 16:54:22 +0000, language_fan thusly wrote:Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:Even though not being an expert in Python (have not really used it), as an experiment I managed to successfully port the examples in 2 minutes without any kind of problems. a = (1,1) e1 = a[0] print a def retTest(): return (1,1) (d,e) = (10,20) (d,_) = (10,20) (d,b) = (1, retTest()) a3b = [ (1,1), (2,2) ] a7 = { (1,1) : 5 } a8 = { 5 : (1,1)}language_fan wrote:Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague. I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.STARTS HERE
Oct 21 2009
language_fan, el 21 de octubre a las 17:52 me escribiste:Wed, 21 Oct 2009 16:54:22 +0000, language_fan thusly wrote:I think this is an important point too. Maybe tuples are not *that* broken as stated in this thread, but they are quite more complex to understand than tuples in other languages, and they feel somehow hackish.Wed, 21 Oct 2009 10:48:34 -0500, Andrei Alexandrescu thusly wrote:Even though not being an expert in Python (have not really used it), as an experiment I managed to successfully port the examples in 2 minutes without any kind of problems.language_fan wrote:Using tuples in D is a major pain in the ass. In fact it has been made so hard that people start avoiding the feature like plague. I wrote some test code to reveal how inconsistent their semantics are. Note that you need the built-in tuples for some stuff, like assigning and mixed value/ type tuples. Stuples can only be used as values and when the auto- flattening is not desired.Wed, 21 Oct 2009 11:07:29 -0400, Robert Jacques thusly wrote:I'm late in this dialog, but I'm not seeing an impediment here. What does it matter to you that tuples actually have a name vs. not having a name at all?My issue was that all your example _showed_ was nominal typing. Though I didn't mention it by name, I did mention that if SOL tuples had structural typing, it might would be a different story. (Well, until/if opImplicitCast was implemented, as it would allow for structural typing.)Why do you insist on using nominal typing for tuples and the library defined "literal". If I want plain old tuples without any kind of type name, why should I care about extra hand waving needed to make it work.STARTS HEREa = (1,1) e1 = a[0] print a def retTest(): return (1,1) (d,e) = (10,20) (d,_) = (10,20) (d,b) = (1, retTest()) a3b = [ (1,1), (2,2) ] a7 = { (1,1) : 5 } a8 = { 5 : (1,1)}In python you can even do: def f(a, b, c): print a, b, c x = (b, c) I think this is only possible in D with type tuples, not with ... "value tuples"? That's part of the complexity, having 2 type of tuples is very confusing. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- You are the very reason why everything happens to you
Oct 21 2009
Leandro Lucarella:In python you can even do: def f(a, b, c): print a, b, c x = (b, c)In Python2.x you can also do: def foo(x, (y, (z1, z2))): print z2 print z1 print y print x Z = (1, 2) yz = [0, Z] foo(-1, yz) That outputs: 2 1 0 -1 Bye, bearophile
Oct 21 2009
language_fan, el 20 de octubre a las 19:19 me escribiste:Yes, thanks for the clarification.Because of the unnecessary nominal typing in D's tuple emulation, redefinitions of Tuples do not have implicit equivalence relation: struct Tuple(T...) { T t; } struct Tuple2(T...) { T t; } void main() { Tuple!(int,int) a; Tuple!(int,int) b; Tuple2!(int,int) c; assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b)) } In some other language: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : [Int,Int] assert(a == b); // ok assert(a != c); // ok Did you get it now?One nasty thing about D's structs is that they don't have structural equivalence relation unlike tuples. So you need to use the same container struct type to get the same semantics. To achieve that you would need some kind of STuple on standard library level or other kinds of hacks. What I find unfortunate in D is that your abstractions come in two sizes - either you use the modest tiny construct that does not scale elegantly or the enormous hammer to crush things down theatretically.I don't understand very well what are you saying anyways...Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.Yes, D support for tuples is way far from ideal. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- If you want to be alone, just be alone If you want to watch the sea, just watch the sea But do it now, timing is the answer, do it now Timing is the answer to success
Oct 20 2009
On Tue, 20 Oct 2009 20:38:33 -0400, Leandro Lucarella <llucax gmail.com> wrote:language_fan, el 20 de octubre a las 19:19 me escribiste:How so? I think this is merely the difference between a library type in a flexible language and a built-in type in an inflexible language. I mean the example was essentially: In D: Apple a Apple b Orange c assert(a != c); // Error: incompatible types Apple and Orange In SOL: Apple a Apple b Apple c assert(a != c); // ok, both a and c are apples. Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given. Now, the example was a good argument for making it easier and more natural to use the built-in tuple type. Adding syntaxtic sugar for tuples has been recommended before. I prefer using the slice syntax '..', as it would allow clean multi-dimensional slicing and mixed indexing and slicing, both of which are important to supporting arrays.Yes, thanks for the clarification.kindsOne nasty thing about D's structs is that they don't have structural equivalence relation unlike tuples. So you need to use the same container struct type to get the same semantics. To achieve that you would need some kind of STuple on standard library level or otherBecause of the unnecessary nominal typing in D's tuple emulation, redefinitions of Tuples do not have implicit equivalence relation: struct Tuple(T...) { T t; } struct Tuple2(T...) { T t; } void main() { Tuple!(int,int) a; Tuple!(int,int) b; Tuple2!(int,int) c; assert(a == b); // ok assert(a != c); // Error: incompatible types for ((a) != (b)) } In some other language: val a = (1,2) : [Int,Int] val b = (1,2) : [Int,Int] val c = (2,3) : [Int,Int] assert(a == b); // ok assert(a != c); // ok Did you get it now?of hacks. What I find unfortunate in D is that your abstractions come in two sizes - either you use the modest tiny construct that does not scale elegantly or the enormous hammer to crush things down theatretically.I don't understand very well what are you saying anyways...Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.Yes, D support for tuples is way far from ideal.
Oct 20 2009
Robert Jacques wrote:On Tue, 20 Oct 2009 20:38:33 -0400, Leandro Lucarella <llucax gmail.com> wrote:I also don't understand all the argument about structural vs. name equivalence. AndreiYes, D support for tuples is way far from ideal.How so? I think this is merely the difference between a library type in a flexible language and a built-in type in an inflexible language. I mean the example was essentially: In D: Apple a Apple b Orange c assert(a != c); // Error: incompatible types Apple and Orange In SOL: Apple a Apple b Apple c assert(a != c); // ok, both a and c are apples. Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.
Oct 20 2009
On Tue, 20 Oct 2009 22:45:53 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Robert Jacques wrote:The original thread stated that D's value tuples (as opposed to type tuples) were far from ideal, because it's not a built-in type. So two people could make value tuple structs types that were incompatible with each other. (One counter to this is it's simple to define a templated opAssgin method that works correctly. Another counter is to relate this problem to typedefs). My issue was with the example comparing D to some-other-language (SOL). The issue was that only the built-in value-tuple type in SOL was shown, and not a value-tuple interfacing with something else that wasn't the built-in value-tuple. This indicates that SOL isn't flexible/expressive enough to have library value-tuple-types, or the problems with D's value-tuple type solution.On Tue, 20 Oct 2009 20:38:33 -0400, Leandro Lucarella <llucax gmail.com> wrote:I also don't understand all the argument about structural vs. name equivalence. AndreiYes, D support for tuples is way far from ideal.How so? I think this is merely the difference between a library type in a flexible language and a built-in type in an inflexible language. I mean the example was essentially: In D: Apple a Apple b Orange c assert(a != c); // Error: incompatible types Apple and Orange In SOL: Apple a Apple b Apple c assert(a != c); // ok, both a and c are apples. Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.
Oct 20 2009
Robert Jacques, el 20 de octubre a las 21:06 me escribiste:I wasn't referring to this particular example, even when I agree this is not a big issue, is much more difficult to end up comparing Apples to Oranges if the language have support for tuple literals (like in the example). In D I think you might find yourself in this situation more often, but still rarely. I think tuple literals is an important thing to encourage people using tuples, specially when you want to support functional programming style.How so? I think this is merely the difference between a library type in a flexible language and a built-in type in an inflexible language. I mean the example was essentially: In D: Apple a Apple b Orange c assert(a != c); // Error: incompatible types Apple and Orange In SOL: Apple a Apple b Apple c assert(a != c); // ok, both a and c are apples.Real tuple types do not have a special type tag which gets injected implicitly with structs. So every time you try to do something lightweight by emulating tuples, you need to refer to the global Tuple type or bang your head to the wall.Yes, D support for tuples is way far from ideal.Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.Yes, that's another thing that can be done without real tuple support in the language. Anyway, I guess I was a little exaggerated with '*way far* from ideal', but I'm convinced there is plenty of room for improvements. =) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- FINALMENTE EL CABALLITO FABIAN VA A PASAR UNA BUENA NAVIDAD -- Crónica TV
Oct 20 2009
On Tue, 20 Oct 2009 23:30:48 -0400, Leandro Lucarella <llucax gmail.com> wrote:Robert Jacques, el 20 de octubre a las 21:06 me escribiste:Would you happen to know of a language which does tuples well already?Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.Yes, that's another thing that can be done without real tuple support in the language. Anyway, I guess I was a little exaggerated with '*way far* from ideal', but I'm convinced there is plenty of room for improvements. =)
Oct 20 2009
On 21/10/2009 05:48, Robert Jacques wrote:On Tue, 20 Oct 2009 23:30:48 -0400, Leandro Lucarella <llucax gmail.com> wrote:pick any functional language.. my favorite is MLRobert Jacques, el 20 de octubre a las 21:06 me escribiste:Would you happen to know of a language which does tuples well already?Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.Yes, that's another thing that can be done without real tuple support in the language. Anyway, I guess I was a little exaggerated with '*way far* from ideal', but I'm convinced there is plenty of room for improvements. =)
Oct 20 2009
Yigal Chripun, el 21 de octubre a las 07:18 me escribiste:On 21/10/2009 05:48, Robert Jacques wrote:Or Python ;) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- HACIA NEUQUEN: EL JUEVES SALDRA CARAVANA CON PERROS DESDE CAPITAL EN APOYO AL CACHORRO CONDENADO A MUERTE -- Crónica TVOn Tue, 20 Oct 2009 23:30:48 -0400, Leandro Lucarella <llucax gmail.com> wrote:pick any functional language.. my favorite is MLRobert Jacques, el 20 de octubre a las 21:06 me escribiste:Would you happen to know of a language which does tuples well already?Now, if SOL allowed tuples to do things you can't do today in D, like assign a tuple to a struct with the same signature, then this might be a point. But that wasn't the example given.Yes, that's another thing that can be done without real tuple support in the language. Anyway, I guess I was a little exaggerated with '*way far* from ideal', but I'm convinced there is plenty of room for improvements. =)
Oct 21 2009
Walter Bright wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)WOO! Thanks! :D
Oct 19 2009
Walter Bright wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Would that be D1&D2 or only D2?
Oct 19 2009
Saaa wrote:Would that be D1&D2 or only D2?D2 only, as it changes the behavior.
Oct 19 2009
On 20/10/2009 03:50, Walter Bright wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)that's good news :)
Oct 19 2009
Walter Bright:The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)If I have generic code, like a templated function, that accepts both a dynamic and a static array, the function call will change its performance signature according to the type (if I don't add a "ref" the pass of a dynamic array will be O(1) while passing a fixed-size array will be O(n)). I can accept your idea (and I can see other people here seem to accept it), but I'd like the function to receive the array by value if the array is small, and by reference if it's large (small and large are defined in terms of true bytes). This can be done automatically by the compiler, but this looks unsafe, because it's bad when the compiler changes the program semantics in an invisible way. So something explicit is better: void foo(bigref T[3] a) That syntax means that if (T[3]).sizeof is big enough then it's a ref argument, otherwise it's a value argument. But I think it's better to be able to somehow define that "bigref" in the standard library: void foo(Bigref!T[3] a) Andrei may like something like that. To do that "ref" may need to change its nature a little, becoming a kind of subtype that the user can define and use. I am ignorant about this, maybe T[3].REF can be the type of the reference to T[3], as T[3]* is the type of the pointer to a T[3]. If something like this is possible then that Bigref!() becomes just a template that contains a static if that according to the value of (T[3]).sizeof and some constant threshold value becomes an alias of T[3] or T[3].REF. Questions: 1) How can I allocate a fixed-size array on the heap? 2) Can such array allocated on the heap be return by "ref" from a function? (Or do I have to return it just by pointer)? 3) How can I implement and use a variable-length struct like this, that sometimes improves the performance of some code? struct S(T) { T cargo; int len; int[0]; } (variable-length structs can even grow in both ways, and the pointer that points to them has to point to their middle, to a field that contains two lengths, but such structs are are less common, so they may be ignored in this discussion). 4) LLVM, the backend of LDC, can map small array operations on SSE operations, so it can often perform the sum among two fixed-sized arrays of integers in a single asm instruction ad clock cycle. I'd like D to pass such semantics to the backend. We can discuss this later. Bye, bearophile
Oct 19 2009
== Quote from bearophile (bearophileHUGS lycos.com)'s articleWalter Bright:and a static array, the function call will change its performance signature according to the type (if I don't add a "ref" the pass of a dynamic array will be O(1) while passing a fixed-size array will be O(n)). Here's a way around that: To pass a static array by reference to a templated function that was written with generic ranges in mind, just slice it to make it a dynamic array: float[3] foo; pragma(msg, typeof(foo[]).stringof); // float[]The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)If I have generic code, like a templated function, that accepts both a dynamic
Oct 20 2009
Walter Bright wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)I think this change is mandatory. We need it for SIMD operations. It will allow us to implement efficient vectors.
Oct 20 2009
Don:I think this change is mandatory. We need it for SIMD operations.<Why? Why the compiler can't optimize things and perform SIMD operations with the fixed-sized array semantics of D1? (I ask this for LDC too, that's mostly D1 still). Bye, bearophile
Oct 20 2009
bearophile wrote:Don:Because they are passed by reference. It certainly can't do it on D1: float dot(float[4] x) { x[3] = 4.5; // surprise! return 0; } void main() { float[4] a; a[3]= 0; float x = dot(a); assert(a[3]==0); // FAILS! }I think this change is mandatory. We need it for SIMD operations.<Why? Why the compiler can't optimize things and perform SIMD operations with the fixed-sized array semantics of D1? (I ask this for LDC too, that's mostly D1 still). Bye, bearophile
Oct 20 2009
Walter Bright wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)I don't know why people are agreeing about this. At least I don't understand what the problem is with static arrays. You say: "Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays." But WHY??? What's the specific problem? I understand that passing things by value would solve this, but will hurt performance and it's not in sync with "arrays are passed by reference".
Oct 20 2009
Jason House Wrote:I've never heard the argument why they should be value types.Weren't they value types from the start? That's surprise. What do you think is memory layout of such array: int[3][] ? And what is memory layout of int[] ?
Oct 20 2009
Walter Bright Wrote:Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types.Nothing to agonize about really (except for C compatibility), they're value types and their behavior must be consistent.
Oct 20 2009
On Mon, 19 Oct 2009 18:50:46 -0700, Walter Bright <newshound1 digitalmars.com> wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)Hooah! I guess their .init value won't be fixed to be consistent with other types?
Oct 20 2009
On Mon, 19 Oct 2009 21:50:46 -0400, Walter Bright <newshound1 digitalmars.com> wrote:Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)What happens for IFTI? void foo(T)(T t) { return t[2]; } void main() { int[3] x; x[] = 5; printf(foo(x)); } I would think T would resolve to int[3], which means pass by value. You'd need a specialization for static arrays to get the current behavior. Don't get me wrong, I would love to see static arrays become real types, but I wonder if there are any ways we can "optimize out" the staticness of an array argument for templates. In particular, I hate how IFTI likes to assume static array for literals... In the absence of such an optimization, I'd still prefer static arrays become value types like you say. -Steve
Oct 20 2009
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s articleOn Mon, 19 Oct 2009 21:50:46 -0400, Walter Bright <newshound1 digitalmars.com> wrote:To me, static arrays are an optimization that you don't use unless you really need it. Dynamic arrays should be most programmers' "default" array type. If you insist on using static arrays, then the onus should be on you to make sure nothing like this happens by doing something like: print(foo(x[])); // Slice operator converts x into an int[], passed //the way dynamic arrays are. The what type are literals question, though, is a legit issue.Currently, static arrays are (as in C) half-value types and half-reference types. This tends to cause a series of weird problems and special cases in the language semantics, such as functions not being able to return static arrays, and out parameters not being possible to be static arrays. Andrei and I agonized over this for some time, and eventually came to the conclusion that static arrays should become value types. I.e., T[3] should behave much as if it were: struct ?? { T[3]; } Then it can be returned from a function. In particular, void foo(T[3] a) is currently done (as in C) by passing a pointer to the array, and then with a bit of compiler magic 'a' is rewritten as (*a)[3]. Making this change would mean that the entire array would be pushed onto the parameter stack, i.e. a copy of the array, rather than a reference to it. Making this change would clean up the internal behavior of types. They'll be more orthogonal and consistent, and templates will work better. The previous behavior for function parameters can be retained by making it a ref parameter: void foo(ref T[3] a)What happens for IFTI? void foo(T)(T t) { return t[2]; } void main() { int[3] x; x[] = 5; printf(foo(x)); } I would think T would resolve to int[3], which means pass by value. You'd need a specialization for static arrays to get the current behavior. Don't get me wrong, I would love to see static arrays become real types, but I wonder if there are any ways we can "optimize out" the staticness of an array argument for templates. In particular, I hate how IFTI likes to assume static array for literals... In the absence of such an optimization, I'd still prefer static arrays become value types like you say. -Steve
Oct 20 2009
Sorry for the late answer, I have missed your answer until now. dsimcha:Here's a way around that: To pass a static array by reference to a templated function that was written with generic ranges in mind, just slice it to make it a dynamic array: float[3] foo; pragma(msg, typeof(foo[]).stringof); // float[]Or you can also pass a pointer to the first item of the fixed-size array: bar(foo.ptr); This change (static arrays becoming value types) will make D less similar to C, so porting C code to D will be less easy (because if in the original C code an array is passed, now the code is slower, and changes to the array can't be seen outside of the function). I think as time passes, D may become less and less compatible with C (and this is has both advantages and disadvantages). A possible solution is to add a new kind of modules to D, the C-like ones, where semantics is kept closer to C (and where switch() has fall-through, etc). No one elase has commented that silly idea of the .ref I have shown. Maybe it's a wrong idea. Bye, bearophile
Oct 24 2009