-
-
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
a, b... = [1,2,3] #2626
Comments
Should we add |
In some cases that would be easy but it won't always. Having a |
Ah, of course, the |
|
Well, they are actually a bit different. |
Ah, that's true, but the |
Wouldn't it be possible to simulate matlab-style |
No, this does not tell the function how many outputs are requested. And actually, in |
But it does result in telling the iterator how many arguments are necessary, so it seems you could write the function as a continuation iterator to weakly simulate matlab's varargout (the sane version where you just do lazy computation) |
We could generally support Matlab's varargout if we did it lazily and changed the protocol for destructuring a little bit. The idea came up in the discussion of factorization objects. I.e. if |
Before implementing this maybe it would be good to check whether a more general approach to destructuring assignments is welcomed. Basically, every function f with a fixed bijective inverse function inv(f) can be used to write
examples for f are tupel composition and list composition from head and tail |
Yes, you can do that, but it's not a new capability added by |
I found myself wanting this syntax yet again today. I think we should consider this. |
(Match.jl has this) |
There are some design issues here, primarily: what should the type of |
Here's an interesting example that begins to address the issue. julia> a, b, c = countfrom()
Base.Count{Int64}(1,1)
julia> a, b, c
(1,2,3) This works as expected, but what if "splatting" was used on one of the variables? In the case that In the case that an iterator is not the right choice, though, the question of mutability (tuple vs. array) definitely seems to be worth debating. |
Yes, it does seem that returning a |
Should of course be taken with a large grain of salt and I'm not saying we should just follow the majority opinion here, but I was interested in what people naturally expected this to do and did a quick survey on Slack: I was especially surprised that so many people considered returning a tuple for arrays the most useful of all the options, since I would have imagined that returning a vector would be generally preferred. As discussed on the triage call, throwing an error if the rhs isn't a tuple until we have made up our minds about all the other cases might also be a very viable option. Regarding other languages, I found rust has something a bit like this, but as part of their more general match syntax. They only support slurping for arrays (no tuples, at least for now) with Since we currently disallow vector expressions on the lhs of assignments, a more speculative proposal would be to support that syntax for destructuring as well, with the difference that |
Interesting. I can see the case for collecting everything to tuples because that makes it as similar as possible to varargs. But I think that option is horribly NON-useful. It's giving special syntax to the operation "take the tail of this data structure and convert it to a tuple". Why would you have syntax for that? It's very slow and type-unstable for basically every case except tuples. The comparison to varargs is not as reasonable as it seems at first, because we always need to splat out function arguments into a virtual tuple first to inspect all of their types for dispatch. And indeed, splatting large collections is slow. It's a somewhat common performance trap. So trying to be like varargs here would be intentionally copying this negative aspect of the language.
I think it's nearly the same thing. Of course rust has different concerns about mutability that make it hard to copy directly though. |
Yes, given that, I think probably the best way forward here would be to go with E, i.e. throw an error for anything that's not a tuple, for 1.6, since returning a tuple here should be pretty uncontroversial and probably also the most common case people want to use this syntax for. That would enable us to revisit the other cases later on, once people have already used this syntax a bit, so perhaps we can make a better informed decision then. |
In case they're of any interest, here are some emails discussing these questions on a Python developer mailing list in 2007. Not sure how useful the Python perspective is, but thought they were interesting. |
In order to pin down the semantics, it would be interesting to see what concrete semantics people want this to replace. Eg I could imagine a, b... = c replacing a, b = first(c), c[(begin+1:end)] but also variations with It is not clear that any of these is preferable to the other. Because of this, I think that just using an explicit construct on the RHS is a reasonable alternative. |
Yes, I agree that finding a semantic that works well for arbitrary array types and iterators is hard, but I think it would be a real shame to give up on this nice syntax altogether. JuliaDiff/ChainRulesCore.jl#128 (comment) is just one example where this would be really useful if it worked at least for tuples. If we only allowed this syntax for tuples for now, I don't see how this would be problematic semantically. |
Restricting to tuples would be somewhat confusing, as the If the user really wants tuples, why not just f(t) = first(t), Base.tail(t) # please someone invent a snappy name for f
a, b = f(t) |
It wouldn't be a syntax error, it will just error because the analog of
Sure, but you could make exactly the same argument against pretty much any syntax feature. I think what |
I understand that you have a specific use case in mind, but from the discussion it seems that others have a different one (ie it should work for One great feature of the current destructuring is that it just works for anything iterable, loosely coupling syntax and types via the iteration interface. Introducing
|
A good candidate might be |
|
Would it make sense to introduce this functionality as a |
Yes, and in a package. |
Slurp in the middle would be great too: a, b..., c = 1:5 |
Yes please, equivalent to python first, *_, last = fun() |
This should now work on Julia nightly |
This would be a very nice syntax for taking head and rest. Likewise
a..., b = [1,2,3]
might be good for slurping the initial elements intoa
and the tail element intob
.The text was updated successfully, but these errors were encountered: