<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Thu Feb 08 05:33:18 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[SERVER-54356] make a ReturnableScopeGuard type</title>
                <link>https://jira.mongodb.org/browse/SERVER-54356</link>
                <project id="10000" key="SERVER">Core Server</project>
                    <description>&lt;p&gt;It seems like it would be nice to be able to return a &lt;tt&gt;ScopeGuard&lt;/tt&gt;-like type from a function. Eg, construct a guard at the top of a&#160;&lt;tt&gt;pushState()&lt;/tt&gt; function to restore it to the then-current state prior to modifying, then return it so that the caller of&#160;&lt;tt&gt;pushState()&lt;/tt&gt; will always automatically pop its state modification. &lt;/p&gt;

&lt;p&gt;&#160;&lt;/p&gt;

&lt;p&gt;Based on a slack discussion, we decided it would be best to be a separate type to avoid breaking the rule that it is always safe (and preferred!) to use &lt;tt&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;&amp;amp;&amp;#93;&lt;/span&gt;&lt;/tt&gt; captures with &lt;tt&gt;makeGuard&lt;/tt&gt; (unless you are literally typing &lt;tt&gt;return makeGuard(&lt;span class=&quot;error&quot;&gt;&amp;#91;&amp;amp;&amp;#93;&lt;/span&gt;{...})&lt;/tt&gt; but then you know what you are doing and deserve to win stupid prizes). From the same discussion, it would be safer if the type only supported move construction but not move assignment. This allows the important use case of returning a guard, but disallows silly operations like swapping two guards.&lt;/p&gt;</description>
                <environment></environment>
        <key id="1614304">SERVER-54356</key>
            <summary>make a ReturnableScopeGuard type</summary>
                <type id="4" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14710&amp;avatarType=issuetype">Improvement</type>
                                            <priority id="3" iconUrl="https://jira.mongodb.org/images/icons/priorities/major.svg">Major - P3</priority>
                        <status id="10038" iconUrl="https://jira.mongodb.org/images/icons/subtask.gif" description="">Backlog</status>
                    <statusCategory id="2" key="new" colorName="default"/>
                                    <resolution id="-1">Unresolved</resolution>
                                        <assignee username="backlog-server-servicearch">Backlog - Service Architecture</assignee>
                                    <reporter username="mathias@mongodb.com">Mathias Stearn</reporter>
                        <labels>
                            <label>sa-remove-fv-backlog-22</label>
                    </labels>
                <created>Fri, 5 Feb 2021 17:44:57 +0000</created>
                <updated>Tue, 6 Dec 2022 01:35:17 +0000</updated>
                                                                            <component>Internal Code</component>
                                        <votes>1</votes>
                                    <watches>5</watches>
                                                                                                                <comments>
                            <comment id="3623965" author="JIRAUSER1256988" created="Thu, 18 Feb 2021 21:01:29 +0000"  >&lt;p&gt;Billy Donahue &lt;a href=&quot;https://jira.mongodb.org/secure/ViewProfile.jspa?name=billy.donahue&quot; class=&quot;user-hover&quot; rel=&quot;billy.donahue&quot;&gt;billy.donahue&lt;/a&gt;  :&lt;br/&gt;
&quot;So maybe there&apos;s a flexible Cleanup type and then the ScopeGuard stays on as derived from Cleanup, but restricting the functionality. Then it&apos;s just like 5 lines or something. I think that could work, yeah.&quot;&lt;/p&gt;</comment>
                            <comment id="3623952" author="JIRAUSER1256988" created="Thu, 18 Feb 2021 20:56:10 +0000"  >&lt;p&gt;&quot;&quot;&quot;Andrew Shuvalov Today at 2:40 PM&lt;br/&gt;
Do we have a RAII &#8216;outstanding counter&#8217;, which adds/deletes something to something and does the opposite in destructor? If not I&#8217;ll write one.&lt;br/&gt;
17 replies&lt;/p&gt;

&lt;p&gt;Sam  1 hour ago&lt;br/&gt;
You can use ScopeGuard to implement this &#8212; increment before making the guard and have the guard do the decrement via its callback.&lt;br/&gt;
:+1:&lt;br/&gt;
1&lt;/p&gt;


&lt;p&gt;Sam  1 hour ago&lt;br/&gt;
Would that work for your use-case?&lt;/p&gt;

&lt;p&gt;Andrew Shuvalov  18 minutes ago&lt;br/&gt;
Thanks, almost. I need to make it to track the long Future lifetime, to delete when the Future is at last step. Is it better to use unique_ptr wrapper around ScopeGuard and make the last callback to own it, or I need a shared_ptr and make more than 1 callback to own it?&lt;/p&gt;

&lt;p&gt;Billy Donahue  15 minutes ago&lt;br/&gt;
You have hit an interesting issue with ScopeGuard that it&apos;s currently associated with scopes. I&apos;ve suggested upgrading it to Cleanup and making it movable, for exactly the motivation you mention. To have a generalized cleanup action as a subobject that executes when its enclosing object (maybe a lambda) is destroyed.  I think some of the hackery with unique_ptr deleters could be alleviated by such a thing.&lt;br/&gt;
&lt;a href=&quot;https://jira.mongodb.org/browse/SERVER-54356&quot; class=&quot;external-link&quot; rel=&quot;nofollow&quot;&gt;https://jira.mongodb.org/browse/SERVER-54356&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Billy Donahue  12 minutes ago&lt;br/&gt;
If it&apos;s common that people consider making scoped_ptr and unique_ptr and optional wrappers just to get the lifetime semantics they want out of something then it feels like our offering might be not quite right.&lt;/p&gt;

&lt;p&gt;Andrew Shuvalov  11 minutes ago&lt;br/&gt;
Ah, totally onboard, and it should be a separate type. Move constructor without move assignment should enforce proper use. I will use uniquer_ptr for now.&lt;/p&gt;

&lt;p&gt;Billy Donahue  10 minutes ago&lt;br/&gt;
DO I Disagree about separate type? Maybe I don&apos;t know what you&apos;re suggesting. (edited) &lt;/p&gt;

&lt;p&gt;Sam  9 minutes ago&lt;br/&gt;
My understanding is that you want the callback to run as the future chain is being destroyed. If that&#8217;s the case, I believe unique_ptr is the right choice until we can have the lambda for the last continuation to capture an instance of ScopeGuard.&lt;/p&gt;

&lt;p&gt;Sam  9 minutes ago&lt;br/&gt;
Is this what you&#8217;re trying to achieve?&lt;/p&gt;

&lt;p&gt;Andrew Shuvalov  6 minutes ago&lt;br/&gt;
Yes. The only reason for a separate type is that the ScopeGuard is 20 lines. Making another 20 lines type with very clear separation is better than extending ScopeGuard to 30 lines and adding 10 lines of comments explaining different usage patterns.&lt;/p&gt;

&lt;p&gt;Billy Donahue  4 minutes ago&lt;br/&gt;
Oh yeah then I do disagree with you. I don&apos;t think the implementation should factor into the decision. The docs need to be good enough as always. I think they can be structured so that users don&apos;t get bogged down in learning features they won&apos;t use.&lt;/p&gt;

&lt;p&gt;Billy Donahue  4 minutes ago&lt;br/&gt;
I would prefer to have fewer types in the zoo, even if it means one of them has extra functionality.&lt;/p&gt;

&lt;p&gt;andy  3 minutes ago&lt;br/&gt;
I&#8217;m in the 2-types camp, I think. It&#8217;s helpful to a reviewer to look at some code and answer the question &#8220;is it OK that the lambda passed to this guard captures &lt;span class=&quot;error&quot;&gt;&amp;#91;&amp;amp;&amp;#93;&lt;/span&gt;?&#8221; Using &#8220;const&#8221; in the capture for that as the answer, I can&#8217;t decide if it&#8217;s too subtle or not.&lt;/p&gt;

&lt;p&gt;Andrew Shuvalov  2 minutes ago&lt;br/&gt;
Ok, hopefully we are smart enough to RTM :slightly_smiling_face:&lt;/p&gt;

&lt;p&gt;andy  2 minutes ago&lt;br/&gt;
If we&#8217;re truly smart, there won&#8217;t need to be a manual.&lt;/p&gt;

&lt;p&gt;andy  1 minute ago&lt;br/&gt;
I would ideally like to have our support libraries usable by people who want to use them, not people who want to know everything about them.&lt;/p&gt;

&lt;p&gt;andy  &amp;lt; 1 minute ago&lt;br/&gt;
I wouldn&#8217;t be surprised (or disappointed) to lose this debate, though. (edited) &lt;br/&gt;
&quot;&quot;&quot;&lt;/p&gt;</comment>
                            <comment id="3616004" author="schwerin" created="Mon, 15 Feb 2021 13:52:03 +0000"  >&lt;p&gt;I could accept a const based solution instead of a separate type. But how many places are we actually returning guard objects that we could turn into makeGuard? Is this functionality we want? None of the ones in Interruptible we&#8217;re good examples, hence my plan to remove them.&lt;/p&gt;</comment>
                            <comment id="3615865" author="billy.donahue" created="Mon, 15 Feb 2021 11:04:20 +0000"  >&lt;p&gt;This line of reasoning reminds me of the case for using more const local variables.&lt;br/&gt;
More const could help here too. A const ScopeGuard can&apos;t move, can&apos;t be returned, and can&apos;t be dismissed. We could add const to guard declarations to mark them undismissable and immovable.&lt;/p&gt;

&lt;p&gt;Of the 194 makeGuard calls, 25 are initializing a const variable. If we see a const auto xxx = makeGuard(...) we know it&apos;s one of the easy cases. If it&apos;s guarding a block that&apos;s only &amp;lt;5 lines, it&apos;s also an easy case.&lt;/p&gt;

&lt;p&gt;&amp;gt; &quot;Since 90% or more of our guards are just trying to always run code at block exit,&quot;&lt;/p&gt;

&lt;p&gt;It&apos;s actually not that high. It&apos;s only 73% (324/443).&lt;/p&gt;


&lt;p&gt;Of the entire population of 443 guards,&lt;/p&gt;

&lt;p&gt;274 are declared undismissable (25 &quot;const makeGuard&quot; and 249 ON_BLOCK_EXIT)&lt;/p&gt;

&lt;p&gt;119 are dismissed.&lt;/p&gt;

&lt;p&gt;50 can be dismissed (&quot;nonconst makeGuard&quot;) but aren&apos;t.&lt;/p&gt;


&lt;p&gt;The problem is then narrowed down to the 50 of 443 that are eligible for tightening up. All the others are already declared properly. We could add const to them or leave them alone. In a lot of these cases they&apos;re guarding a scope that&apos;s extremely small, like &amp;lt;5 lines. Sometimes just 1 line. There&apos;s no way to make those more clear, really.&lt;/p&gt;</comment>
                            <comment id="3615803" author="redbeard0531" created="Mon, 15 Feb 2021 09:13:13 +0000"  >&lt;p&gt;&lt;a href=&quot;https://jira.mongodb.org/secure/ViewProfile.jspa?name=schwerin&quot; class=&quot;user-hover&quot; rel=&quot;schwerin&quot;&gt;schwerin&lt;/a&gt; was more opposed to the unified type so I&apos;ll let him defend the separate types.&lt;/p&gt;

&lt;p&gt;Personally I&apos;d be fine with a unified type, but if we go that route, I&apos;d rather we replace all &quot;simple&quot; uses of &lt;tt&gt;makeGuard&lt;/tt&gt; with &lt;tt&gt;ON_BLOCK_EXIT&lt;/tt&gt;. While I already dislike code using &lt;tt&gt;makeGuard&lt;/tt&gt; when the declarative &lt;tt&gt;ON_BLOCK_EXIT&lt;/tt&gt; would work, currently it is still restricted to the current block and may or may not be dismissed. If we unify, then that is one more thing that I need to check for when I see a call to &lt;tt&gt;makeGuard&lt;/tt&gt; in order to understand the code. Since 90% or more of our guards are just trying to always run code at block exit, we should save the explicit &lt;tt&gt;makeGuard&lt;/tt&gt; for the interesting cases where more caution is needed by readers.&lt;/p&gt;</comment>
                            <comment id="3615097" author="billy.donahue" created="Sat, 13 Feb 2021 03:41:21 +0000"  >&lt;p&gt;I strongly agree with the basic idea that a movable&#160;&lt;tt&gt;ScopeGuard&lt;/tt&gt;&#160;is really useful.&lt;/p&gt;

&lt;p&gt;Instead of a new type, I propose the simpler&#160;change to just make &lt;tt&gt;ScopeGuard&lt;/tt&gt;&#160;movable, and rename it &lt;tt&gt;Cleanup&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;The word &lt;tt&gt;ScopeGuard&lt;/tt&gt;&#160;appears only 2 times in our codebase, vs 443 for &lt;tt&gt;ON_BLOCK_EXIT or makeGuard&lt;/tt&gt;. So we can just rename it whatever we want. I like Cleanup, which is the name I gave the same class when I wrote it at my previous job. It&apos;s been changed a bit but it was released in an absl drop last month.&lt;br/&gt;
&lt;a href=&quot;https://github.com/abseil/abseil-cpp/blob/master/absl/cleanup/cleanup.h&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/abseil/abseil-cpp/blob/master/absl/cleanup/cleanup.h&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don&apos;t like the name &lt;tt&gt;ScopeGuard&lt;/tt&gt;&#160;if it becomes movable. Its behavior isn&apos;t really bound to a scope anymore. ReturnableScopeGuard is almost a contradiction in terms. It still refers to &quot;scope&quot;, and when its salient feature is its ability to escape from a scope this feels unclear. But that&apos;s just bikeshedding.&lt;/p&gt;

&lt;p&gt;On to the point about referential safety though, and the motivation for splitting off the new type, I don&apos;t feel there&apos;s a need to do that.&lt;/p&gt;

&lt;p&gt;We all know the well-known rule of thumb is that if the lambda doesn&apos;t leave the scope, you can always use &lt;span class=&quot;error&quot;&gt;&amp;#91;&amp;amp;&amp;#93;&lt;/span&gt;. I think people are pretty good at applying that rule, and they use &lt;tt&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;&amp;amp;&amp;#93;&lt;/span&gt;&lt;/tt&gt;&#160;lambdas with generic algorithms like &lt;tt&gt;sort&lt;/tt&gt;&#160;or &lt;tt&gt;remove_if&lt;/tt&gt;, but not with, say, &lt;tt&gt;std::async&lt;/tt&gt;, and when passing to functions with complex behaviors they know to choose bindings carefully. I don&apos;t think making a Cleanup object is a complex behavior, though. When passing any reference handle to any function you have to be on your toes and know whether the function being called is going to retain a copy or not.&lt;/p&gt;


&lt;p&gt;I think that declaring a local &lt;tt&gt;Cleanup&lt;/tt&gt;&#160;is a lot like declaring a local &lt;tt&gt;std::function&lt;/tt&gt;. There has to be an awareness that this new object now holds the lambda and its references. If it leaves the scope you have to think harder about the lambda reference captures. Similar to &lt;tt&gt;StringData&lt;/tt&gt;&#160;too. If you let a &lt;tt&gt;StringData&lt;/tt&gt;&#160;leave the scope you have to think about the lifetime of its referent character array. I meann to say that a movable, returnable &lt;tt&gt;Cleanup&lt;/tt&gt; is familiar territory and we have the intuition required to deal with it.&lt;/p&gt;



&lt;p&gt;As for move-assignment, I think we don&apos;t really have a strong reason to forbid that either. If F can move-assign, just let it. Lambdas have deleted assignment operators so we&apos;re not talking about lambdas. If F is a nonlambda callable like &lt;tt&gt;std::function&lt;/tt&gt;&#160;we don&apos;t have to fret about allowing conventional value-type operations, and should just let the users decide what&apos;s useful to them. Move-assignment is necessary to be able to store these things in containers or use them as data members of assignable value types. They&apos;re not fundamentally different from &lt;tt&gt;std::function&lt;/tt&gt;&#160;in terms of lifetime concerns. They just have a special behavior that they&apos;re invoked upon destruction, but that&apos;s not so magical.&lt;/p&gt;



&lt;p&gt;Swapping &lt;tt&gt;Cleanup&lt;/tt&gt;&#160;objects isn&apos;t silly. I guess if we call them &lt;tt&gt;ScopeGuard&lt;/tt&gt;&#160;it sounds silly &lt;img class=&quot;emoticon&quot; src=&quot;https://jira.mongodb.org/images/icons/emoticons/smile.png&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;&#160;but it&apos;s logically fine. Those objects are generalized destructor behavior and in that case they could be used as data members of other objects, serving pretty much the same boilerplate-saving role as they did in the example given above with the foo.resize(oldSize) code. E.g. you can bind a Cleanup expression to a lambda and then move the lambda so that it carries its cleanup action along whereever it goes.&lt;/p&gt;

&lt;p&gt;&#160;&lt;/p&gt;</comment>
                            <comment id="3602102" author="redbeard0531" created="Fri, 5 Feb 2021 17:46:44 +0000"  >&lt;p&gt;This is better than writing custom types everwhere something like this is needed, both to avoid having to maintain the &quot;am I dismissed&quot; logic, and because &lt;tt&gt;&lt;span class=&quot;error&quot;&gt;&amp;#91;this, oldSize=foo.size()&amp;#93;&lt;/span&gt; { foo.resize(oldSize);&lt;/tt&gt;} is a &lt;b&gt;lot&lt;/b&gt; less boiler plate than writing a class with members, constructors and a destructor.&lt;/p&gt;</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                <customfield id="customfield_10050" key="com.atlassian.jira.toolkit:comments">
                        <customfieldname># Replies</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>7.0</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                <customfield id="customfield_12751" key="com.atlassian.jira.plugin.system.customfieldtypes:multiselect">
                        <customfieldname>Assigned Teams</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="25132"><![CDATA[Service Arch]]></customfieldvalue>
    
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10055" key="com.atlassian.jira.ext.charting:firstresponsedate">
                        <customfieldname>Date of 1st Reply</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>Sat, 13 Feb 2021 03:41:21 +0000</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10052" key="com.atlassian.jira.toolkit:dayslastcommented">
                        <customfieldname>Days since reply</customfieldname>
                        <customfieldvalues>
                                        2 years, 50 weeks, 6 days ago
    
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_18254" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname>Dependencies</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue><![CDATA[]]></customfieldvalue>


                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_10057" key="com.atlassian.jira.toolkit:lastusercommented">
                        <customfieldname>Last comment by Customer</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>true</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_10056" key="com.atlassian.jira.toolkit:lastupdaterorcommenter">
                        <customfieldname>Last commenter</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>alexander.golin@mongodb.com</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_11151" key="com.atlassian.jira.toolkit:LastCommentDate">
                        <customfieldname>Last public comment date</customfieldname>
                        <customfieldvalues>
                            2 years, 50 weeks, 6 days ago
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                    <customfield id="customfield_10051" key="com.atlassian.jira.toolkit:participants">
                        <customfieldname>Participants</customfieldname>
                        <customfieldvalues>
                                        <customfieldvalue>andrew.shuvalov@mongodb.com</customfieldvalue>
            <customfieldvalue>schwerin@mongodb.com</customfieldvalue>
            <customfieldvalue>backlog-server-servicearch</customfieldvalue>
            <customfieldvalue>billy.donahue@mongodb.com</customfieldvalue>
            <customfieldvalue>mathias@mongodb.com</customfieldvalue>
    
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                        <customfield id="customfield_14254" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Product Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>1|hytlhb:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hyf4vj:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>9223372036854775807</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                            <customfield id="customfield_23361" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname>Requested By</customfieldname>
                        <customfieldvalues>
                                

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_22870" key="com.onresolve.jira.groovy.groovyrunner:scripted-field">
                        <customfieldname>Triagers</customfieldname>
                        <customfieldvalues>
                                

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_14350" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>serverRank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>1|hyt7qf:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                    </customfields>
    </item>
</channel>
</rss>