Skip to content

Latest commit

 

History

History
161 lines (130 loc) · 5.12 KB

README.md

File metadata and controls

161 lines (130 loc) · 5.12 KB

Derive.jl

Stable Dev Build Status Coverage Code Style: Blue Aqua

About

This is a package for defining and deriving functionality for objects based around interfaces and traits, outside of the Julia type hierarchy. It is heavily inspired by Moshi.@derive, which itself is inspired by Rust's derive functionality, and the design of ArrayLayouts.jl.

The basic idea is to define implementations of a set of functions for a given interface, and types can overload, or derive, those implementations by specifying the desired interface. This provides a systematic way to define implementations of functions for objects that act in a certain way but may not share convenient abstact supertypes, such as a sparse array object and wrappers around that sparse array. Like in Moshi.jl and Rust's derive functionality, traits are simply sets of functions that can be derived for a certain type.

Installation instructions

This package resides in the ITensor/ITensorRegistry local registry. In order to install, simply add that registry through your package manager. This step is only required once.

julia> using Pkg: Pkg

julia> Pkg.Registry.add(url="https://github.com/ITensor/ITensorRegistry")

or:

julia> Pkg.Registry.add(url="[email protected]:ITensor/ITensorRegistry.git")

if you want to use SSH credentials, which can make it so you don't have to enter your Github ursername and password when registering packages.

Then, the package can be added as usual through the package manager:

julia> Pkg.add("Derive")

Examples

using Derive: Derive, @array_aliases, @derive, @interface, interface
using Test: @test

Define an interface.

struct SparseArrayInterface end

Define interface functions.

@interface ::SparseArrayInterface function Base.getindex(a, I::Int...)
  checkbounds(a, I...)
  !isstored(a, I...) && return getunstoredindex(a, I...)
  return getstoredindex(a, I...)
end
@interface ::SparseArrayInterface function Base.setindex!(a, value, I::Int...)
  checkbounds(a, I...)
  iszero(value) && return a
  if !isstored(a, I...)
    setunstoredindex!(a, value, I...)
    return a
  end
  setstoredindex!(a, value, I...)
  return a
end

Define a type that will derive the interface.

struct SparseArrayDOK{T,N} <: AbstractArray{T,N}
  storage::Dict{CartesianIndex{N},T}
  size::NTuple{N,Int}
end
storage(a::SparseArrayDOK) = a.storage
Base.size(a::SparseArrayDOK) = a.size
function SparseArrayDOK{T}(size::Int...) where {T}
  N = length(size)
  return SparseArrayDOK{T,N}(Dict{CartesianIndex{N},T}(), size)
end
function isstored(a::SparseArrayDOK, I::Int...)
  return CartesianIndex(I) in keys(storage(a))
end
function getstoredindex(a::SparseArrayDOK, I::Int...)
  return storage(a)[CartesianIndex(I)]
end
function getunstoredindex(a::SparseArrayDOK, I::Int...)
  return zero(eltype(a))
end
function setstoredindex!(a::SparseArrayDOK, value, I::Int...)
  storage(a)[CartesianIndex(I)] = value
  return a
end
function setunstoredindex!(a::SparseArrayDOK, value, I::Int...)
  storage(a)[CartesianIndex(I)] = value
  return a
end

Specify the interface the type adheres to.

Derive.interface(::Type{<:SparseArrayDOK}) = SparseArrayInterface()

Define aliases like SparseMatrixDOK, AnySparseArrayDOK, etc.

@array_aliases SparseArrayDOK

Derive the interface for the type.

@derive (T=SparseArrayDOK,) begin
  Base.getindex(::T, ::Int...)
  Base.setindex!(::T, ::Any, ::Int...)
end

a = SparseArrayDOK{Float64}(2, 2)
a[1, 1] = 2
@test a[1, 1] == 2
@test a[2, 1] == 0
@test a[1, 2] == 0
@test a[2, 2] == 0

@test a isa SparseMatrixDOK
@test a' isa AnySparseMatrixDOK

Call the sparse array interface on a dense array.

isstored(a::AbstractArray, I::Int...) = true
getstoredindex(a::AbstractArray, I::Int...) = getindex(a, I...)
setstoredindex!(a::AbstractArray, value, I::Int...) = setindex!(a, value, I...)

a = zeros(2, 2)
@interface SparseArrayInterface() a[1, 1] = 2
@test @interface(SparseArrayInterface(), a[1, 1]) == 2
@test @interface(SparseArrayInterface(), a[2, 1]) == 0
@test @interface(SparseArrayInterface(), a[1, 2]) == 0
@test @interface(SparseArrayInterface(), a[2, 2]) == 0

This page was generated using Literate.jl.