-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
&<var> syntax to declare a scalar to broadcast with #27563
Comments
This particular syntax proposal has been discussed a bit before and if I recall there was some concern over the operator precedence for |
Searched again, and only found issue #25322 yet, but it is not related to |
The issue is not really one of precedence as it is of confusion between unary operators vs. function calls. We'd be making a distinction between |
Currently we define |
I looked at that a while ago and IIRC we had been relying upon that method in base for |
that is a fairly useless method but sticking Ref functionality into the bitwise and operator is distinctly punny. The unary operator syntax does not need to be related to the binary and operator, however. |
Maybe a good reason to deprecate the bitwise operators to something more readable (e.g bitwise_and, bitwise_or, bitwise_xor)? The don't really need to used enough to warrant having syntax, and it would remove the precedence question ( |
That was already discussed and decided against. |
That is a fair point. So is that a "no" on this proposal then? (FWIW I remain in favor.) |
We'd definitely need to simultaneously introduce the I don't really see a problem with having a special |
Yes, ☝️ |
Note that |
Another nice thing about this is that |
As I mentioned in #27608, if we do this it would seem valuable to consider uses of references beyond the I can see that this will work nicely for For example, can we use |
I like @andyferris's idea of getting more out of this syntax by using it for various kinds of references. |
In 1.0 the error is cryptic
This is probably going to scare off some new users. I prefer '&', but if you want to buy time until the |
That would be backwards-incompatible because variable names can start with |
|
The difference is that
This is important because the version 1.0 comes with a stability guarantee — code written for 1.0 should continue to work on 1.x. There are a few other characters that are already parsed as unary operators, and those can be used now:
|
@yurivish The release candidate of 1.0 lasted few hours only before the official release.
In my opinion, the lack of feedback implies that this rule can be relaxed somewhat, The current situation is bad, because octave and python users trying julia-1.0 after the holidays |
How would Python and Octave users encounter corner cases of a syntax that's unique to Julia immediately upon trying out the language? |
Because we use broadcast extensively, so this is one of the first thing we try. |
Starting from a concept that the notation sum(&(sin.(x .+ π))) being lowered to %1 = (Base.broadcasted)(+, x, π)
%2 = (Base.broadcasted)(sin, %1)
%3 = sum(%2) # w/o materialize(%2) The motivation here is to fuse the mapping and reduction. To make it more extensible, this can probably go through an additional indirection of lowering shield(bc::Broadcasted) = bc
shield(x) = Ref(x) Further extending the concept, how about "indexing by y .= sum(&(sin.(M .+ π))[:, .]) .+ v to do (without allocation) for i in 1:size(M, 2)
y[i] = sum(sin.(M[:, i] .+ π)) + v[i]
end (note that the loop fusion happens even though Writing this even for non-dotted expression (i.e., "array reference") inside y .= sum(&M[:, .]) .+ v Also, indexing by symbol other than |
Good point. Since what I proposed has to "shield" against two mechanisms,
I was thinking "Minimal shield"Suppose
Let's see how it plays in different contexts: # Proposed | In Julia 1.1
1: x .+ f(y, &identity(z)) | x .+ f(y, Ref(z)) # maybe disallow?
2: x .+ f(y, &identity.(z)) | x .+ f(y, broadcasted(identity, z))
3: x .+ f.(y, &identity(z)) | x .+ f.(y, Ref(z))
4: x .+ f.(y, &identity.(z)) | x .+ f.(y, Ref(broadcasted(identity, z))) The result of expressions 3 and 4 would be the same while expressions 1 and 2 probably have different results. This shows that you have to look at both "Uniform shield"Suppose more "uniform" rule:
The same examples now become # Proposed | In Julia 1.1
1: x .+ f(y, &identity(z)) | x .+ f(y, Ref(z))
2: x .+ f(y, &identity.(z)) | x .+ f(y, Ref(broadcasted(identity, z))) # changed
3: x .+ f.(y, &identity(z)) | x .+ f.(y, Ref(z))
4: x .+ f.(y, &identity.(z)) | x .+ f.(y, Ref(broadcasted(identity, z))) Now 2': x .+ f(y, &identity.(z)[]) | x .+ f(y, broadcasted(identity, z)) But this pattern seems to be more useful than single |
Thanks so much for enumerating those examples. Unfortunately they also make the prospect of doubling up the behaviors (to serve as both Ref & no-materialize) here much less exciting to me. I don't really like the behaviors of either variant. The part that is quite exciting to me, however, is the idea of using a |
Yeah, I guess adding multiple responsibilities to one syntax was not a good direction. I was thinking I didn't realize |
As suggested on discourse,
it would be lighter to replace
$Ref(s)
by&s
to declare that
s
should be treated as a scalar in broadcasting:@. f($Ref(s), t)
would become
@. f(&s, t)
Outside
@.
macros,&s
would be a shortcut forRef(s)
.The error message should be updated accordingly.
The text was updated successfully, but these errors were encountered: