digitalmars.D.learn - Is this a bug in std.typecons.Tuple.slice?
- Saurabh Das (47/47) Feb 04 2016 This code:
- Saurabh Das (19/21) Feb 04 2016 Update: Simplified, this also doesn't work:
- Marco Leise (6/34) Feb 04 2016 Yes this is a clear bug, I'll report a bug and post the issue
- Marco Leise (1/1) Feb 04 2016 https://issues.dlang.org/show_bug.cgi?id=15645
- Saurabh Das (4/5) Feb 04 2016 Thank you.
- Saurabh Das (44/45) Feb 04 2016 Is this a possible fixed implementation? :
- Saurabh Das (2/3) Feb 04 2016 PS: Additionally, '@trusted' can now be substituted with '@safe'.
- Saurabh Das (28/32) Feb 04 2016 On Friday, 5 February 2016 at 05:18:01 UTC, Saurabh Das wrote:
- Marco Leise (51/87) Feb 05 2016 That's quite concise. I like this. Though 'field' is now
- tsbockman (5/12) Feb 05 2016 Actually, it's not:
- Marco Leise (11/26) Feb 05 2016 I don't want to sound dismissive, but when that thought came
- tsbockman (14/21) Feb 05 2016 I'm not sure which approach is ultimately better, but aside from
- Marco Leise (28/51) Feb 06 2016 True.
- tsbockman (7/18) Feb 06 2016 Thank you for the example.
- tsbockman (15/26) Feb 06 2016 I think the key question is, do users care about being able to
- tsbockman (3/6) Feb 06 2016 I made a poll:
- Saurabh Das (9/39) Feb 06 2016 The PR definitely needs work - it was proposed to outline the
- tsbockman (6/9) Feb 08 2016 Although I wish more than 3 people had voted in my poll, two of
- Marco Leise (9/20) Feb 08 2016 As mentioned I never used the feature myself and wont vote
- tsbockman (9/13) Feb 09 2016 The mere fact that all I had to do to find people who use and
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/11) Feb 09 2016 I suggest lobbying for proper builtin tuple support. IMO one
- Marc =?UTF-8?B?U2Now7x0eg==?= (6/8) Feb 09 2016 No need to restrict the language here, there's nothing stopping a
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (8/12) Feb 09 2016 If you don't restrict the language people will write code that
- Marc =?UTF-8?B?U2Now7x0eg==?= (7/20) Feb 09 2016 So what? Using that argument, you could just as well forbid
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (12/20) Feb 09 2016 Some key common qualities for a tuple:
- Marc =?UTF-8?B?U2Now7x0eg==?= (14/36) Feb 09 2016 As you said, primarily. There's no reason not to use them for
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (14/27) Feb 09 2016 It does if you allow casting and to use tuples a types in
- tsbockman (7/8) Feb 09 2016 Built-in tuple support would be great (although to my mind,
- Saurabh Das (2/6) Feb 09 2016 +1
- tsbockman (10/11) Feb 06 2016 I should also point out that, since there is no way to actually
- Saurabh Das (10/21) Feb 06 2016 I think we should add a static assert to slice to ensure that the
- tsbockman (4/14) Feb 06 2016 If we pursue the deprecation route, I agree that this is a
- Marco Leise (10/28) Feb 06 2016 That would hurt the least, yes. It's more like a .dup with
- Saurabh Das (4/7) Feb 05 2016 That is enlightening. I have updated the PR at
This code: void main() { import std.typecons; auto tp = tuple!("a", "b", "c")(10, false, "hello"); auto u0 = tp.slice!(0, tp.length); auto u1 = tp.slice!(1, tp.length); auto u2 = tp.slice!(2, tp.length); static assert(is(typeof(u0) == Tuple!(int, "a", bool, "b", string, "c"))); static assert(is(typeof(u1) == Tuple!(bool, "b", string, "c"))); static assert(is(typeof(u2) == Tuple!(string, "c"))); assert(u2.c == "hello"); assert(u0.c == "hello"); assert(u1.c == "hello"); // This assert fails. Why? } core.exception.AssertError erasetype.d(16): Assertion failure ---------------- 4 erasetype 0x0000000100ce8128 _d_assert + 104 5 erasetype 0x0000000100cd12fe void erasetype.__assert(int) + 38 6 erasetype 0x0000000100cd12aa _Dmain + 250 7 erasetype 0x0000000100cf7297 D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv + 39 8 erasetype 0x0000000100cf71cf void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) + 55 9 erasetype 0x0000000100cf723c void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() + 44 10 erasetype 0x0000000100cf71cf void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) + 55 11 erasetype 0x0000000100cf7121 _d_run_main + 497 12 erasetype 0x0000000100cd133f main + 15 13 libdyld.dylib 0x00007fff8a1345c8 start + 0 14 ??? 0x0000000000000000 0x0 + 0 Why does 'u1' behave differently? I'm thinking it's a bug, but I haven't worked much with tuples, so maybe I'm missing something? Thanks, Saurabh
Feb 04 2016
On Thursday, 4 February 2016 at 12:28:39 UTC, Saurabh Das wrote:This code: [...]Update: Simplified, this also doesn't work: void main() { import std.typecons; auto tp = tuple(10, false, "hello"); auto u0 = tp.slice!(0, tp.length); auto u1 = tp.slice!(1, tp.length); auto u2 = tp.slice!(2, tp.length); static assert(is(typeof(u0) == Tuple!(int, bool, string))); static assert(is(typeof(u1) == Tuple!(bool, string))); static assert(is(typeof(u2) == Tuple!(string))); assert(u2[0] == "hello"); assert(u0[2] == "hello"); assert(u1[1] == "hello"); // This fails } rdmd erasetype.d core.exception.AssertError erasetype.d(16): Assertion failure Any ideas?
Feb 04 2016
Am Thu, 04 Feb 2016 15:17:54 +0000 schrieb Saurabh Das <saurabh.das gmail.com>:On Thursday, 4 February 2016 at 12:28:39 UTC, Saurabh Das wrote:Yes this is a clear bug, I'll report a bug and post the issue number later. -- MarcoThis code: [...]Update: Simplified, this also doesn't work: void main() { import std.typecons; auto tp = tuple(10, false, "hello"); auto u0 = tp.slice!(0, tp.length); auto u1 = tp.slice!(1, tp.length); auto u2 = tp.slice!(2, tp.length); static assert(is(typeof(u0) == Tuple!(int, bool, string))); static assert(is(typeof(u1) == Tuple!(bool, string))); static assert(is(typeof(u2) == Tuple!(string))); assert(u2[0] == "hello"); assert(u0[2] == "hello"); assert(u1[1] == "hello"); // This fails } rdmd erasetype.d core.exception.AssertError erasetype.d(16): Assertion failure Any ideas?
Feb 04 2016
On Thursday, 4 February 2016 at 17:52:16 UTC, Marco Leise wrote:https://issues.dlang.org/show_bug.cgi?id=15645Thank you. I understood why this is happening from your explanation in the bug report.
Feb 04 2016
On Thursday, 4 February 2016 at 17:52:16 UTC, Marco Leise wrote:https://issues.dlang.org/show_bug.cgi?id=15645Is this a possible fixed implementation? : property Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() trusted const if (from <= to && to <= Types.length) { auto sliceMixinGenerator() { string rv; for(auto i=from; i<to; ++i) { import std.conv : to; rv ~= "returnValue[" ~ (i-from).to!string ~ "]=field[" ~ i.to!string ~"];"; } return rv; } alias ReturnType = typeof(return); ReturnType returnValue; mixin(sliceMixinGenerator()); return returnValue; } /// unittest { Tuple!(int, string, float, double) a; a[1] = "abc"; a[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); Tuple!(int, int, long) b; b[1] = 42; b[2] = 101; auto t = b.slice!(1, 3); static assert(is(typeof(t) == Tuple!(int, long))); assert(t[0] == 42 && t[1] == 101); } I'm unsure about: 1. Removing 'ref' from the return type 2. Adding 'const' to the function signature 3. Is the new implementation less efficient for correctly aligned tuples?
Feb 04 2016
On Friday, 5 February 2016 at 05:18:01 UTC, Saurabh Das wrote:[...]PS: Additionally, ' trusted' can now be substituted with ' safe'.
Feb 04 2016
On Friday, 5 February 2016 at 05:18:01 UTC, Saurabh Das wrote: [...] Apologies for spamming. This is an improved implementation: property Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() safe const if (from <= to && to <= Types.length) { return typeof(return)(field[from .. to]); } /// unittest { Tuple!(int, string, float, double) a; a[1] = "abc"; a[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); Tuple!(int, int, long) b; b[1] = 42; b[2] = 101; auto t = b.slice!(1, 3); static assert(is(typeof(t) == Tuple!(int, long))); assert(t[0] == 42 && t[1] == 101); } These questions still remain:1. Removing 'ref' from the return type 2. Adding 'const' to the function signature 3. Is the new implementation less efficient for correctly aligned tuples?4. trusted -> safe?
Feb 04 2016
Am Fri, 05 Feb 2016 05:31:15 +0000 schrieb Saurabh Das <saurabh.das gmail.com>:On Friday, 5 February 2016 at 05:18:01 UTC, Saurabh Das wrote: [...] Apologies for spamming. This is an improved implementation: property Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() safe const if (from <= to && to <= Types.length) { return typeof(return)(field[from .. to]); } /// unittest { Tuple!(int, string, float, double) a; a[1] = "abc"; a[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); Tuple!(int, int, long) b; b[1] = 42; b[2] = 101; auto t = b.slice!(1, 3); static assert(is(typeof(t) == Tuple!(int, long))); assert(t[0] == 42 && t[1] == 101); }That's quite concise. I like this. Though 'field' is now called 'expand': // backwards compatibility alias field = expand;These questions still remain:Must happen. 'ref' only worked because of the reinterpreting cast which doesn't work in general. This will change the semantics. Now the caller of 'slice' will deal with a whole new copy of everything in the returned slice instead of a narrower view into the original data. But that's a needed change to fix the bug.1. Removing 'ref' from the return typeHmm. Since const is transitive this may add const to stuff that wasn't const, like in a Tuple!(Object). When you call const slice on that, you would get a Tuple!(const(Object)). I would use inout, making it so that the tuple's original constness is propagated to the result. I.e.: property inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() safe inout2. Adding 'const' to the function signatureYes, the previous one just added a compile-time known offset to the "this"-pointer. That's _one_ assembly instruction after inlining and optimization. The new one makes a copy of every field. On struct fields this can call the copy constructor "this(this)" which is used for example in reference counting to preform an increment for the copy. On "plain old data" it would simply copy the bit patterns. But that's obviously still less efficient than adding an offset to the pointer. You need two methods if you want to offer the best of both worlds. As soon as your function does not return a pointer or has 'ref' on it, the compiler will provide memory on the stack to hold the result and a copy will occur. That said, sufficiently smart compilers can analyze what's happening and come to the conclusion that when after the copy, the original is no longer used, they can be merged.3. Is the new implementation less efficient for correctly aligned tuples?4. trusted -> safe?Sounds good, but be aware of the mentioned implications with "this(this)". Copy constructors often need to do unsafe things, so safe here would disallow them in Tuples. On the other hand recent versions of the front-end should infer attributes for templates, so you can generally omit them and "let the Tuple decide". This mechanism also already adds nogc, pure, nothrow as possible in both the original and your implementation. (The original code only had trusted on it because the compiler would always infer the safety as system due to the pointer casts and system is close to intolerable for a "high-level" functional programming feature such as tuples. The other attributes should have been inferred correctly.) -- Marco
Feb 05 2016
On Friday, 5 February 2016 at 19:16:11 UTC, Marco Leise wrote:Actually, it's not: https://github.com/D-Programming-Language/phobos/pull/3973 All that is required is to include a little padding at the beginning of the slice struct to make the alignments match.Must happen. 'ref' only worked because of the reinterpreting cast which doesn't work in general. This will change the semantics. Now the caller of 'slice' will deal with a whole new copy of everything in the returned slice instead of a narrower view into the original data. But that's a needed change to fix the bug.1. Removing 'ref' from the return type
Feb 05 2016
Am Sat, 06 Feb 2016 04:28:17 +0000 schrieb tsbockman <thomas.bockman gmail.com>:On Friday, 5 February 2016 at 19:16:11 UTC, Marco Leise wrote:I don't want to sound dismissive, but when that thought came to my mind I considered it unacceptable that the type of Tuple!(int, bool, string).slice(1, 3) would be something different than Tuple!(bool, string). In your case Tuple!(TuplePad!4LU, bool, string). That's just a matter of least surprise when comparing the types. I'll let others decide, since I never used tuple slices. -- MarcoActually, it's not: https://github.com/D-Programming-Language/phobos/pull/3973 All that is required is to include a little padding at the beginning of the slice struct to make the alignments match.Must happen. 'ref' only worked because of the reinterpreting cast which doesn't work in general. This will change the semantics. Now the caller of 'slice' will deal with a whole new copy of everything in the returned slice instead of a narrower view into the original data. But that's a needed change to fix the bug.1. Removing 'ref' from the return type
Feb 05 2016
On Saturday, 6 February 2016 at 06:34:05 UTC, Marco Leise wrote:I don't want to sound dismissive, but when that thought came to my mind I considered it unacceptable that the type of Tuple!(int, bool, string).slice(1, 3) would be something different than Tuple!(bool, string). In your case Tuple!(TuplePad!4LU, bool, string). That's just a matter of least surprise when comparing the types. I'll let others decide, since I never used tuple slices.I'm not sure which approach is ultimately better, but aside from the performance implications, your "needed change" could break a lot of valid code in the wild - or it might break none; it really just depends on whether anyone actually *uses* the `ref`-ness of the `Tuple.slice` return type. (It appears that Phobos, at least, does not. But there is no guarantee that the rest of the world is using `Tuple` only in the ways that Phobos does.) Leaving aside bizarre meta-programming stuff (because then *anything* is a breaking change), my PR does not break any code, except that which was already broken: the type of the slice is only different in those cases where it *has* to be, for alignment reasons; otherwise it remains the same as it was before.
Feb 05 2016
Am Sat, 06 Feb 2016 07:57:08 +0000 schrieb tsbockman <thomas.bockman gmail.com>:On Saturday, 6 February 2016 at 06:34:05 UTC, Marco Leise wrote:True.I don't want to sound dismissive, but when that thought came to my mind I considered it unacceptable that the type of Tuple!(int, bool, string).slice(1, 3) would be something different than Tuple!(bool, string). In your case Tuple!(TuplePad!4LU, bool, string). That's just a matter of least surprise when comparing the types. I'll let others decide, since I never used tuple slices.I'm not sure which approach is ultimately better, but aside from the performance implications, your "needed change" could break a lot of valid code in the wild - or it might break none; it really just depends on whether anyone actually *uses* the `ref`-ness of the `Tuple.slice` return type.(It appears that Phobos, at least, does not. But there is no guarantee that the rest of the world is using `Tuple` only in the ways that Phobos does.) Leaving aside bizarre meta-programming stuff (because then *anything* is a breaking change), my PR does not break any code, except that which was already broken: the type of the slice is only different in those cases where it *has* to be, for alignment reasons; otherwise it remains the same as it was before.I understand that. We just have a different perspective on the problem. Your priorities: - don't break what's not broken - .slice! lends on opSlice and should return by ref My priorities: - type of .slice! should be as if constructing with same values from scratch - keep code additions in Phobos to a minimum Why do I insist on the return type? Because surprisingly simple code breaks if it doesn't match. Not everything can be covered by runtime conversions in D. It still took me a while to come up with something obvious: uint[Tuple!(uint, ulong)] hash; auto tup = tuple(1u, 2u, 3UL); hash[tup.slice!(1, 3)] = tup[0]; compiles? works? original Tuple : yes no Saurabh Das changes: yes yes your changes : no no What I like most about your proposal is that it doesn't break any existing code that wasn't broken before. That can't be emphasized enough. -- Marco
Feb 06 2016
On Sunday, 7 February 2016 at 02:11:15 UTC, Marco Leise wrote:Why do I insist on the return type? Because surprisingly simple code breaks if it doesn't match. Not everything can be covered by runtime conversions in D. It still took me a while to come up with something obvious: uint[Tuple!(uint, ulong)] hash; auto tup = tuple(1u, 2u, 3UL); hash[tup.slice!(1, 3)] = tup[0]; compiles? works? original Tuple : yes no Saurabh Das changes: yes yes your changes : no noThank you for the example. If multiple alias this ever makes it into the language (see https://wiki.dlang.org/DIP66 and https://github.com/D-Programming-Language/dmd/pull/3998), this could be fixed quite easily. But, I do not see any way to fix it with the tools currently available.
Feb 06 2016
On Sunday, 7 February 2016 at 02:11:15 UTC, Marco Leise wrote:I understand that. We just have a different perspective on the problem. Your priorities: - don't break what's not broken - .slice! lends on opSlice and should return by ref My priorities: - type of .slice! should be as if constructing with same values from scratch - keep code additions in Phobos to a minimum Why do I insist on the return type? Because surprisingly simple code breaks if it doesn't match. Not everything can be covered by runtime conversions in D.I think the key question is, do users care about being able to modify the original `Tuple` instance indirectly through `slice`? If yes, then the only workable solutions I can see are: 1) My current proposal (insert a hidden padding member at the beginning of the slice `Tuple`) 2) Don't return a `Tuple` at all - return a dedicated `TupleSlice` type that is implicitly convertible to `Tuple`. This approach would work with the example you came up with, but implementing `TupleSlice` well could be very complex, I think. If not, then I have no fundamental objection to Saurabh Das' approach, although I think the PR needs work. We should start a new thread in "General" to ask whether people care about the `ref`-ness of `Tuple` slices is really the deciding factor.
Feb 06 2016
On Sunday, 7 February 2016 at 02:51:49 UTC, tsbockman wrote:We should start a new thread in "General" to ask whether people care about the `ref`-ness of `Tuple` slices is really the deciding factor.I made a poll: http://forum.dlang.org/post/inswmiscuqirkhfqlhtd forum.dlang.org
Feb 06 2016
On Sunday, 7 February 2016 at 02:51:49 UTC, tsbockman wrote:On Sunday, 7 February 2016 at 02:11:15 UTC, Marco Leise wrote:The PR definitely needs work - it was proposed to outline the direction. I haven't worked at all on Phobos and I am not yet knowledgeable on writing library-quality code in D. I'm hoping to contribute back to Phobos this year - so pointing out as many flaws will help learn faster :) In particular - the inout problem in the PR - I'm not sure yet on how to fix that. Thanks, SaurabhI understand that. We just have a different perspective on the problem. Your priorities: - don't break what's not broken - .slice! lends on opSlice and should return by ref My priorities: - type of .slice! should be as if constructing with same values from scratch - keep code additions in Phobos to a minimum Why do I insist on the return type? Because surprisingly simple code breaks if it doesn't match. Not everything can be covered by runtime conversions in D.I think the key question is, do users care about being able to modify the original `Tuple` instance indirectly through `slice`? If yes, then the only workable solutions I can see are: 1) My current proposal (insert a hidden padding member at the beginning of the slice `Tuple`) 2) Don't return a `Tuple` at all - return a dedicated `TupleSlice` type that is implicitly convertible to `Tuple`. This approach would work with the example you came up with, but implementing `TupleSlice` well could be very complex, I think. If not, then I have no fundamental objection to Saurabh Das' approach, although I think the PR needs work.We should start a new thread in "General" to ask whether people care about the `ref`-ness of `Tuple` slices is really the deciding factor.
Feb 06 2016
On Sunday, 7 February 2016 at 02:11:15 UTC, Marco Leise wrote:What I like most about your proposal is that it doesn't break any existing code that wasn't broken before. That can't be emphasized enough.Although I wish more than 3 people had voted in my poll, two of them did claim to need the `ref`-ness of `Tuple.slice`, so I don't think we can just ditch it. (I did not vote.) If you guys want to add a return-by-value version, it should be treated as an enhancement, not a bug fix in my opinion.
Feb 08 2016
Am Tue, 09 Feb 2016 00:38:10 +0000 schrieb tsbockman <thomas.bockman gmail.com>:On Sunday, 7 February 2016 at 02:11:15 UTC, Marco Leise wrote:As mentioned I never used the feature myself and wont vote for one or the other. Three people with no source code to exemplify current use of .slice! is indeed not much to base decisions on and both fixes yield unexpected results in different contexts that warrant bug reports. -- MarcoWhat I like most about your proposal is that it doesn't break any existing code that wasn't broken before. That can't be emphasized enough.Although I wish more than 3 people had voted in my poll, two of them did claim to need the `ref`-ness of `Tuple.slice`, so I don't think we can just ditch it. (I did not vote.) If you guys want to add a return-by-value version, it should be treated as an enhancement, not a bug fix in my opinion.
Feb 08 2016
On Tuesday, 9 February 2016 at 06:22:55 UTC, Marco Leise wrote:As mentioned I never used the feature myself and wont vote for one or the other. Three people with no source code to exemplify current use of .slice! is indeed not much to base decisions on...The mere fact that all I had to do to find people who use and care about the `ref`-ness of `Tuple.slice` was ask, and then wait a few hours, strongly suggests that there are other such people among the D user base. When faced with a judgment call like this, we really ought to err on the side of maintaining backwards compatibility - especially since this does not preclude adding a separate by-value version of `Tuple.slice`, as well. It was going to need a new name anyway.
Feb 09 2016
On Tuesday, 9 February 2016 at 08:35:21 UTC, tsbockman wrote:When faced with a judgment call like this, we really ought to err on the side of maintaining backwards compatibility - especially since this does not preclude adding a separate by-value version of `Tuple.slice`, as well. It was going to need a new name anyway.I suggest lobbying for proper builtin tuple support. IMO one shouldn't be able to take the reference of a tuple, to ensure that it can be kept in registers. Modern desktop CPUs have maybe 512 bytes of register space. In most cases a tuple will be within 8 bytes * 16 or something like that.
Feb 09 2016
On Tuesday, 9 February 2016 at 09:05:58 UTC, Ola Fosheim Grøstad wrote:IMO one shouldn't be able to take the reference of a tuple, to ensure that it can be kept in registers.No need to restrict the language here, there's nothing stopping a decent compiler from storing tuples (actually _anything_) in registers, in some cases even if references are taken. I'm pretty sure LLVM can handle this.
Feb 09 2016
On Tuesday, 9 February 2016 at 10:54:42 UTC, Marc Schütz wrote:No need to restrict the language here, there's nothing stopping a decent compiler from storing tuples (actually _anything_) in registers, in some cases even if references are taken. I'm pretty sure LLVM can handle this.If you don't restrict the language people will write code that the optimizer will struggle with. LLVM can only handle what goes on within a compilation unit, and not if there are stores, because those are visible in other threads. Tuples should be considered immutable constants (think functional programming), not in-memory storage. Tuple's can serve as a good approximation to SIMD registers.
Feb 09 2016
On Tuesday, 9 February 2016 at 11:38:14 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 9 February 2016 at 10:54:42 UTC, Marc Schütz wrote:So what? Using that argument, you could just as well forbid taking the address of any variable. What's so special about tuples, in contrast to structs and arrays?No need to restrict the language here, there's nothing stopping a decent compiler from storing tuples (actually _anything_) in registers, in some cases even if references are taken. I'm pretty sure LLVM can handle this.If you don't restrict the language people will write code that the optimizer will struggle with.LLVM can only handle what goes on within a compilation unit, and not if there are stores, because those are visible in other threads. Tuples should be considered immutable constants (think functional programming), not in-memory storage.Again, why?Tuple's can serve as a good approximation to SIMD registers.What relation does that have to the above?
Feb 09 2016
On Tuesday, 9 February 2016 at 13:43:16 UTC, Marc Schütz wrote:So what? Using that argument, you could just as well forbid taking the address of any variable. What's so special about tuples, in contrast to structs and arrays?Some key common qualities for a tuple: 1. They are primarily used for multiple return values from functions. 2. Tuples use structural typing, not nominal typing. 3. They are identity-less. If you can take reference and compare, they no longer are identity-less.Because that is how a tuple is commonly defined, for performance and semantic reasons.Tuples should be considered immutable constants (think functional programming), not in-memory storage.Again, why?You don't want to spill out SIMD registers to the stack if you can avoid it. You want to do the changes within the CPU pipeline, i.e. using copies (and register renaming).Tuple's can serve as a good approximation to SIMD registers.What relation does that have to the above?
Feb 09 2016
On Tuesday, 9 February 2016 at 14:28:35 UTC, Ola Fosheim Grøstad wrote:On Tuesday, 9 February 2016 at 13:43:16 UTC, Marc Schütz wrote:As you said, primarily. There's no reason not to use them for something else.So what? Using that argument, you could just as well forbid taking the address of any variable. What's so special about tuples, in contrast to structs and arrays?Some key common qualities for a tuple: 1. They are primarily used for multiple return values from functions.2. Tuples use structural typing, not nominal typing.This has no relevance for the question at hand.3. They are identity-less. If you can take reference and compare, they no longer are identity-less.Like value types in general, nothing special about tuples here.I believe it's more because the concept is more frequently used in functional programming languages, for which immutability is not surprising. Other languages do have mutable tuples, e.g. Swift and C++11 (std::tuple).Because that is how a tuple is commonly defined, for performance and semantic reasons.Tuples should be considered immutable constants (think functional programming), not in-memory storage.Again, why?As said above, wanting to avoid spilling is not a reason to disallow spilling. Besides, fixed-size arrays seem more similar to SIMD registers, and they don't have the restrictions you tuples to have.You don't want to spill out SIMD registers to the stack if you can avoid it. You want to do the changes within the CPU pipeline, i.e. using copies (and register renaming).Tuple's can serve as a good approximation to SIMD registers.What relation does that have to the above?
Feb 09 2016
On Tuesday, 9 February 2016 at 16:00:09 UTC, Marc Schütz wrote:It does if you allow casting and to use tuples a types in aggregates. The language becomes less strongly typed.2. Tuples use structural typing, not nominal typing.This has no relevance for the question at hand.I don't know what you mean by that. D doesn't provide proper value types. If you can compare identities (address) then it is not a value, but an object.3. They are identity-less. If you can take reference and compare, they no longer are identity-less.Like value types in general, nothing special about tuples here.I believe it's more because the concept is more frequently used in functional programming languages, for which immutability is not surprising. Other languages do have mutable tuples, e.g. Swift and C++11 (std::tuple).C++ doesn't have real tuples. I don't know the details of Swift regarding tuples, but Swift is an OO language that does not aim for high performance or very strong typing.As said above, wanting to avoid spilling is not a reason to disallow spilling. Besides, fixed-size arrays seem more similar to SIMD registers, and they don't have the restrictions you tuples to have.Well, I disagree. There is very little reason to encourage people to use tuples for storage, you end up with a weaker typed language and less performant code. (You can do various types of packing in registers too, depends on the CPU.)
Feb 09 2016
On Tuesday, 9 February 2016 at 09:05:58 UTC, Ola Fosheim Grøstad wrote:I suggest lobbying for proper builtin tuple support.Built-in tuple support would be great (although to my mind, mostly because the current syntax is clunky). But that is a long-term goal, and `Tuple.slice` is corrupting data *right now*. Some sort of short-term fix should be merged in the next release of D.
Feb 09 2016
On Wednesday, 10 February 2016 at 00:24:56 UTC, tsbockman wrote:[...] `Tuple.slice` is corrupting data *right now*. Some sort of short-term fix should be merged in the next release of D.+1
Feb 09 2016
On Saturday, 6 February 2016 at 06:34:05 UTC, Marco Leise wrote:[...]I should also point out that, since there is no way to actually find out whether anyone is using the `ref`-ness of the return type in the wild, the approach that you and Saurabh Das are taking really ought to include changing the symbol name and deprecating the old one. Otherwise you could introduce subtle bugs into previously valid code; not every significant effect of removing `ref` will cause an error message at compile time *or* run time - some will just silently change the behaviour of the program, which is awful.
Feb 06 2016
On Saturday, 6 February 2016 at 08:01:20 UTC, tsbockman wrote:On Saturday, 6 February 2016 at 06:34:05 UTC, Marco Leise wrote:I think we should add a static assert to slice to ensure that the current implementation is not used in a case where the alignment doesn't match. This is better than failing without any warning. We could add new (differently named) functions for slicing non-aligned tuples. I agree that my approach of removing the ref may break existing code, so if introduced, it should be named differently. I am not comfortable with tuple(42, true, "abc").slice(1, 3) being different in type from tuple(true, " abc").[...]I should also point out that, since there is no way to actually find out whether anyone is using the `ref`-ness of the return type in the wild, the approach that you and Saurabh Das are taking really ought to include changing the symbol name and deprecating the old one. Otherwise you could introduce subtle bugs into previously valid code; not every significant effect of removing `ref` will cause an error message at compile time *or* run time - some will just silently change the behaviour of the program, which is awful.
Feb 06 2016
On Saturday, 6 February 2016 at 08:47:01 UTC, Saurabh Das wrote:I think we should add a static assert to slice to ensure that the current implementation is not used in a case where the alignment doesn't match. This is better than failing without any warning.If we pursue the deprecation route, I agree that this is a necessary step.We could add new (differently named) functions for slicing non-aligned tuples. I agree that my approach of removing the ref may break existing code, so if introduced, it should be named differently. I am not comfortable with tuple(42, true, "abc").slice(1, 3) being different in type from tuple(true, " abc").Why? What practical problem does this cause?
Feb 06 2016
Am Sat, 06 Feb 2016 11:02:37 +0000 schrieb tsbockman <thomas.bockman gmail.com>:On Saturday, 6 February 2016 at 08:47:01 UTC, Saurabh Das wrote:That would hurt the least, yes. It's more like a .dup with start and end parameter then.I think we should add a static assert to slice to ensure that the current implementation is not used in a case where the alignment doesn't match. This is better than failing without any warning.If we pursue the deprecation route, I agree that this is a necessary step.For me it is mostly a gut feeling. Historically types mimicking other types have often evoked trouble for example in generic functions or concretely - if you look at my other post - in D's AA implementation. -- MarcoWe could add new (differently named) functions for slicing non-aligned tuples. I agree that my approach of removing the ref may break existing code, so if introduced, it should be named differently. I am not comfortable with tuple(42, true, "abc").slice(1, 3) being different in type from tuple(true, " abc").Why? What practical problem does this cause?
Feb 06 2016
On Friday, 5 February 2016 at 19:16:11 UTC, Marco Leise wrote:Am Fri, 05 Feb 2016 05:31:15 +0000 schrieb Saurabh Das <saurabh.das gmail.com>: [...]That is enlightening. I have updated the PR at https://github.com/D-Programming-Language/phobos/pull/3975 to incorporate these changes.
Feb 05 2016