Docs: The example on byref returns doesn't return a byref and is confusing

Created on 6 Jan 2020  Â·  5Comments  Â·  Source: dotnet/docs

This page has the following example of a function that returns a byref:

```f#
let safeSum(bytes: Span) =
let mutable sum = 0
for i in 0 .. bytes.Length - 1 do
sum <- sum + int bytes.[i]
sum

let sum = safeSum(mySpanOfBytes)
printfn "%d" sum // 'sum' is of type 'int'
```

However, safeSum does not return a byref. The local mutable value is already dereferenced before returning from the function. This can be seen when you try to take the address of the returned value, or when you inspect the signature of the function, which is C.safeSpan : bytes: Span<byte> -> int.

As is elsewhere explained, you can cannot let a byref escape its scope and here the compiler automatically dereferences the mutable. To have it return a byref value, have it refer to a mutable value outside its scope. This, however, is not possible with let-bound local functions (though I noticed if you make the function module level and sum module level and mutable, it works).

The text also says:

To avoid the implicit dereference, such as passing a reference through multiple chained calls, use &x (where x is the value).

It took me a long time to understand this, as it is not possible with the given example, and it suggests an extra operation. It turns out that you can apply & to the function directly, by prepending it (as in the next example on the page). This seems to be the intent of this line, but I couldn't distill it given the example.

I suggest some or all of the following fixes (and willing to make the PR for it):

  • Fix the example and explain that the mutable must be scoped module level, class level or instance level
  • Explain that byref-returns on let-functions is limited to global scope
  • Explain the auto-dereferencing inside the function (if the value is mutable) and outside the function on the returned byref, specifically:

    • Explain that returning a mutable as-is will be dereferenced before the function returns

    • Explain that to create a byref-return, you must explicitly return the address, like &sum

    • Explain that this returned reference is auto-dereferenced upon consuming (as is explained now), unless the function-call or method-call is prepended with the & operator

    • Explain that taking the reference of the returned value after consuming creates an inref, which is not the same will operate on a copy.

We might also add a note that explains that it is not possible to have tupled byref-returns.

And we might want to add a note on auto-tupling of byref and outref parameters, like with let (x, y) = Int32.TryParse("123") (here, the out-parameter is consumed on the lh-side).


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Area - F# Guide Pri2 doc-bug dotnet-fsharprod

All 5 comments

As an aside, the bot screwed up my code sections, where can I report that as a bug or is this already known? (fixing it after-the-fact, but this is how it looked)

image

Thanks @abelbraaksma. Do you mind opening an issue at https://github.com/microsoftdocs/feedback/issues for the feedback functionality?

@mairaw Sorry, I deleted my last comment, I misunderstood. Sure, no problem, I'll do that.

No problem. But just to be clear. The feedback you have here for the F# content is the right place. I was just asking for a new issue regarding the feedback bot comment you had earlier. That would be in a separate place.

Do you mind opening an issue at https://github.com/microsoftdocs/feedback/issues for the feedback functionality?

Done, see https://github.com/MicrosoftDocs/feedback/issues/2398.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stanuku picture stanuku  Â·  3Comments

tswett picture tswett  Â·  3Comments

ike86 picture ike86  Â·  3Comments

gmatv picture gmatv  Â·  3Comments

sebagomez picture sebagomez  Â·  3Comments