{"id":8075,"date":"2017-04-06T14:24:35","date_gmt":"2017-04-06T22:24:35","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/?p=8075"},"modified":"2024-07-05T12:36:42","modified_gmt":"2024-07-05T19:36:42","slug":"why-vb2017-only-supports-consuming-ref-returning-methods","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/why-vb2017-only-supports-consuming-ref-returning-methods\/","title":{"rendered":"Why VB2017 only supports consuming ref returning methods"},"content":{"rendered":"<p>Hi VBers,\nLast week Klaus wrote an <a href=\"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2017\/03\/30\/whats-new-in-visual-basic-2017\/\">amazing post<\/a> detailing a number of improvements made to the Visual Basic IDE and language in Visual Studio 2017 (and he even forgot one, stay tuned for awesome). Regarding the new ref-return feature Jonathan Allen inquired as to why the design was so different from the one in C#. It&#8217;s not uncommon for considerations in one language to be different in the other or for the styles of the languages to yield different design decisions, even from the same people. But it&#8217;s a great question so I thought I&#8217;d write up a longer explanation for the VB design.\nTo put it bluntly, the capabilities around ref-returning method consumption in VB2017 are designed\u00a0to hedge VB\u2019s bets against\u00a0an uncertain future rather than to bring that feature into the mainstream (which it isn&#8217;t, even in C#).\nThe #1 scenario for ref returns is array slices&#8211;a\u00a0collection type being discussed for the .NET framework which will let you \u2018slice\u2019 off a subset of an array and hand that slice to some other code. We tried an earlier attempt of this with the ArraySegment(Of T) type but it has several drawbacks. Most importantly,\u00a0that its performance isn\u2019t at all comparable to accessing the array element directly. One reason for that is because it requires a lot of copying. So, prior to VS2017 we\u2019d need to write the slice type like this.<\/p>\n<div style=\"background-color: #f9f9f9;color: #000000;font-family: Courier New\"><span style=\"color: #007f00\"><\/span><span style=\"color: #0000ff\">structure<\/span> <span style=\"color: #2b91af\">Slice<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #0000ff\">of<\/span> <span style=\"color: #2b91af\">T<\/span><span style=\"color: #000000\">)<\/span>\n<span style=\"color: #0000ff\">\u00a0 \u00a0 private<\/span> <span style=\"color: #0000ff\">readonly<\/span> <span style=\"color: #000000\">_Array<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #2b91af\">T<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">)<\/span>\n<span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">private<\/span> <span style=\"color: #0000ff\">readonly<\/span> <span style=\"color: #000000\">_Offset<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #0000ff\"><span style=\"color: #0000ff\">integer\n<\/span><\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">sub<\/span> <span style=\"color: #0000ff\">new<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">array<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #2b91af\">T<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">)<\/span><span style=\"color: #000000\">,<\/span> <span style=\"color: #2b91af\">offset<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #0000ff\">integer<\/span><span style=\"color: #000000\">)<\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #000000\">_Array<\/span> <span style=\"color: #000000\">=<\/span> <span style=\"color: #000000\">array<\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #000000\">_Offset<\/span> <span style=\"color: #000000\">=<\/span> <span style=\"color: #000000\">offset<\/span>\n<span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">end<\/span> <span style=\"color: #0000ff\">sub<\/span>\n<span style=\"color: #0000ff\"><span>\u00a0 \u00a0 <\/span>default<\/span> <span style=\"color: #0000ff\">property<\/span> <span style=\"color: #000000\">Item<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">index<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #0000ff\">integer<\/span><span style=\"color: #000000\">)<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #2b91af\">T<\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">get<\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"font-weight: bold\"><span style=\"color: #0000ff\">return<\/span> <span style=\"color: #000000\">_Array<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">_Offset<\/span> <span style=\"color: #000000\">+<\/span> <span style=\"color: #000000\">index<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">end<\/span> <span style=\"color: #0000ff\">get<\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">set<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">value<\/span> <span style=\"color: #0000ff\">as<\/span> <span style=\"color: #2b91af\">T<\/span><span style=\"color: #000000\">)<\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"font-weight: bold\"><span style=\"color: #000000\">_Array<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #000000\">_Offset<\/span> <span style=\"color: #000000\">+<\/span> <span style=\"color: #000000\">index<\/span><span style=\"color: #000000\">)<\/span> <span style=\"color: #000000\">=<\/span> <span style=\"color: #000000\">value<\/span><\/span>\n<span>\u00a0 \u00a0 <\/span><span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">end<\/span> <span style=\"color: #0000ff\">set<\/span>\n<span>\u00a0 \u00a0 <\/span><span style=\"color: #0000ff\">end<\/span> <span style=\"color: #0000ff\">property<\/span>\n<span style=\"color: #0000ff\">end<\/span> <span style=\"color: #0000ff\">structure<\/span><\/div>\n<p>&nbsp;\nThe lines in bold are the problem. The getter\u00a0copies the element at that offsets and returns it. So whatever the size of the element code must pay the cost of copying it. Then the consumer has to copy that value to a local variable. And on the other side if someone wants to write to the array they have to copy the value to call the setter and the setter then copies it again to set the element of the array.\nAlso, because of this difference you can\u2019t modify a member of the element directly if T is a value type. So you couldn\u2019t say (imagine this slice is from an array of points):<\/p>\n<div style=\"background-color: #f9f9f9;color: #000000;font-family: Courier New\"><span style=\"color: #007f00\">&#8216; Doesn&#8217;t work.<\/span>\n<span style=\"color: #000000\">mySlice<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #7f0000\">3<\/span><span style=\"color: #000000\">)<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #000000\">X<\/span> <span style=\"color: #000000\">+<\/span><span style=\"color: #000000\">=<\/span> <span style=\"color: #7f0000\">1<\/span><\/div>\n<p>&nbsp;\nThe reason for that is because the <em>value<\/em> returned from mySlice(3) is a copy, not a reference to that element. So modifying it doesn\u2019t really mean anything. So today you\u2019d have to write:<\/p>\n<div style=\"background-color: #f9f9f9;color: #000000;font-family: Courier New\"><span style=\"color: #007f00\"><\/span><span style=\"color: #0000ff\">Dim<\/span> <span style=\"color: #000000\">temp<\/span> <span style=\"color: #000000\">=<\/span> <span style=\"color: #000000\">mySlice<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #7f0000\">3<\/span><span style=\"color: #000000\">)<\/span>\n<span style=\"color: #000000\">temp<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #000000\">X<\/span> <span style=\"color: #000000\">+<\/span><span style=\"color: #000000\">=<\/span> <span style=\"color: #7f0000\">1<\/span>\n<span style=\"color: #000000\">mySlice<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #7f0000\">3<\/span><span style=\"color: #000000\">)<\/span> <span style=\"color: #000000\">=<\/span> <span style=\"color: #000000\">temp<\/span><\/div>\n<p>&nbsp;\nSo, in addition to paying for all the copying I mentioned earlier the indexing operation happens twice;\u00a0once to get the value and once to set it. With a true array this doesn\u2019t happen\u2014there is a single index and the value is modified in place without being copied. These difference may seem small, but in certain high performance applications (*cough* games) the extra overhead is devastating. Enter ref returns. Now a slice default property (or indexer in C#) can be written which directly returns a reference to the underlying array index. That eliminates all of the overhead I just talked about. The index happens only once, and no copying takes place <em>unless<\/em> you store the value of that element in a variable or set that element to a different value. Other than computing the offset that performance is virtually identical to accessing the underlying array directly.\nNow, we haven\u2019t specifically added a slice type to the .NET Framework but it\u2019s something we&#8217;re thinking over adding one day. There are other design issues that need to be resolved but this was the very first thing needed to unblock them.\nIf you look at C# this release this one feature pulled in another feature, namely ref locals. There are also considerations around ref locals and decisions like ref re-assignment (making a local \u2018point\u2019 to another location) and whether ref locals are readonly by default and how to specify refness in all of the places a variable can be introduced, differentiating regular assignment from ref assignment, etc. that would all need to be solved in VB as well to enable the same production capabilities. That\u2019s a <em>lot<\/em> of plumbing.\nAnd in VB it would be even <em>more<\/em> plumbing because VB has extra functionality around ByRef such as passing a property ByRef. VB compiler development lead Jared Parsons has a great post detailing <a href=\"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2010\/01\/26\/the-many-cases-of-byref\/\">the many cases of ByRef in VB<\/a> that explains this. It doesn\u2019t really make any sense to return a property ByRef and handling ByRef in a late-bound context and so the language would work differently for ByRef returns that ByRef parameters (in addition to all the considerations in C#) which is confusing (<em>and<\/em> Jared would have to go update that post with yet more cases).\u00a0That\u2019s a <em>lot<\/em>\u00a0of confusion, syntax, and conceptual overhead to add to VB because C# added a feature that <em>might<\/em> be used to write one collection type <em>someday<\/em>.\nInstead we took a different approach. In short, we implemented <em>just enough<\/em> of the consumption scenario to allow you to do <em>exactly<\/em> with a Slice (or ref returning thing) what you can do with an array and <em>nothing more than that<\/em>. You can assign directly to the array element when you index it but you can\u2019t assign a reference from an array element to a local and assign back into the array later,\u00a0you can modify the value at that index in place, and you can pass that element ByRef but you can\u2019t return it ByRef. This means no new syntax and VB is protected <em>if<\/em> we add slice between VS2017 release and the next version of the language <em>and<\/em> slice becomes the collection type to end all collection types and a million APIs pop up everywhere overnight all returning things ByRef. And if that <em>highly improbable<\/em> nightmare scenario never happens the language bears no scars from it. And that\u2019s why the design is the way it is.\nYou can read the original design notes from last year <a href=\"https:\/\/github.com\/dotnet\/vblang\/blob\/master\/meetings\/2016\/LDM-2016-05-06-VB.md\">here<\/a> which briefly say what I\u2019ve said above. But that\u2019s the whole story. Nothing sinister or because VB was thought about at the last minute. It was a tactical decision made to target precisely the scenario for which the ref-return feature was added to\u00a0protect VB users from possibly important consumption scenarios appearing between releases while protecting VB from considerable feature creep of dubious value to its users. Feel free to leave any feedback below or to me directly on Twitter (<a href=\"https:\/\/twitter.com\/ThatVBGuy\">@ThatVBGuy<\/a>).\nRegards,\n<a href=\"https:\/\/twitter.com\/ThatVBGuy\"><strong>Anthony D. Green<\/strong><\/a>, Program Manager, <strong>Visual Basic<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi VBers, Last week Klaus wrote an amazing post detailing a number of improvements made to the Visual Basic IDE and language in Visual Studio 2017 (and he even forgot one, stay tuned for awesome). Regarding the new ref-return feature Jonathan Allen inquired as to why the design was so different from the one in [&hellip;]<\/p>\n","protected":false},"author":258,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7,195],"tags":[],"class_list":["post-8075","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-language-design","category-visual-basic"],"acf":[],"blog_post_summary":"<p>Hi VBers, Last week Klaus wrote an amazing post detailing a number of improvements made to the Visual Basic IDE and language in Visual Studio 2017 (and he even forgot one, stay tuned for awesome). Regarding the new ref-return feature Jonathan Allen inquired as to why the design was so different from the one in [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/8075","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/258"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=8075"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/8075\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=8075"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=8075"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=8075"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}