-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
implement @fill([0, 0], 2)
#41209
Comments
Copying by default seems even more confusing to me. This would cause lots of allocations any time an array is filled with mutable objects. There are many situations where you actually want to fill an array with references to the same mutable object, for example pretty much any time you don't plan to mutate the items in an array themselves, which is a frequent use case when working with DataFrames. Implicit copies can also lead to wrong results in some cases, for example Measurements.jl uses references to other measurements to keep track of correlations. It is also not clear how this should behave for recursively mutable objects: if it's just the default I think we should just document the current behavior better. Once you have a basic understanding how memory and references work, the current behavior makes a lot of sense, so I don't think that needs to be changed. One thing we could do is add a |
Fully agree with Simeon. Calling |
Does that really add something over just using an array comprehension though? |
Not really, it's just shorter. |
I believe those discourse threads signal that the documentation could be improved. In fact, the expression |
Is it wrong to say |
Could I ask you submit a PR - and then we see how this plays out? |
julia> ismutable(1 => Ref(2))
false while this will still run into the same issues as mentioned above. |
Thanks. I (and several others, it seems) am still struggling with |
There's no if. All elements always are the same object. The only time it's observable, though, is if there's something mutable. |
I concede that there isn't really a sensible way to do this. We would need to use either a macro or a function I'm not too invested in this anyways---I just noticed that this question came up a lot on Discourse. |
On second thought, could we branch on julia> myismutable = !isbits
#76 (generic function with 1 method)
julia> myismutable([1, 2])
true
julia> myismutable(1 => Ref(2))
true
julia> struct A
x::Vector{Int}
end
julia> myismutable(A([1, 2]))
true |
That wouldn't make any difference, since |
Yeah, I just noticed that isbitstype(typeof(x)) && return x for its first line.
But that's fine. We want it to be a no-op for |
That wouldn't address any of the issues raised by Jeff and myself above though. |
@simeonschaub , right, good. Is |
There's clearly some demand for the copying behavior. In order to keep the current Though I don't have any data to back up this hypothesis, I would guess that most people who use |
That's a good question. I don't think the current wording is very accurate, it should probably say "object contains any references" rather than "object is a reference". I also agree with Matt that "all elements will refer to the same object" is not really different between objects with and without references, we should clarify that the only difference is that this is directly observable with references, while you wouldn't be able to tell for immutable objects. |
My inclination (as always) in these situations is to introduce a new type name and rely on multiple dispatch, as opposed to introducing a new function name. The call would then be something like The benefit over A downside has something to do with a proliferation of wrapper types and not a lot of great idioms for dealing with them, especially when there are multiple wrappers. |
As far as I can tell, you could define |
I also think that just updating the documentation a bit would be fine. We could add a sentence that suggests using a comprehension if you want to make copies of a non- Add this to
|
That seems right! I already mentioned strings earlier. I am pretty confused about strings with respect to mutability. (Because
though I don't think there is any non- |
See if the my suggested changes to |
To be clear, I already understood that. I just noticed that the |
I'll just put in a vote here for making a copying fill (just the top level, not a deep copy) the default in 2.0 and a non-copying fill the "advanced" version. Whether that's a kwarg switch or another function, could go either way. Though if someone can show there's a really common case that would get slowed down and/or become annoying because they keep having to add a new argument to avoid copying, that would be a good reason to not do this. |
This seems simple to me... One just introduces a new function, say
etc. And (which has been mentioned) there could be a |
e.g. fillf(f, args...) = [f() for k in keys(fill(nothing, args...))] It seems like you might as well pass the indices to |
Simeon listed a number of these in this comment above: #41209 (comment). It's not about performance or annoyance — it's about semantics and what you should expect from the language. At its heart, I think this is a natural language/computer language mismatch. I'm hopeful that the new documentation in v1.8 will help some. Maybe there'd be a different English-language verb that would more clearly express this behavior, but I'm doubtful we could find anything dramatically clearer; in the natural world we typically can't put the same thing in multiple places at once. I don't think a higher order function like |
yes, that will help. Much appreciated.
I disagree here. Some sort of convenience function for pre-allocating an array of arrays could be very helpful. |
I think @mbauman is saying that if a naïve user knows that they can do It could still be worth having a function like |
OK, fair enough. I think there are two points of having a |
The main advantage I can see for |
Yeah, my reasoning behind saying that
I'm not averse to a more succinct comprehension-like syntax, but I'd want something whose name is a little more clearly distinct from |
fill([0, 0], 2)
behavior for 2.0@fill([0, 0], 2)
I'm not that worried about beginners—they're going to be confused at some point and need to learn this either way and as you say, |
Given the change in the name of this issue, can we remove the "breaking" label? |
I wonder if VSCode/Lint could help flag places where any value in a |
Original Title: Change
fill([0, 0], 2)
behavior for 2.0The behavior of
fill
when its first argument is an array is to create an array of arrays, where each of the elements is a reference to the exact same array in memory. This is counterintuitive to many users (see Discourse links below), and it seems kind of pointless. I propose that in 2.0fill
with an array input should fill the resulting array with copies of the input array.Below are some examples where this came up on Discourse. There may be more.
https://discourse.julialang.org/t/simple-question-about-assignment-to-a-vector-of-vectors/62744
https://discourse.julialang.org/t/fill-anarray-2-behaviour/22429
https://discourse.julialang.org/t/initialization-of-array-of-arrays-with-fill-ones-1-2-2-only-one-vector-is-created/48048
https://discourse.julialang.org/t/how-can-i-fill-an-array-with-empty-2d-arrays/60895
The text was updated successfully, but these errors were encountered: