Date: Sat, 12 Apr 2025 16:45:44 -0400
On 4/10/25 6:07 AM, Frederick Virchanza Gotham via Std-Proposals wrote:
> On Thu, Apr 10, 2025 at 10:40 AM Rhidian De Wit wrote:
>> Hi Frederick,
>>
>> Isn't this a rather small problem to face? Granted an annoying one when it occurs,
>> but just not needing to add a single std::forward call in the one appropriate line
>> doesn't seem to be worth a language change
>
> I think it would reduce the possibility of introducing
> very-hard-to-find bugs. I mean let's say Billy The Programmer started
> out by writing the following function:
>
> template<typename T>
> void ProcessNode(T &&arg)
> {
> NormaliseNode(arg);
> DistributeNode(arg);
> AssimilateNode( forward<T>(arg) );
> }
>
> and the Mandy The Programmer came along a year later and added a new line:
>
> template<typename T>
> void ProcessNode(T &&arg)
> {
> NormaliseNode(arg);
> DistributeNode(arg);
> AssimilateNode( forward<T>(arg) );
> TrimMemoryUsage( forward<T>(arg) );
> }
Existing static analysis tools will report issues for code like this.
For example, Coverity will report a USE_AFTER_MOVE issue. Compilers can
(and I think should) diagnose such code; I'm not sure if there are
reasons they don't beyond no one having done the work yet.
Tom.
>
> Of course this is a very very simple example, and Mandy would be able
> to see straight away that 'arg' was already forwarded on the previous
> line. But what if the function were 340 lines long, and what if Mandy
> missed that 'arg' had previously been forwarded. This bug could lead
> to the building of an executable binary that doesn't crash, but
> behaves oddly only for a few corner cases. The person tasked with
> fixing this bug might spend a long time trying to figure out what's
> gone wrong.
>
> The whole point of the trigraph reference is that it means that the
> programmer can no longer make the mistake.
>
>
>
>> and one that makes references harder to read, making it more confusing for beginners as well,
>> as we'd have &, && and &&& which doesn't really follow the rules of the previous 2.
>
> I'm not too fussed about the syntax, i.e. whether it's a symbol or a
> word or whatever. It could as easily be written as:
>
> template<typename T>
> void ProcessNode(T &&arg [[auto_forward]])
>
> Just now I asked ChatGPT to give me 20 possible ways of writing it:
>
> template<typename T> void ProcessNode( T &&&arg )
> template<typename T> void ProcessNode( T&|&arg )
> template<typename T> void ProcessNode( T&!&arg )
> template<typename T> void ProcessNode( T&^&arg )
> template<typename T> void ProcessNode( forwardref<T> arg )
> template<typename T> void ProcessNode( autoforward<T&&> arg )
> template<typename T> void ProcessNode( T&& autoforward arg )
> template<typename T> void ProcessNode( forward T&& arg )
> template<typename T> void ProcessNode( T&& arg forward )
> template<typename T> void ProcessNode( T&& arg [[autoforward]] )
> template<typename T> void ProcessNode( T&& arg [[forwarding_ref]] )
> template<typename T> void ProcessNode( T&& arg [[pass_through]] )
> template<typename T> void ProcessNode( T&& arg [[binds_to_any]] )
> template<typename T> void ProcessNode( T&& arg [[perfect]] )
> template<typename T> void ProcessNode( forward<T> arg )
> template<typename T> void ProcessNode( auto&& arg = forward<T> )
> template<typename T> void ProcessNode( T&& arg = auto_forward )
> template<typename T> void ProcessNode( forwardref auto arg )
> template<typename T> void ProcessNode( T>>> arg )
> template<typename T> void ProcessNode( T&&... arg ) // reimagined
> ellipsis use
> On Thu, Apr 10, 2025 at 10:40 AM Rhidian De Wit wrote:
>> Hi Frederick,
>>
>> Isn't this a rather small problem to face? Granted an annoying one when it occurs,
>> but just not needing to add a single std::forward call in the one appropriate line
>> doesn't seem to be worth a language change
>
> I think it would reduce the possibility of introducing
> very-hard-to-find bugs. I mean let's say Billy The Programmer started
> out by writing the following function:
>
> template<typename T>
> void ProcessNode(T &&arg)
> {
> NormaliseNode(arg);
> DistributeNode(arg);
> AssimilateNode( forward<T>(arg) );
> }
>
> and the Mandy The Programmer came along a year later and added a new line:
>
> template<typename T>
> void ProcessNode(T &&arg)
> {
> NormaliseNode(arg);
> DistributeNode(arg);
> AssimilateNode( forward<T>(arg) );
> TrimMemoryUsage( forward<T>(arg) );
> }
Existing static analysis tools will report issues for code like this.
For example, Coverity will report a USE_AFTER_MOVE issue. Compilers can
(and I think should) diagnose such code; I'm not sure if there are
reasons they don't beyond no one having done the work yet.
Tom.
>
> Of course this is a very very simple example, and Mandy would be able
> to see straight away that 'arg' was already forwarded on the previous
> line. But what if the function were 340 lines long, and what if Mandy
> missed that 'arg' had previously been forwarded. This bug could lead
> to the building of an executable binary that doesn't crash, but
> behaves oddly only for a few corner cases. The person tasked with
> fixing this bug might spend a long time trying to figure out what's
> gone wrong.
>
> The whole point of the trigraph reference is that it means that the
> programmer can no longer make the mistake.
>
>
>
>> and one that makes references harder to read, making it more confusing for beginners as well,
>> as we'd have &, && and &&& which doesn't really follow the rules of the previous 2.
>
> I'm not too fussed about the syntax, i.e. whether it's a symbol or a
> word or whatever. It could as easily be written as:
>
> template<typename T>
> void ProcessNode(T &&arg [[auto_forward]])
>
> Just now I asked ChatGPT to give me 20 possible ways of writing it:
>
> template<typename T> void ProcessNode( T &&&arg )
> template<typename T> void ProcessNode( T&|&arg )
> template<typename T> void ProcessNode( T&!&arg )
> template<typename T> void ProcessNode( T&^&arg )
> template<typename T> void ProcessNode( forwardref<T> arg )
> template<typename T> void ProcessNode( autoforward<T&&> arg )
> template<typename T> void ProcessNode( T&& autoforward arg )
> template<typename T> void ProcessNode( forward T&& arg )
> template<typename T> void ProcessNode( T&& arg forward )
> template<typename T> void ProcessNode( T&& arg [[autoforward]] )
> template<typename T> void ProcessNode( T&& arg [[forwarding_ref]] )
> template<typename T> void ProcessNode( T&& arg [[pass_through]] )
> template<typename T> void ProcessNode( T&& arg [[binds_to_any]] )
> template<typename T> void ProcessNode( T&& arg [[perfect]] )
> template<typename T> void ProcessNode( forward<T> arg )
> template<typename T> void ProcessNode( auto&& arg = forward<T> )
> template<typename T> void ProcessNode( T&& arg = auto_forward )
> template<typename T> void ProcessNode( forwardref auto arg )
> template<typename T> void ProcessNode( T>>> arg )
> template<typename T> void ProcessNode( T&&... arg ) // reimagined
> ellipsis use
Received on 2025-04-12 20:45:46