map<foo, map<set<bar>, baz>
complicated(...) {
decltype(return) ret;
// add stuff to ret
return try;
}
Sounds like a nice idea, but can you elaborate a little, maybe with some more examples? I'm most confused about the "return try" part of this.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CACGiwhFY8C30LKtApxjopXDJKH-hMrrhaZdL66moW2xf4fUCHw%40mail.gmail.com.
auto complicated(...) -> map<foo, map<set<bar>, baz>
ret // ret is a "return variable"
{
// add stuff to ret
} // no return statement is ok: we have an implicit return variable
map<foo, map<set<bar>, baz>
complicated(...)
{
decltype(return) a, b;
// populate a and b
if (is_better(a, b))
return a;
else
return b;
}
auto complicated(...) ->map<foo, map<set<bar>, baz>
ret // ret is a "return variable"
{
// add stuff to ret
} // no return statement is ok: we have an implicit return variable
But you may be right, that this might turn out to be prone to errors. Without playing with it, one never knows.
Regards,
&rzej;
Just two comments, now that you have explored this.
- Having an implicit return value does not prevent you from explicitly returning something else.
- This solution is less implicit than the case of main, because you have to explicitly say that you are using an implicit return value.
But you may be right, that this might turn out to be prone to errors. Without playing with it, one never knows.
Regards,
&rzej;
W dniu środa, 23 listopada 2016 10:53:45 UTC+1 użytkownik D. B. napisał:On Wed, Nov 23, 2016 at 9:50 AM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
auto complicated(...) ->map<foo, map<set<bar>, baz>
ret // ret is a "return variable"
{
// add stuff to ret
} // no return statement is ok: we have an implicit return variable[bikeshed] I don't find this very appealing. It seems prone to errors and is inapplicable for functions needing early return anyway. [btw, I don't even like the implicit return 0; in main() very much]
Just two comments, now that you have explored this.
- Having an implicit return value does not prevent you from explicitly returning something else.
On Wednesday, November 23, 2016 at 6:56:45 AM UTC-5, Andrzej Krzemieński wrote:
W dniu środa, 23 listopada 2016 10:53:45 UTC+1 użytkownik D. B. napisał:On Wed, Nov 23, 2016 at 9:50 AM, Andrzej Krzemieński <akrz...@gmail.com> wrote:
auto complicated(...) ->map<foo, map<set<bar>, baz>
ret // ret is a "return variable"
{
// add stuff to ret
} // no return statement is ok: we have an implicit return variable[bikeshed] I don't find this very appealing. It seems prone to errors and is inapplicable for functions needing early return anyway. [btw, I don't even like the implicit return 0; in main() very much]
Just two comments, now that you have explored this.
- Having an implicit return value does not prevent you from explicitly returning something else.
This is getting a bit off-topic (since there are plenty of uses for `decltype(return)` besides declaring a variable to be returned), but...
C++'s function model gives every function a return value object. As it currently stands, this object is initialized by the `return` statement, but the storage for it always exists (provided by the caller).
If you can name this variable, then it seems to me that what you're doing is giving the user direct access to the return value object itself. This named return value object is being initialized at the start of the function, and the user gets to manipulate it in whatever way they see fit. If you are directly manipulating the return value object, it must be impossible for a user to return "something else".
Oh sure, a return statement in a function with a named return value (NRV) could simply perform the equivalent of assigning the returned expression to the NRV. Or even destroying the existing NRV object and re-creating it in-situ (which is perfectly legal C++). But you aren't truly returning "something else"; you're just doing what a typical `return` statement would do.
There are two things I don't like about directly accessing the return value object the way you define it is this.
1: Where it gets named.
You name it in the function's signature. Why? Users of the function don't need to know the name. Users of the function don't even need to know that it has a name. I suppose you could treat the name as optional, the way parameter names are optional. But I don't think function signatures need more optional things.
// declaration:
map<foo, map<set<bar>, baz>
complicated(...);
// definition:
auto complicated(...) -> map<foo, map<set<bar>, baz> ret {baz{}} // return value is initialized
{
// add stuff to ret
}
This is similar to taking an int by value in a declaration and by const value in the definition:void fun(int x); // declaration
void fun(const int x) // definition
{}
struct X { void * p; }; // sizeof(X) == 8
std::vector<X> fun()
{
struct X {}; // sizeof(X) == 1
decltype(return) v;
return v;
}
typedef std::vector<X> THE_TYPE;
THE_TYPE fun()
{
THE_TYPE v;
}
#define THE_TYPE
std::vector<X>
THE_TYPE fun()
{
THE_TYPE v;
}
Hi,
I like the idea very much, but please bear in mind that `return` is not a variable. It's a keyword and the closest approximation is an operator taking a single type, being [[noreturn]] and thus returning void.Thus, if you want to be coherent, decltype(return) should be `void(*)(T)` instead of `T`. Which is fine - you can write `paramof()` and then `decltype(paramof(return))`.
Why it's important (to me, at least)? I'm working on a way to capture `return` and pass it along. Double return, if you like: it's useful for custom control structures, like custom for-loop. If you put this piece in incoherently, I won't be able to specify the type of the `return` being captured (or at the very least, I'll need new logic for that).
With that said, I'd welcome a version of this in the standard.
/* As for the return variable: we have the need for uninitialized variables elsewhere (ideally even >> would be implemented that way), we have placement new() to initialize it. I don't really see a problem with taking the address of the variable-to-be-returned and then placement new-ing into it.
On Saturday, November 26, 2016 at 8:36:36 AM UTC-5, szollos...@gmail.com wrote:Hi,
I like the idea very much, but please bear in mind that `return` is not a variable. It's a keyword and the closest approximation is an operator taking a single type, being [[noreturn]] and thus returning void.Thus, if you want to be coherent, decltype(return) should be `void(*)(T)` instead of `T`. Which is fine - you can write `paramof()` and then `decltype(paramof(return))`.
And yet, I don't think anyone will be in any way confused by the meaning of `decltype(return)`. Much as they're not confused by the idea of what `decltype(auto)` means.
Why it's important (to me, at least)? I'm working on a way to capture `return` and pass it along. Double return, if you like: it's useful for custom control structures, like custom for-loop. If you put this piece in incoherently, I won't be able to specify the type of the `return` being captured (or at the very least, I'll need new logic for that).
People will be more likely to need to get the type of the return value than they will need to create "custom control structures" that require getting the type of whatever you're capturing. So forcing people to use the long syntax for the more common case is not the best idea.
With that said, I'd welcome a version of this in the standard.
/* As for the return variable: we have the need for uninitialized variables elsewhere (ideally even >> would be implemented that way), we have placement new() to initialize it. I don't really see a problem with taking the address of the variable-to-be-returned and then placement new-ing into it.
The problem there is that such a feature must affect how the standard handles a `return` statement. If you initialize the return value object, then issue a `return <expr>`, the only reasonable thing for the compiler to do is destroy the return value object you initialized, then initialize it again with `<expr>`. To do anything else would impose requirements like copy/move assignment, as well as damage guaranteed elision.
As such, the compiler must have a way to know that you've initialized the return value. And that means it must be done via some specialized syntax, not merely getting some `void*`. Let's not make this harder on the compiler than it needs to be.
2016-11-18 19:01 GMT+03:00 Avi Kivity <a...@scylladb.com>:
>
> map<foo, map<set<bar>, baz>>
> complicated(...) {
> decltype(return) ret;
> // add stuff to ret
> return try;
> }
>
> Instead of repeating the complicated type, refer to it via decltype(return).
> Won't work with deduced return types, of course.
Syntax sugar makes the language harder to understand.
decltype(return) does not reduce code lines,
looks good only if the function is small,
motivates people to write ugly return types instead of providing a humanreadable typedef for the result type:
2016-12-25 22:27 GMT+03:00 Nicol Bolas <jmck...@gmail.com>:
>
>
> On Sunday, December 25, 2016 at 2:13:57 PM UTC-5, Antony Polukhin wrote:
>>
>> 2016-11-18 19:01 GMT+03:00 Avi Kivity <a...@scylladb.com>:
>> >
>> > map<foo, map<set<bar>, baz>>
>> > complicated(...) {
>> > decltype(return) ret;
>> > // add stuff to ret
>> > return try;
>> > }
>> >
>> > Instead of repeating the complicated type, refer to it via
>> > decltype(return).
>> > Won't work with deduced return types, of course.
>>
>> Syntax sugar makes the language harder to understand.
>
>
> No, it doesn't. `for` loops are syntactic sugar for `while` loops.
> Range-based `for` loops are syntactic sugar for `for` loops over the
> begin/end iterators. And technically, you could implement all of those with
> `goto`.
All that sugar exist in many popular languages. decltype(return) does not.
> That depends on how many lines it takes to enter that return type. After
> all, you can use `decltype(return)` even in a function that deduces its
> return type from a return statement. So that return type could be quite
> lengthy.
It's already hard to understand what is happening if there's multiple
chained functions with auto return type. Adding decltype(return) may
make the things wose.
>> motivates people to write ugly return types instead of providing a
>> humanreadable typedef for the result type:
>
>
> You assume that such a typedef can actually be written. Automatic return
> type deduction means that types with very complex typenames can be returned.
> Not all of them can be easily predicted and culled out with a typedef.
Could you give an example?
W dniu piątek, 18 listopada 2016 17:01:41 UTC+1 użytkownik Avi Kivity napisał:
map<foo, map<set<bar>, baz>
complicated(...) {
decltype(return) ret;
// add stuff to ret
return try;
}
Instead of repeating the complicated type, refer to it via
decltype(return). Won't work with deduced return types, of course.
In your example, you use this hypothetical feature to create up front the value you will be returning. I wonder if this is the only use case that drives your feature, because if so, you could consider an alternative feature: give a variable name in the place where you declare the return type:
auto complicated(...) ->map<foo, map<set<bar>, baz>
ret // ret is a "return variable"
{
// add stuff to ret
} // no return statement is ok: we have an implicit return variable
Of course, your solution is more general, it also covers other cases:
map<foo, map<set<bar>, baz>
complicated(...)
{
decltype(return) a, b;
// populate a and b
if (is_better(a, b))
return a;
else
return b;
}
Regards,
&rzej;