I typically use them to have a simple (quick and dirty) modifiable field in a struct or for a pass-by-reference argument into a function. I presume there is no real performance difference between using one or the other in such a case?
Array is always a pretty fat jl_array from the runtime, always heap allocated, etc.
In contrast, RefValue is almost the same as a mutable struct with a single field plus convenience access functions. This means that the optimizer can see through Ref, and often stack allocate it or refuse to allocate it alltogether.
An especially important idiom is to use unsafe_store! / unsafe_load on pointer_from_objref on refs in order to fiddle with bits / reinterpret between arbitrary bitstypes. The compiler is quite good at optimizing out that kind of stuff. This would not work with Array.
yep, that’s one level of pointer indirection less than Array. However, mutable struct S s::Int end is still one less level of pointer indirection (and one less allocation).
I think that Refwas hijacked incidentally for this purpose, possibly following this suggestion. Cf
On 1.2-pre, ?Ref still does not mention that it has anything to do with broadcasting.
In retrospect I think that this choice was unfortunate, as it conflates semantics. Also, I am not sure that many users are aware that Ref{T} is not a concrete type.
Just the other day a colleague asked me how to make something behave as a scalar under broadcasting. I showed him Ref and he was suprised that he couldn’t find anything about it in the docs.
Ref doesn’t really have anything to do with broadcasting. It’s just a convenient, short-named zero-dimensional container that doesn’t have the overhead of the Array header. As long as Ref is a zero-dimensional container, I don’t see any conflating of semantics. Now, that view isn’t entirely historically accurate, as Refs were indeed previously “hijacked” and special-cased to behave like 0-dimensional arrays only for the purposes of broadcast, but these days they really are 0-dimensional like and they just behave appropriately.
I was imagining that Ref would only be transiently visible to users until the &x syntax landed, but that got tied up and slogged down. I’d still love to see that, then the choice of how we implement scalars would be entirely internal. It’s indeed the &x syntax that could unites the ccall and broadcast use-cases.
You can also use (x,) or [x] as 1-tuples and 1-vectors also broadcast (almost) entirely like scalars. The tuple will of course be more efficient than the vector.
I meant that Ref is now the de facto solution for escaping broadcasting.
You are of course right, and indeed any 0-dimensional container would do, so in this sense Ref isn’t special, but in practice Ref has assumed this role.
It would be somewhat cleaner if we had something like Scalar proposed in the above PR, with the sole purpose of just escaping broadcasting, and no shared meaning with anything else. This a style question, but I think an important one.