March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| On 13 March 2012 06:45, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>wrote: > You see, at this point I have no idea what to believe anymore. You argued very strongly from the position of one whose life depends on efficiency. Here and there you'd mix some remark about syntax, and I'd like "whaa?..." but generally discounted it as distraction from the main point, which was that all you must do is f(g()) where the body of g() is insignificantly small, which makes the cost of passing arguments around absolutely paramount. > > And now you come with this completely opposite viewpoint in which the syntax is paramount and urgent, whereas codegen is like let's leave it for later. I really am confused. Okay sorry, let me clarify. My own personal stance is unchanged, but I appreciate your assertion of priorities and I relent :) This topic has meandered between 2 distinct threads, syntax and abi, and I feel strongly about both, so maybe my personal sense of priority comes across wrong as I'm discussing one topic or the other. Trying to see it from a practicality standpoint, there is a pull request there which would seem like a near-complete implementation of the syntax, so that's a much easier/smaller step than messing with the ABI. Also, the syntax element of the feature will benefit far more people, and more immediately. Note, I still find myself wanting this feature, at least syntactically, every other day (my motivation starting the thread initially). But for my purposes (simd math library currently) it wouldn't do for it to be inefficient. At least the promise of an efficient implementation down the road is needed to make use of it. I think I feel a sense of urgency towards the ABI aspect because it is a breaking change, and I suspect the longer anything like that is left, the less likely/more risky it becomes. If it gets delayed for 6-12 months, are you honestly more or less likely to say it's a good idea to fiddle with the ABI? I am sold on the Tuple approach now, so that's a big discussion that can be dismissed. I think it was as a result of realising this that the ABI became of higher importance in my mind, since I agree, workable syntax is technically possible already (although ugly/verbose). You don't see the immediate value in a convenient MRV syntax? It would >> improve code clarity in many places, and allow the code to also be more efficient down the road. >> > > I see value in Kenji's related diff, but not in adding syntax to e.g. return "(int, int)". But we want to make sure we address the matter holistically (for example: is Kenji's diff enough, or do we need to worry about assignment too?). The worst strategy in chess is to move a piece and then start analyzing the new situation on the board. > Shall we discuss the shortcomings of his implementation? Can someone demonstrate the details of his implementation? >From the little examples up in the thread, it looked like you could only declare new variables inline, but not assign out to existing ones. I'd say this needs to be added too, and perhaps that will throw the whole design into turmoil? ;) |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
On 13 March 2012 09:12, Manu <turkeyman@gmail.com> wrote: > On 13 March 2012 06:45, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: >> >> You see, at this point I have no idea what to believe anymore. You argued very strongly from the position of one whose life depends on efficiency. Here and there you'd mix some remark about syntax, and I'd like "whaa?..." but generally discounted it as distraction from the main point, which was that all you must do is f(g()) where the body of g() is insignificantly small, which makes the cost of passing arguments around absolutely paramount. >> >> And now you come with this completely opposite viewpoint in which the syntax is paramount and urgent, whereas codegen is like let's leave it for later. I really am confused. > > > Okay sorry, let me clarify. My own personal stance is unchanged, but I > appreciate your assertion of priorities and I relent :) > This topic has meandered between 2 distinct threads, syntax and abi, and I > feel strongly about both, so maybe my personal sense of priority comes > across wrong as I'm discussing one topic or the other. > > Trying to see it from a practicality standpoint, there is a pull request > there which would seem like a near-complete implementation of the syntax, so > that's a much easier/smaller step than messing with the ABI. Also, the > syntax element of the feature will benefit far more people, and more > immediately. > Note, I still find myself wanting this feature, at least syntactically, > every other day (my motivation starting the thread initially). But for my > purposes (simd math library currently) it wouldn't do for it to be > inefficient. At least the promise of an efficient implementation down the > road is needed to make use of it. > > I think I feel a sense of urgency towards the ABI aspect because it is a > breaking change, and I suspect the longer anything like that is left, the > less likely/more risky it becomes. > If it gets delayed for 6-12 months, are you honestly more or less likely to > say it's a good idea to fiddle with the ABI? > > I am sold on the Tuple approach now, so that's a big discussion that can be dismissed. I think it was as a result of realising this that the ABI became of higher importance in my mind, since I agree, workable syntax is technically possible already (although ugly/verbose). > > What about alternative optimisations for MRV, rather than stating that it should always be returned in registers where possible (and breaking ABI on all target platforms). What about, for example, using named return value optimisation in this case to help improve the cost of returning on non-x86 architectures. Just throwing random thoughts out there. -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Attachments:
| On 13 March 2012 13:27, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> What about alternative optimisations for MRV, rather than stating that it should always be returned in registers where possible (and breaking ABI on all target platforms). What about, for example, using named return value optimisation in this case to help improve the cost of returning on non-x86 architectures.
>
> Just throwing random thoughts out there.
>
What difference would that actually make? The effect is still the same,
unless perhaps you were returning directly into some output structure, that
might be a win in that case (but that's the opposite of what MRV is
actually for).
Definitely no good for slices, and it doesn't help calls, only returns.
The non-x86 platforms don't only suffer from return values, they suffer passing TO functions as well. So currently they take the hit on both sides. Slices are fundamental to the language feature, they need to be efficient :/
|
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 3/13/12 4:12 AM, Manu wrote: > I think I feel a sense of urgency towards the ABI aspect because it is a > breaking change, and I suspect the longer anything like that is left, > the less likely/more risky it becomes. > If it gets delayed for 6-12 months, are you honestly more or less likely > to say it's a good idea to fiddle with the ABI? I think Walter could answer that. > I am sold on the Tuple approach now, so that's a big discussion that can > be dismissed. Great! > Shall we discuss the shortcomings of his implementation? Can someone > demonstrate the details of his implementation? > From the little examples up in the thread, it looked like you could > only declare new variables inline, but not assign out to existing ones. > I'd say this needs to be added too, and perhaps that will throw the > whole design into turmoil? ;) I thought more about it and we should be fine with two functions (untested): enum Skip {}; @property ref Skip skip() { static __gshared Skip result; return result; } void scatter(T, U...)(auto ref T source, ref U targets) { assert(source.length == targets.length); foreach (i, ref target; targets) { static if (is(typeof(target) != Skip)) { target = source[i]; } } } void gather(T, U...)(ref T target, auto ref U sources) { assert(target.length == sources.length); foreach (i, source; sources) { static if (is(typeof(source) != Skip)) { target[i] = source; } } } Usage: auto t = tuple(1, "hi", 2.3); int a; string b; double c; t.scatter(a, b, skip); // assigns a and b from tuple b = "!"; ++c; t.gather(skip, b, c); // assigns tuple from variables b and c Andrei |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| On 13 March 2012 16:44, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>wrote: > I thought more about it and we should be fine with two functions > (untested): > > enum Skip {}; > @property ref Skip skip() { > static __gshared Skip result; > return result; > } > > void scatter(T, U...)(auto ref T source, ref U targets) { > assert(source.length == targets.length); > foreach (i, ref target; targets) { > static if (is(typeof(target) != Skip)) { > target = source[i]; > } > } > } > > void gather(T, U...)(ref T target, auto ref U sources) { > assert(target.length == sources.length); > foreach (i, source; sources) { > static if (is(typeof(source) != Skip)) { > target[i] = source; > } > } > } > > Usage: > > auto t = tuple(1, "hi", 2.3); > int a; > string b; > double c; > t.scatter(a, b, skip); // assigns a and b from tuple > b = "!"; > ++c; > t.gather(skip, b, c); // assigns tuple from variables b and c Well, that 'works' :) .. Is that a proposal for a 'final' syntax, or something to work with in the mean time? I said I've come to accept the Tuple *implementation*, but I'm absolutely not ready to accept the syntax baggage ;) I'd really rather see something that actually looks like a language feature in its final manifestation. Is natural and convenient to read and type. float t; ... (myStruct.pos, t, _, int err) = intersectThings(); Or something to this effect. That's about as clear and concise as it gets for my money. |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 3/13/12 10:48 AM, Manu wrote:
> float t;
> ...
> (myStruct.pos, t, _, int err) = intersectThings();
I actually find the scatter syntax better than this. Anyway, I hope you'll agree there's not much difference pragmatically.
Andrei
|
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| On 13 March 2012 18:07, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>wrote: > On 3/13/12 10:48 AM, Manu wrote: > >> float t; >> ... >> (myStruct.pos, t, _, int err) = intersectThings(); >> > > I actually find the scatter syntax better than this. Anyway, I hope you'll agree there's not much difference pragmatically. There's a few finicky differences. I'm still of the understanding (and I may be wrong, still mystified by some of D's more complicated template syntax) that once you give the returned tuple a name, it is structurally bound to the stack. At that point, passing any member by-ref to any function must conservatively commit the entire tuple to the stack. This behaviour won't be intuitive to most users, and can be easily avoided; by obscuring the Tuple from user visibility, they can only access the returned values through their independant output assignments, which guarantees the independence of each returned item. Syntactically, scatter can't declare new variables inline (?), it also uses additional lines of code (1 + as many variables as you need to declare), which is very disruptive to flow. Maths-y code should be un-cluttered and read sequentially. Having to put extra lines in to munge un-related things really ruins the code IMO ('t' is of no consequence to the user, pollutes their namespace, gets in the way with extra lines, etc). What people want from MRV is to capture the returned values independently. If I *wanted* to capture the returned Tuple (the extremely rare case), I'd rather do that explicitly, something like this: auto t = tuple(mrvFunc()); scatter/gather is nice and simple, I'll take it in the mean time, but I think it would be a shame for it to stop there longer term... That said though, it's all still nothing to me without at least a promise on the ABI :) .. And I feel that should ideally come in the form of a language policy/promise that this feature will be 'efficient' (or at very least, not *inefficient* as it is now), and leave it to compiler implementations to concur with that promise, ie, failing to be 'standards' compliant if they fail to do so. |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 3/13/12 12:02 PM, Manu wrote: > There's a few finicky differences. I'm still of the understanding (and I > may be wrong, still mystified by some of D's more complicated template > syntax) that once you give the returned tuple a name, it is structurally > bound to the stack. At that point, passing any member by-ref to any > function must conservatively commit the entire tuple to the stack. This > behaviour won't be intuitive to most users, and can be easily avoided; > by obscuring the Tuple from user visibility, they can only access the > returned values through their independant output assignments, which > guarantees the independence of each returned item. Here we go moving the goalposts again. > Syntactically, scatter can't declare new variables inline (?), it also > uses additional lines of code (1 + as many variables as you need to > declare), which is very disruptive to flow. This is in addition to Kenji's change. > What people want from MRV is to capture the returned > values independently. If I /wanted/ to capture the returned Tuple (the > extremely rare case), I'd rather do that explicitly, something like this: > auto t = tuple(mrvFunc()); No. Tuple stays together by default and is expanded explicitly. This is not negotiable. > scatter/gather is nice and simple, I'll take it in the mean time, but I > think it would be a shame for it to stop there longer term... > That said though, it's all still nothing to me without at least a > promise on the ABI :) .. And I feel that should ideally come in the form > of a language policy/promise that this feature will be 'efficient' (or > at very least, not /inefficient/ as it is now), and leave it to compiler > implementations to concur with that promise, ie, failing to be > 'standards' compliant if they fail to do so. This is not for me to promise. Andrei |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu Attachments:
| On 13 March 2012 19:25, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>wrote: > On 3/13/12 12:02 PM, Manu wrote: > >> There's a few finicky differences. I'm still of the understanding (and I may be wrong, still mystified by some of D's more complicated template syntax) that once you give the returned tuple a name, it is structurally bound to the stack. At that point, passing any member by-ref to any function must conservatively commit the entire tuple to the stack. This behaviour won't be intuitive to most users, and can be easily avoided; by obscuring the Tuple from user visibility, they can only access the returned values through their independant output assignments, which guarantees the independence of each returned item. >> > > Here we go moving the goalposts again. I don't see how? I'm just saying that I don't think they are pragmatically identical. Syntactically, scatter can't declare new variables inline (?), it also >> uses additional lines of code (1 + as many variables as you need to declare), which is very disruptive to flow. >> > > This is in addition to Kenji's change. > What value does it add over Kenji's change? Is this because Kenji's change is unable to perform direct to existing variables? My understanding from early in the thread was that Kenji's change hides the returned tuple, and performs a convenient unpack. How can you perform a scatter if the tuple instance is no longer visible? What people want from MRV is to capture the returned >> values independently. If I /wanted/ to capture the returned Tuple (the >> >> extremely rare case), I'd rather do that explicitly, something like this: >> auto t = tuple(mrvFunc()); >> > > No. Tuple stays together by default and is expanded explicitly. This is not negotiable. > Then I think you commit to polluting the common case with wordy redundant noise. Why is it so important? If it were expanded by default, all you need to do it put a tuple constructor around it to wrap it up again. It creates semantic multi-assignment problems I suspect? This is what I reckon needs to be addressed to make the implementation really nice. scatter/gather is nice and simple, I'll take it in the mean time, but I >> think it would be a shame for it to stop there longer term... >> That said though, it's all still nothing to me without at least a >> promise on the ABI :) .. And I feel that should ideally come in the form >> of a language policy/promise that this feature will be 'efficient' (or >> at very least, not /inefficient/ as it is now), and leave it to compiler >> >> implementations to concur with that promise, ie, failing to be 'standards' compliant if they fail to do so. >> > > This is not for me to promise. Sure, but it'd be good to get a weigh in on that issue from Walter, and others, Iain? |
March 13, 2012 Re: Multiple return values... | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Tue, Mar 13, 2012 at 9:07 AM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote: > On 3/13/12 10:48 AM, Manu wrote: >> >> float t; >> ... >> (myStruct.pos, t, _, int err) = intersectThings(); > This can be checked at compile time. The D compiler can check that the number of arguments and the types match. > > I actually find the scatter syntax better than this. Anyway, I hope you'll agree there's not much difference pragmatically. > Correct if I am wrong but the scatter and gather functions cannot check that the number of arguments and their type match at compile time. > Andrei > > |
Copyright © 1999-2021 by the D Language Foundation