-
-
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
extensible bounds checking removal #7799
Comments
Yep, for me this is a priority with 0.4. My presumption is that the right way forward is to add the |
I'd recommend we rename the current @boundscheck 1 <= i <= length(a) || throw(BoundsError()) as a declarative statement. |
I'm wondering if having both of those |
Whoops! Combined => defined |
Users won't see both. |
Okay, thanks for the clarification. Cheers! |
Another strategy would be:
This would be extensible, and also stop |
That seems like an interesting strategy. |
That does sound like a good approach. The existing design comes from (1) not wanting to add names, (2) considering the behavior with inlining a feature. The idea was to automatically catch To really break this into orthogonal components, you'd define |
Yeah, I too worry that it's a bit ugly. |
You also may want to create a type that can't have its bounds-checks disabled. For example, there are times where you really don't want to check bounds upon construction (see examples in #4044). In such cases, you might want to implement a |
My original thought was that we'd define a The orthogonal design is clearly less verbose. Ideally if you define As far as ugliness of library code, if unsafe_getindex(x::MyType, i) = @inbounds x.a[i] which doesn't seem so ugly. |
Yep, fair enough. I think this could work. Perhaps the best argument for the other approach is that it's part of a whole new suite of capabilities that stem from being able to talk directly to the compiler. |
Returning to this issue, I think there are cases where we don't want @inbounds fx1 = evaluate(f, A[ifirst])
@inbounds fx2 = evaluate(f, A[ifirst+=1]) This is only okay because at present we can't inline function-valued arguments, so we can never inline @inbounds v1 = A[ifirst]
fx1 = evaluate(f, v1)
@inbounds v2 = A[ifirst+=1]
fx2 = evaluate(f, v2) which would be safe, but is awkward. In general the effects of |
I've had the same thoughts. It would be a bit of a pity to not have a way to |
Another syntax that this should ideally be able to support is iteration loops like: @inbounds for elt in A
…
end This is a tough case because we've generally talked about function next(itr, state)
@boundscheck checkbounds(itr,state)
@inbounds x = itr[state]
return (x, state+1)
end This is effectively #10614 (comment) with per-method compilation settings… and unfortunately #8227 would not be able to support this sort of thing. |
That's a good point. I think the Unsafe/Unchecked module proposal from #8227 could do this: Base.next(itr, state) = (itr[state], state+1)
Base.Unchecked.next(itr, state) = @inbounds (itr[state], state+1) We could have a If |
I'm still very hesitant about having separate functions (be they It also just seems like having two functions is asking for trouble. It's the kind of thing that would drive me batty during debugging if one happened to have an error while the other didn't. I know the typical way to write these functions will be |
I think you are right that two generic functions is not really a viable solution if both The problem is that, at the codegen level, either we make I'm left wondering how hard it would be to implement range analysis and automatic bounds check elimination to the point where we can get good performance in the majority of the cases where it matters, and sidestep this whole issue. |
On Wed, Apr 8, 2015 at 6:00 PM, Simon Kornblith [email protected]
|
|
I would expect I have trouble seeing when you would want to override |
We seriously need to make Traits part of the language (#5). They are starting to appear everywhere on base, and this would make them much easier to work with. |
@timholy I'd say such objects doesn't follow (what I expect to be) the When I apply |
I don't understand your concern; with this proposal, you can have your cake and eat it too. The point is that users who want to do fancy things in their own code trees can add extra safety checks to |
Exactly, the whole point behind this idea is that you almost always want to check bounds before doing indexing. And checking bounds is almost always asserting that each The bonuses to this proposal are that it breaks these things down into orthogonal components:
As I was thinking about this last night, I realized that we'll have to make this scheme support Cartesian indices, which may be tough to do without duplicating functionality (and work). Edit: actually, it's not really any worse than the status quo, I think — it just requires a little extra indirection. Mixed cartesian/integer indexing breaks the assumption that each index corresponds to exactly one dimension… which means that the |
The trouble is that if you have an array type that break the Can you give an example on a correct piece of generic code that uses inbounds and works on both Julia (1 based) and C (0 based) arrays (without resorting to |
Right now it would cause segfaults. With the proposed scheme, it would only cause a segfault if The easiest solution is to say that an array with 0-based indexing should not subtype AbstractArray. This seems pretty reasonable to me, since I suspect there's not much that accepts AbstractArrays but not ordinary iterators that will actually work with 0-based indexing. |
Ok, but this seems like a discussion for another day. We certainly don't need to document the fact that |
Ah, right, and I totally forgot - we do need to encourage the overloading of |
I still have some serious doubts about splitting getindex into two functions. It's quite ugly to have to tell people to define Here's a possible alternative. First, we mark code that performs bounds checks with |
+1 that was something like what I was thinking of. What's a little weird though is that you seem to need to have machinery to compile two different versions of functions that have |
Yes, please! That was definitely my first choice (#10525 (comment)), but as I said there, "that just punts the complexity up the chain to a system I don't know and only a few could implement." This proposal was my compromise that was implementable by peons. :) |
As a first cut, we might try having I haven't read all of the discussion on this, but is it thought to be important to remove bounds checks even if |
Also, this needn't tax method tables or dispatch. A benefit of leaving this to the compiler is that it can do any dirty trick it wants. We will eventually have some kind of |
The consensus seems to be in strong favor of decoupling |
To be safer, As I said, we could also limit it to 1 level of inlining. That's a bit arbitrary, but seems pretty safe to me. |
Ah, whoops, I missed the "up to 1 level." I like that. I don't think it's all that arbitrary - I think that each indexing level should need to explicitly opt-in to I also like the idea of specifying which array the indexing is inbounds for, but that might be somewhat redundant with the above. I'll have to think through that a bit more. |
I don't like the idea of specifying the array : if the array gets stored into temporaries or something then it becomes harder, and if you already went to the trouble of adding |
I've thought about this solution before. I don't think it would matter for performance if you're not able to eliminate bounds checks from functions that aren't inlined, but here is the worst case scenario: function getindex(x, i)
@checkbounds begin
...
i += 1 # oops, meant to put this outside the @checkbounds block
end
@inbounds x.x[i]
end Now your Travis build with |
Jeff, is the idea that you would generate both the getindex and unsafe_getindex methods from the single definition that contains |
This issue has been quiet for 4.5 months... what's necessary to actually make progress on @JeffBezanson's proposal? Are the required changes buried within codegen? |
Closed by #14474. 🍰 |
For user written short functions that have a huge overhead from bounds checking, it would be nice if it was possible to hook into the
boundscheck
system with@inbounds
in order to let the user be able to disable manual bounds checking inside the function.This might be beneficial for
SubString
,SubArray
, and many wrapping types that have to check bounds before forwarding to the internal storage.One suggestion is to have a
@bounds
macro that you can wrap the optional checking code in, but that seems somewhat brittle.The text was updated successfully, but these errors were encountered: