-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
make Base.setindex() public #55129
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
base: master
Are you sure you want to change the base?
make Base.setindex() public #55129
Conversation
I'm missing the point of this PR, as far as I can tell this is already public:
|
Note the difference: julia> Base.ispublic(Base, :setindex!)
true
julia> Base.ispublic(Base, :setindex)
false |
Not sure what's the status here. Should I do some update of this PR or ...? |
If |
I'm not familiar with documentation generation, could use some pointers on where to update things :) |
This comment was marked as outdated.
This comment was marked as outdated.
If the function is to be made public, we'd need to decide if it's just for tuples, i.e, will adding methods for other collection types be allowed. Perhaps we could instead define something like Adding new methods would negatively affect abstract return type inference in the extreme case where the type of the input collection is unknown (inferred as |
(Removing my review request as @nsajko has got this handled 😉) |
Not sure what you exactly the issue with extending As the semantics of the function is pretty clear, and it's already extensively used in the wild (including new method definitions), what specific issues do you see with marking it
Tbh, I don't see a reason to do that. Defining separate functions for every type, instead of methods of the same functions, goes directly against Julia multiple dispatch design and practice. |
I'm referring to the "world splitting" optimization, see the EDIT: I only mentioned this issue for completeness. IMO it's secondary to proper documentation. |
Base.setpropertyonce! | ||
Base.propertynames | ||
Base.hasproperty | ||
Base.setindex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May I ask, Is there a logic to this specific location, between hasproperty
and getfield
? Mostly just curious, I don't really have a better suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, perhaps the doc string would fit better into the Collections and Data Structures page? Under Indexable Collections I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Properties/fields and indices are kinda close conceptually, and they are exactly the same for tuples and namedtuples (the types setindex
is defined for). So it seems to make sense to put it here.
But any location works for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it can't go under "Indexable collections" as-is, because of the "fully implemented by" list in that section. The list includes types which don't implement setindex
...
FWIW, given that |
Still not sure how these considerations are relevant to marking Btw, a lot of high-performance code uses StaticArrays, and with them loaded one has at least 6 |
bump... |
bump :) |
bump... anything else I should do here? |
and another bump |
bump, anyone?.. |
should be a tiny change, any issues with it?.. |
Actually the semantics are not at all clear. The behavior of julia> Base.setindex((1, ), 10, 2)
ERROR: BoundsError: attempt to access Tuple{Int64} at index [2]
Stacktrace:
[1] setindex(x::Tuple{Int64}, v::Int64, i::Int64)
@ Base ./tuple.jl:57
[2] top-level scope
@ REPL[34]:1
julia> Base.setindex((a=1, ), 10, :b)
(a = 1, b = 10) Ideally a generic function should have one docstring (per arity). In other words, there should only be one meaning for a generic function. Consider the """
setindex!(collection, value, key...)
Store the given value at the given key or index within a collection. The syntax `a[i,j,...] =
x` is converted by the compiler to `(setindex!(a, x, i, j, ...); x)`.
...
""" (I know there is a second docstring for I don't think
If we decide to add |
Comparison to julia> setindex!([1], 10, 2)
ERROR: BoundsError: attempt to access 1-element Vector{Int64} at index [2]
Stacktrace:
[1] setindex!(A::Vector{Int64}, x::Int64, i1::Int64)
@ Base ./array.jl:1021
[2] top-level scope
@ REPL[6]:1
julia> setindex!(Dict(:a => 1), 10, :b)
Dict{Symbol, Int64} with 2 entries:
:a => 1
:b => 10 So the consequence would be to write a docstring for |
My comparison to the iterate(iter [, state]) -> Union{Nothing, Tuple{Any, Any}}
Advance the iterator to obtain the next element. If no elements remain, `nothing` should
be returned. Otherwise, a 2-tuple of the next element and the new iteration state
should be returned. Note that the docstring provides a single definition for But you bring up an interesting point. In my previous comment I explicitly ignored the second docstring for Throw a bounds error for an array: julia> x = [1, 2];
julia> x[3] = 10
ERROR: BoundsError: attempt to access 2-element Vector{Int64} at index [3] Extend a dictionary: julia> d = Dict(:a => 1);
julia> d[:b] = 2
2 Set multiple indices at once for an array: julia> a = [1, 2, 3, 4];
julia> a[[2, 3]] = [10, 20];
julia> a
4-element Vector{Int64}:
1
10
20
4 So,
No, that's not the consequence. Please take a look at the example docstrings that I provided in my previous post. |
Sorry, forgot about this for a while!
Added. |
It looks like my concern about the generic definition of I think |
I think the only reasonable way to define This function is well-defined and documented, naturally leading to a widespread use in many packages.
would cause quite some breakage if implemented. That's one of the reasons to mark it public – because it effectively is already. I haven't seen new triage comments here, so assuming they still agree with the PR. |
My concerns were raised after that triage call, so triage may not have considered the issues that I raised.
I agree there is some logic to that, but
We shouldn't be encouraging the usage of Base internals. This PR sets a bad precedent. Once someone starts using a Base internal they can open an issue requesting that the internal is marked public because "it's used widely in the ecosystem." Consider the following two code chunks. The first one uses
|
Note that
It's clear that you disagree. Neither of us can merge this PR anyways, so now it's up to Julia developers. |
Semiannual bump |
Sorry this has languished for so long, @aplavin. Looks like this will need to be rebased since there's a merge conflict. @oscardssmith, since you commented on behalf of triage when the group discussed this PR last year, can you speak to whether any of the concerns raised in this thread (after triage occurred, so would have been raised independently) were discussed at the time, or if there were any takeaways beyond "merge it"? |
To be fully honest, I don't really remember the triage discussion here. |
Not surprising given how much time has passed since then. Worth re-triaging, do you think? |
yeah. Can you summarize the issues for triage to consider? |
I'm probably not the one to do that as I haven't taken the time to understand them myself, tbh. 😅 |
as far as I can tell, @CameronBieganek 's observations of potential inconsistencies in the existing semantics of |
I see a handful of concrete concerns, the biggest one being that the current documentation does not speak to any generic behaviors. I think that could be ok — I'm sure we publicize other functions that are inherently not generic — but the persistent analogies to Even within the narrow existing documentation for just
|
Given the wide variety of indexing behaviors in Base and in the wild, I think it's best to view (To clarify, the syntax transformation for square bracket indexing is well-defined. It's just that the desugared functions
|
I struggle to see what you mean here.
What is not generic here? My suggestion going forwards is to treat But note that making it public (this PR) doesn't mean that methods to support all potentially relevant types have to be added immediately. |
I can see @CameronBieganek's point. For example, I honestly don't know what the invariants should be for
My main hesitancy in making this public without further work on its documentation is that it won't actually resolve any issues. It's not even public now and there are a number of issues/PRs trying to figure out what its behavior should be (#43155, #54508, #43338, #33495). Even more concretely, there's #46453 which tries to define (some of) its implementation requirements in an updated docstring. Making this public when we know there are folks currently extending it—and doing so without an understanding of how they should be extending it—seems to only make it harder to merge something like that in the future. |
also FWIW I'm not even sure that |
Given that Julia already has generic functions that return a copy of a collection with some values changed, @mbauman's questions about julia> replace(Bidiagonal([1,2,3],[4,5], :L), 2 => 30.)
3×3 Bidiagonal{Float64, Vector{Float64}}:
1.0 ⋅ ⋅
4.0 30.0 ⋅
⋅ 5.0 3.0
julia> replace((1,2), 2 => 3.)
(1, 3.0)
julia> replace([1,2], 2 => 3.)
2-element Vector{Float64}:
1.0
3.0
julia> replace([1.,2.], 2 => 3)
2-element Vector{Float64}:
1.0
3.0 It's not like
I personally never suggested |
Triage accepts @mbauman's summary and thinks that we need to wait until that's all figured out to make it public. The standard is "beyond a reasonable doubt" that it's the right API long term, otherwise we can just put it in a package (e.g. SetField.jl or Accessors.jl) |
Interesting, I didn't expect that This means opening issues/PRs to remove usage/overload of |
No, that is not a reasonable thing to do. From the FAQ, we do not discourage the attempt to create packages that expose stable public interfaces while relying on non-public implementation details of Julia and buffering the differences across different Julia versions. |
Ok, I see! Basically, the main reason for me opening this PR was to get a "guarantee" that such a widely used function is considered public and can be responsibly used in packages. But given that you (not you personally, Julia devs in general) encourage packages using and overloading this function anyway, my original point becomes kinda moot. |
"We" do not encourage use of internals, no. |
If I were maintaining StaticArrays, I would not take any further action until Julia settles on a final API for |
setindex() is a widely used well-documented function, it should be marked public, right?
Not sure what's the right way to make a function with multiple methods public, please correct me if I'm wrong here!