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

Adding an example of an array type wrapper without loose of performance. #33420

Closed
wants to merge 5 commits into from
Closed
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions doc/src/manual/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,27 @@ so that the `dims` argument (ordinarily a `Dims` size-tuple) can accept `Abstrac
perhaps range-types `Ind` of your own design. For more information, see
[Arrays with custom indices](@ref man-custom-indices).

Sometimes you need to wrap a standard array into an extra type to be able to dispatch on this type but without
the need of any real changes to the standard array behavior.
The following example introduces such a wrapper type and ensures that the new type will work at the same
speed as a standard array type.
The key point is the `Base.@propagate_inbounds` which allows predefined functions like `sum`
to skip bounds checking as they do for a standard array.

```jldoctest wrapperarray
julia> mutable struct MyArray{T,N} <: AbstractArray{T,N}
a::Array{T,N}
end

julia> Base.size(A::MyArray) = size(A.a)

julia> Base.@propagate_inbounds Base.getindex(A::MyArray, i...) = getindex(A.a, i...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should encourage the passing on of keywords, for named A[i=3] type indexing?

Suggested change
julia> Base.@propagate_inbounds Base.getindex(A::MyArray, i...) = getindex(A.a, i...)
julia> Base.@propagate_inbounds Base.getindex(A::MyArray, i...; kw...) = getindex(A.a, i...; kw...)

Link: JuliaCollections/AxisArraysFuture#1 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keyword arguments often cause various performance problems. Just look at this for example: JuliaArrays/StaticArrays.jl#540 . I don't this it should be encouraged in a section dedicated to fast wrappers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. But is this a concern with unused kw... being passed along, or only when they are actually used? I can’t detect any effect on things I tried.

(And, is there a good explanation of this issue somewhere?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem occurs when you call a function with keyword arguments. It's OK to have default keyword arguments though but even passing these default kwargs slows things down. That's why in some places keyword arguments are forwarded as normal arguments (as named tuples). There might be some exceptions that can be optimized by the compiler but from my experience it's a good rule of thumb.

(And, is there a good explanation of this issue somewhere?)

I don't know, it seems to generally be hard to find good explanations of such compiler details.


julia> Base.@propagate_inbounds Base.setindex!(A::MyArray, v, i...) = setindex!(A.a, v, i...)

julia> Base.IndexStyle(::Type{<:MyArray}) = IndexLinear()
```

## [Strided Arrays](@id man-interface-strided-arrays)

| Methods to implement |   | Brief description |
Expand Down