Commonizing code between `Fixed` and `Normed`
kimikage opened this issue · comments
Fixed
and Normed
have evolved independently. Therefore, some functions are specialized even though they do not need specialization.
cf. ee5bd54...kimikage:commonize PR #151
I'm going to refactor the codes by taking the following 3 steps.
- Commonize the existing implementation code
- Add the functions which are implemented only in either (e.g. rounding functions for
Fixed
) - Commonize the test codes
Although "test-first" is a good practice, the step 3. requires major renovations. Please give me your advice if you have any ideas.
It might be a good idea to add the step.
- Update comments and Add docstrings
For example, "32-bit fixed point" is a holdover from the Fixed32
age.
FixedPointNumbers.jl/src/fixed.jl
Lines 1 to 2 in 8d17739
If we modify the comments, I think it is better to write them in the docstring style, e.g:
"""
FixedPoint{T <: Integer, f} <: Real
Supertype of the two fixed-point number types: `Fixed{T, f}` and `Normed{T, f}`.
The parameter `T` is the underlying machine representation and `f` is the number of fraction bits.
"""
abstract type FixedPoint{T <: Integer, f} <: Real end
The problem is that I am not good at English.
Edit:
Also, what about setting coding guidlines for the static parameters (parametric methods)?
I am concerned that I will unnecessarily be blamed by renaming all parameters at once (even though Github provides a good UI for "diff"). So, I think it is better to rename them at every opportunity rather than at once.
There are two type of inconsistency: the naming and the specialization level. The following is my draft.
Naming
F
,F[0-9]
X
,X[0-9]
- for
<: FixedPoint
,<: Fixed
,<: Normed
- for
F
,F[0-9]
- for
<: Fixed
- for
N
,N[0-9]
- for
<: Normed
- for
f
,f[0-9]
- for the number of fractional bits
T
,T[0-9]
- for the rawtype
Integer
- for the rawtype
T[a-z]+
- for general purpose, e.g.:
Ti <: Integer
Tf <: AbstractFloat
Tw <: widen(T)
- for general purpose, e.g.:
Specialization level
- Don't use unnecessary static parameters
- especially when the method is not worth inlining, e.g.:
- using
IO
- might
throw
an exception
- using
- exceptions:
- the rawtype
T
with the nbitsfracf
- when using two or more
typeof
-like methods - needs for solving ambiguity
- the rawtype
- especially when the method is not worth inlining, e.g.:
Steps 1 and 2 are almost complete. Step 0 (the coding guidelines) is partially unfinished. Step 3 has not been started yet. I will keep this issue open until we have a concrete work plan.
I thought the test code was difficult to commonize. However, as I'll add tests for arithmetic operations, I am not very satisfied with the current test code.
A practical problem is the long testing times. It's not fatal at the moment, but it should be an obstacle to supporting signed Normed
in the future.
We spend the most part of the testing time compiling. Therefore, except the reduction of memory allocation, optimization techniques for "run-time" speed has almost no effect. So it's important to reduce the number of test cases, or target types.
Currently, 128-bit/64-bit types are tested, even though they are rarely used in practice. I believe that the reduction of the target type can be abstracted. For example, the following API can be considered:
julia> target(Normed, (:i8, :i16), :light)
(N7f1, N1f7, N0f8, N15f1, N9f7, N8f8, N7f9, N6f10, N5f11, N1f15, N0f16)
We can use include
to do things like mix-in, but the unit of common reusable test sets are per file. That is incompatible with ”partially" commonizable test sets. @includetests
of TestSetExtensions.jl also have the same problem.
I devised (ugly) small macros like this:
https://github.com/kimikage/CommonTests.jl
The pair of macros @common
and @runcommon
use the names of the test sets to map the caller to the callee. However, I think there is a more elegant way.
The support for checked basic four operations is almost complete. Now that I know that those 100% tests are common to Fixed
and Normed
, I would like to commonize their codes. However, I'm not going to introduce any tricky macros, but simply write functions.