Keyword Forcing Trailing Return

67 views
Skip to first unread message

alexander.g...@gmail.com

unread,
Oct 1, 2018, 5:46:48 PM10/1/18
to ISO C++ Standard - Future Proposals
Not sure what tone to write this in, but this is a problem that I think needs to be addressed, and would like some feedback regarding the issue and this proposed solution.
I also did not see this anywhere else, but if it is redundant, please let me know.

Currently the auto keyword is required to use a trailing return (except with lambda functions).
However, auto can also be used without a trailing return to auto-deduce the return type.
This can lead to errors if a trailing return is unintentionally forgotten, which could then cause difficult to locate unintended behavior.
I'd like to discuss a keyword that required that the function return type should be specified though a trailing return.

The keyword would take on a subset of the auto keyword's behavior. Similar to the auto keyword, it would look for the trailing return.
However, it would not auto deduce the return type if there is no trailing return. 
If no trailing return is given, then no return type would have been specified, and a compiler error would be thrown (No return type specified).
In the case of the trailing return being "auto", it should be equivalent to using the auto without a trailing return (to allow for consistent code style).

The keyword would add additional specificity to the language, by allowing programmers to better express intention.
examples:
           auto get42(){ return 42; }                               // returns 42 as an int (possibly unintended return type)
<keyword> get42(){ return 42; }                    // compiler error, no return type specified
           <keyword> get42()->double { return 42; }     // returns 42 as a double (intended)
<keyword> get42()->auto { return 42; }         // returns 42 as an int (auto return type behavior intended) 

This is useful in preventing the following:
auto get42()->double { return 42; }                // Intended: returns 42 as a double 
auto get42() { return 42; }                              // Unintended: returns 42 as an int
In this case, the error is that the programmer intended to write a function with a trailing return, but forgot the trailing return.
Everything could work fine, or unintended behavior could occur in the program somewhere due to the different type.
The source of the unintended behavior could also be difficult to locate, especially if the auto keyword is overused.
A similar issue can also be introduced in the case of a bad refactor, if the return type of an auto function is unintentionally changed.

The keyword would prevent issues like this by catching such a scenario at compile time using additional specificity.
Thus the case of a programmer unintentionally forgetting to specify a trailing return type, can be caught at compile time, and remove a source of difficult to locate errors.
It also increases code readability, by better expressing programmer intent.

Hopefully I've shown that such a keyword is useful, and there is just the question of naming.
The two keywords I've thought of are "trailing" and the ever controversal "func".
My preference is towards "func", since I think it makes code more readable.
example:  func get42()->double() { return 42; } 
Unfortunately I am not sure if it would cause any name conflict issues given the given the prevalence of the abbreviation.
It could also possibly conflict with possible future uses of func. 

Ville Voutilainen

unread,
Oct 1, 2018, 5:51:49 PM10/1/18
to ISO C++ Standard - Future Proposals
On Tue, 2 Oct 2018 at 00:46, <alexander.g...@gmail.com> wrote:
> The keyword would add additional specificity to the language, by allowing programmers to better express intention.
> examples:
> auto get42(){ return 42; } // returns 42 as an int (possibly unintended return type)
>
> <keyword> get42(){ return 42; } // compiler error, no return type specified
>
> <keyword> get42()->double { return 42; } // returns 42 as a double (intended)
>
> <keyword> get42()->auto { return 42; } // returns 42 as an int (auto return type behavior intended)
>
>
> This is useful in preventing the following:
>
> auto get42()->double { return 42; } // Intended: returns 42 as a double
>
> auto get42() { return 42; } // Unintended: returns 42 as an int

All of which I can write with a traditional return type, completely
avoiding the problem. Show me a compelling
use case where the return type must be trailing, and we'll talk.

Alexander Graber-Tilton

unread,
Oct 1, 2018, 6:42:19 PM10/1/18
to std-pr...@isocpp.org
My understanding is that there is are already compelling use cases for trailing returns, which is why it is part of the standard.
This is more aimed at resolving the ambiguous uses of the auto keyword, which can be used for multiple purposes when defining a function and as such be a contributing factor to programmer errors.
In this case the keyword is to create a more specified way to declare programmer intention between the following use cases.
1. Declare a function with a trailing return: auto mul(T a, T b) -> decltype(a*b){ return a*b; }
2. Automatically deduced the return type for a function: auto getChild(T a){ return a.child(); }
Currently there is no way to express the intent of #1 without the intent of #2
We have #2: auto-deduce return type.
We have #1 else #2: use trailing return type, else auto-deduce.
We don't have #1: use the trailing return type.

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/0euDU94QGks/unsubscribe.
To unsubscribe from this group and all its topics, 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/CAFk2RUbD6GqOC6XtAhDR3DVG4npXEPA4ghT_FDDHqkSCr7PO2w%40mail.gmail.com.

Gašper Ažman

unread,
Oct 1, 2018, 6:46:51 PM10/1/18
to std-pr...@isocpp.org
This sounds a lot like a self-correcting declaration to me, which is... weird? There are no other intent-checking provisions in declarations, so why would we need one for the trailing return type?

The only motivation for *something* like this, to me, would be, if I could *omit* the return type, but the deduction of it would still take place in a SFINAE context, so I didn't have to *repeat* it.

My point is that the feature space is larger than just checking, and there are competing interests in this space, where keywords are already very scarce.

G

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.

Ray Hamel

unread,
Oct 1, 2018, 7:48:40 PM10/1/18
to ISO C++ Standard - Future Proposals, alexander.g...@gmail.com
What about just extending C-syntax returns so they behave the same way as trailing returns? It would be a potentially breaking change if a parameter shadows another identifier at class, namespace or global scope, but I don't think that would break much actual code, and it might even fix some subtly incorrect code.

-Ray

alexander.g...@gmail.com

unread,
Oct 1, 2018, 7:56:29 PM10/1/18
to ISO C++ Standard - Future Proposals
This is somewhat aimed at a more general use case, in favor of tying to have a consistent style.
There are now essentially two ways to write functions, both valid, and both use-able in multiple scenarios.
The trailing return can be used in all scenarios, as it can be used for: templates, non-templates, and lambda functions.
The traditional return style can only be used for a subset of those: some templates, and non-templates

This means the most consistent way to write a function is using a trailing return, yet it has a number of issues including the else auto-deduce return type.
With the traditional style, a missing return type causes a compile error: "ISO C++ forbids declaration of with no type"
There is no way to get a compilation error for a missing return type with trailing return, since the "else auto-deduce" automatically kicks in.
The auto deduction leaves a space for programmer error in a way that is difficult to locate, despite the fact that this is something that should be catch-able at compile time and easily found.
So given that everything can be done using trailing returns, it makes a lot of sense to have a way of enforcing that the return type is specified.

So the question then becomes how to specify a function that requires a trailing return.
auto can't be used, since the auto-deduction is the issue.
I would have proposed something like being able to specify a trailing return function without the auto keyword, but that seems odd to me, as it doesn't match the typical way of defining things
get42()->double{return 42;} // this doesn't seem like it should be valid, as it still has no type, but would be the alternative. 
I don't see a way to deal with this other than a keyword.

In the end, I don't think that auto-deduction should be the default return type for a function, and that is currently the case for any trailing return.
The programmer should have the option to use auto-deduction, but it shouldn't be the default.

alexander.g...@gmail.com

unread,
Oct 3, 2018, 12:44:54 AM10/3/18
to ISO C++ Standard - Future Proposals, alexander.g...@gmail.com
Thinking about this further, it could also be done using static analysis, but would then end up forcing warnings with the traditional style auto return type functions.
The ambiguity comes from weather auto is indicating an auto-deduced return type, or if it is indicating a trailing return.
The only way to check programmer error where they possibly forgot the trailing return would be to warn on something like: "auto doSomething(){}"

It does make sense to have the func keyword though for this purpose, as it would add a lot of readability to the trailing return style.
It is easier to read type and teach
{
  int i = 0;
  func test()->bool{return false;}
}
in comparison to:
  int i = 0;
  bool test(){return false;}
}

Maybe this would be better to simply revisit if there is ever a proposal for a func keyword for some other reason.
Reply all
Reply to author
Forward
0 new messages