|
4 | 4 | [](https://putianyi889.github.io/EltypeExtensions.jl/stable)
|
5 | 5 | [](https://putianyi889.github.io/EltypeExtensions.jl/dev)
|
6 | 6 | [](https://github.com/JuliaTesting/Aqua.jl)
|
7 |
| -[](https://codecov.io/gh/putianyi889/EltypeExtensions.jl) |
| 7 | +[](https://codecov.io/gh/putianyi889/EltypeExtensions.jl) |
| 8 | + |
| 9 | +EltypeExtensions.jl is a mini toolbox for eltype-related conversions. The motivation of this package comes from manipulating (nested) arrays with different eltypes. However if you have any reasonable idea that works on other instances, feel free to write an issue/pull request. |
| 10 | + |
| 11 | +We note that this package has some overlap with [TypeUtils.jl](https://github.com/emmt/TypeUtils.jl) and [Unitless.jl](https://github.com/emmt/Unitless.jl). |
| 12 | + |
| 13 | +## Introduction |
| 14 | + |
| 15 | +### `elconvert` and `_to_eltype` |
| 16 | +`elconvert(T, x)` works like `convert(T, x)`, except that `T` refers to the eltype of the result. This can be useful for generic codes. |
| 17 | + |
| 18 | +It should be always true that `elconvert(T, x) isa _to_eltype(T, typeof(x))`. However, since `elconvert` and `_to_eltype` use different routines, it's possible that the equality doesn't hold for some types. Please submit an issue or PR if that happens. |
| 19 | + |
| 20 | +If `typeof(x)` is not in Base or stdlib, the package who owns the type should implement corresponding `_to_eltype` or `elconvert`. `elconvert` has fallbacks, in which case it could be unnecessary: |
| 21 | +- For a subtype of `AbstractArray`, `elconvert` calls the constructor `AbstractArray{T}` and `_to_eltype` returns `Array`. |
| 22 | +- For a subtype of `AbstractUnitRange`, `elconvert` calls the constructor `AbstractUnitRange{T}`. |
| 23 | +- For a subtype of `AbstractRange`, `elconvert` uses broadcast through `map`. |
| 24 | +- For a `Tuple`, `elconvert` uses dot broadcast. |
| 25 | +- For other types, `elconvert` calls `convert` and `_to_eltype`. |
| 26 | + |
| 27 | +However, `_to_eltype` must be implemented for each type to support `baseconvert` and `precisionconvert`. The following types from Base and stdlib are explicitly supported by `_to_eltype`: |
| 28 | +``` |
| 29 | +AbstractArray, AbstractDict, AbstractSet, Adjoint, Bidiagonal, BitArray, CartesianIndices, Diagonal, Dict, Hermitian, Set, StepRangeLen, Symmetric, SymTridiagonal, Transpose, TwicePrecision, UnitRange |
| 30 | +``` |
| 31 | + |
| 32 | +### `basetype` and `precisiontype` |
| 33 | +The `basetype` is used for nested collections, where `eltype` is repeatedly applied until the bottom. `precisiontype` has a similar idea, but goes deeper when possible. `precisiontype` is used to manipulate the accuracy of (nested) collections. |
| 34 | + |
| 35 | +### Method naming convention |
| 36 | +- `sometype(T)` gets the `sometype` of type `T`. |
| 37 | +- `sometype(x) = sometype(typeof(x))` is also provided for convenience. |
| 38 | +- `_to_sometype(T,S)` converts the type `S` to have the `sometype` of `T`. |
| 39 | +- `someconvert(T,A)` converts `A` to have the `sometype` of `T`. |
| 40 | + |
| 41 | +where `some` can be `el`, `base` and `precision`. |
| 42 | + |
| 43 | +### On `precisionconvert` |
| 44 | +`precisionconvert` accepts an optional third argument `prec`. |
| 45 | +- When `T` has static precision, `prec` has no effect. |
| 46 | +- When `T` has dynamic precision, `prec` specifies the precision of conversion. When `prec` is not provided, the precision is decided by the external setup from `T`. The difference is significant when `precisionconvert` is called by another function: |
| 47 | +- When `T` is an integer, the conversion will dig into `Rational` as well. In contrast, since `Rational` as a whole is more "precise" than an integer, `precisiontype` doesn't unwrap `Rational`. |
0 commit comments