4
let a = ref 0
let f (x: byref<int>) = x

f a // type error

System.Int32.TryParse("123",a) // works

f a being a type error is puzzling to me since a can be passed into .NET library methods with a byref<int> type. Why?

Edit: I think I really explained the question poorly. The type of System.Int32.TryParse is string * byref<int> -> bool and yet it works. So why can't I pass a into a function of type x:byref<int> -> int? That is all I am asking.

Marko Grdinić
  • 3,798
  • 3
  • 18
  • 21
  • What's the exact error? – TheQuickBrownFox Jul 29 '17 at 08:27
  • May be a duplicate of https://stackoverflow.com/questions/5028377/understanding-byref-ref-and – rmunn Jul 29 '17 at 08:31
  • error FS0001: This expression was expected to have type `byref` but here has type `int ref` – Marko Grdinić Jul 29 '17 at 08:32
  • I understand that the compiler is converting the reference to `byref` in the call to `TryParse`. What I am wondering is why isn't it doing for functions on the F# side? – Marko Grdinić Jul 29 '17 at 08:33
  • @rmunn No, I can't see this particular example being addressed in the question you linked. – Marko Grdinić Jul 29 '17 at 08:34
  • It explains the difference between `ref` and `byref`, which are two different things. – rmunn Jul 29 '17 at 08:42
  • Yes, I understand that `ref` is a class and `byref` is a pointer. What I am wondering is whether there is an explicit reason why the implicit conversion during method calls is not being done on the F# side. Maybe instead of asking this here on SO, I should open an issue on the F# Github repo and ask there? – Marko Grdinić Jul 29 '17 at 08:46
  • The reason why this thing bothers me is because I am working on a language that compiles to F# and it makes the semantics of references wonky to have special cases like this. – Marko Grdinić Jul 29 '17 at 08:48

2 Answers2

5

This feature is described in section 8.13.7 of the F# spec. The ability to use a ref when a byref is expected is enabled by a "type-directed conversion", but these are applied only on member invocations, not on regular function applications.

kvb
  • 54,864
  • 2
  • 91
  • 133
1

The only thing I am seeing wrong with that code is the Type Annotation is incorrect, try :int ref instead of byref<int>

Full code:

let a = ref 0
let f (x: int ref) = x

f a // type error

System.Int32.TryParse("123",a) // works

Edit: Sorry, I misunderstood your question. So this one is a bit vague on F#'s part, I do think F# needs to improve it's error messages a bit. What is happening is since C# did not originally have tuples, they needed out parameters in order to return multiple values. So when you see a signature like byref<int>, that is .NET's way of telling you that is the signature of an out parameter, out parameters are for C# only. More reading here.

JosephStevens
  • 1,668
  • 1
  • 15
  • 17