Skip to content
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

In-place assignment syntax #4019

Closed
johnmyleswhite opened this issue Aug 11, 2013 · 19 comments
Closed

In-place assignment syntax #4019

johnmyleswhite opened this issue Aug 11, 2013 · 19 comments

Comments

@johnmyleswhite
Copy link
Member

In #3950, people restarted the debate about an in-place assignment operator. The preferred proposal was a .= operator that would make things like A .= B + C equivalent to something like +!(A, B, C).

If one follows a convention in which the mutated arguments for an in-place operation are always the first arguments, then it's trivial to translate between the proposed syntactic sugar o1, o2, ... .= f(i1, i2, ...) and the existing solution, f!(o1, o2, ..., i1, i2, ...). Following a suggestion from @lindahua, the Distributions package has tried to structure its functions so that in-place and pure functions can be readily translated back-and-forth in this way.

Pros:

  • This solution makes it trivial to take pure code and transform it into in-place code by simply replacing .= with = in most assignment calls.
  • The convention of always situating mutated arguments in the same place for all functions means that it will be easy to define alternative syntax instead of .= if we can't agree on the addition of a new assignment operator.

Cons:

  • The proposed solution requires that we introduce a large chunk of new functions like +!, -!, etc. Many of these exist in NumericExtensions, but committing to this proposal requires making the newly document ! convention into something more meaningful in the language. More problematically, this proposal makes the suffixes of function names into something more than a mere convention. Arguably what we want is something built into the language at a deeper level.
  • Many existing functions break the argument order convention needed to make the proposed translation step easy. Although functions like A_mul_B work this way, functions like rand! do not. Making the language consistent with the proposed argument ordering convention would involve massive code breakage.

I think this proposal isn't great, but I wanted to get the debate going again.

@kmsquire
Copy link
Member

For reference, here are the current bang functions exported in base:

broadcast! cholpfact! tril! empty! quantile!
broadcast_setindex! eigfact! triu! filter! bfft!
conj! factorize! flipbits! intersect! dct!
copy! hessfact! append! map! fft!
fill! isposdef! insert! merge! idct!
ipermute! ldltd! pop! setdiff! ifft!
nthperm! lufact! prepend! setindex! plan_bfft!
permute! qrfact! push! splice! plan_dct!
reverse! qrpfact! resize! symdiff! plan_fft!
select! scale! shift! union! plan_idct!
shuffle! schurfact! unshift! rand! plan_ifft!
sort! svdfact! add! randbool! readbytes!
bkfact! svdvals! complement! randn! unsafe_copy!
cholfact! symmetrize! delete! median! unsafe_store!

@mlubin
Copy link
Member

mlubin commented Aug 11, 2013

How do you handle cases where the assigned variable is present in the other arguments to the function, e.g. A .= A*B? Implementing this is somewhat tricky, and it depends on the algorithm whether extra storage space is needed. If we have operators like this, they need to be able to handle anything that the user might imagine they want to do.

@kmsquire
Copy link
Member

I could imagine annotating the parameters to functions to indicate which values are outputs, and letting the compiler use that as a hint as to where the LHS variable might go. But it sounds somewhat complicated.

@Keno
Copy link
Member

Keno commented Aug 11, 2013

Jeff and I had discussed allowing something like +(a::Array,b::Array;out=similar(a)) which the compiler could use as a hint.

@StefanKarpinski
Copy link
Member

The out keyword idea is generally pretty appealing. I guess the calling convention could be that the operation on the RHS is supplied with the LHS as the out keyword argument when the .= operation is used (or := or whatever).

@johnmyleswhite
Copy link
Member Author

An out keyword would work for me. How would we handle multiple outputs? And will the compiler be able to inline the keyword argument that it's efficient. Dahua has shown me examples of keywords coming with a big cost inside of loops.

@JeffBezanson
Copy link
Member

Compile-time sorting of keyword arguments isn't implemented yet but will be.
On Aug 12, 2013 10:50 AM, "John Myles White" [email protected]
wrote:

An out keyword would work for me. How would we handle multiple outputs?
And will the compiler be able to inline the keyword argument that it's
efficient. Dahua has shown me examples of keywords coming with a big cost
inside of loops.


Reply to this email directly or view it on GitHubhttps://github.com//issues/4019#issuecomment-22498583
.

@pao
Copy link
Member

pao commented Aug 12, 2013

Syntax consideration: I know := has baggage, but with the . meaning "elementwise prefix" in so many places, including .==, I'm not sure .= is going to be a good choice.

@StefanKarpinski
Copy link
Member

yeah, that's a fair point, @pao.

@kmsquire
Copy link
Member

I'm wondering if the interpretation of .= as "elementwise assignment" might actually be reasonable? (But I'm okay with := or whatever.)

@kmsquire
Copy link
Member

(To clarify, reasonable as "elementwise assignment" and used for inplace assignment...)

@StefanKarpinski
Copy link
Member

If the semantics we pick are element-wise, .= seems better, while for in-place := might be better. There's also the issue of introducing a lot of new operators and ambiguous operators, which a : prefix seems better for, as in A :+= B meaning +(A,B,out=A).

@JeffBezanson
Copy link
Member

:= does traditionally refer to mutating assignment, so the meaning is pretty close.

@JeffBezanson
Copy link
Member

dup of #249

@StefanKarpinski
Copy link
Member

:= does traditionally refer to mutating assignment, so the meaning is pretty close.

Reference? I thought this was just the name for assignment in some languages, e.g. Algol and Pascal. In Mathematica it's the difference between immediate and delayed assignment, iirc.

@ivarne
Copy link
Member

ivarne commented Aug 14, 2013

Go uses := to introduce a new variable where the type is infered from the value that is assigned, so that you don't have to declare the type fo the variable.

@StefanKarpinski
Copy link
Member

Yes, that usage I was aware of.

@JeffBezanson
Copy link
Member

I'm thinking mostly of pascal, but := is commonly used as an updating assignment operator in pseudocode, to distinguish it from mathematical =.

@stevengj
Copy link
Member

Fixed by #17510, although we won't get the full power of fusing in-place assignment until .+ etcetera turn into fusing calls ala #16285.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants