A more intuitive way to treat an object as a scalar in broadcasting?

I think it would make sense to have a more intuitive way to treat an object as a scalar for broadcasting. The canonical example, which new users ask about all the time, is when using in:

julia> [2, 3, 4] .∈ Ref([1, 3, 5])
3-element BitArray{1}:
 0
 1
 0

I don’t think the use of Ref to denote that an object should be a scalar is very intuitive, especially for users new to the language. Furthermore, this usage is not mentioned anywhere in the official docs that I can find, not even in the docstring for in. One has to stumble upon it on Discourse or Stack Overflow.

However, I don’t have a concrete suggestion for what the preferred syntax should be…

1 Like

If performance isn’t an issue, I go for [2,3,4] .∈ [[1,3,5]]. If there’s performance on the table then I use a 1-tuple instead (it requires one extra character ,). I find Ref cumbersome indeed — and the reason why it’s been promoted as an alternative is that there was a proposal to use &x for Ref(x) which could then be shared between ccall and broadcast, but it went nowhere.

1 Like

Yeah, I suppose [2,3,4] .∈ ([1,3,5],) is not too bad, now that I think about it. I should start using that instead of Ref. :slight_smile: I guess I’m biased because I come from R where I can do c(2, 3, 4) %in% c(1, 3, 5) and it “just works” the way I expect.

Edit:

Adding an example like

julia> [2, 3, 4] .∈ ([1, 3, 5],)
3-element BitArray{1}:
 0
 1
 0

to the docstring for in would probably be a good idea.

This was definitely a pain point for me initially, same use-case even. I previously did use the array or the tuple approach, but then I saw the suggestion to use Ref. I actually don’t find it too cumbersome to use although I agree that it isn’t something you are likely to stumble upon on your own.

I think it was once proposed to introduce a dedicated Scalar type, which I believe would be much more intuitive for newcomers to learn about. One problem with Ref is also that it’s mutable and will therefore always allocate, whereas Scalar could just be an immutable struct with a very minimal implementation.

2 Likes

I could get behind that, but calling it Scalar just feels wrong to me. It’s not a scalar; it’s a 1-element container! While it makes sense that you want broadcast to treat the thing it contains as a scalar, that’s not at all what the object itself behaves like.

So, yeah, the word Scalar might make sense to a naive user in the context of broadcast, but it’s wholly confusing everywhere else.

2 Likes

Good idea, would you make a pull request to add this? You can edit the file directly on GitHub.

3 Likes

There was a suggestion to use &x as sugar for this (https://github.com/JuliaLang/julia/pull/27608).

1 Like

I think the single element tuple is clear in its purpose. I wouldn’t want another way to do it unless it was somehow more efficient.

Sure thing:

2 Likes