Design Review: RegisterCore.jl
Date: 2026-04-28
Overview
RegisterCore provides NumDenom{T} — a packed (num, denom) pair that
behaves as a 2-vector under interpolation arithmetic without forming
the ratio prematurely — and MismatchArray, a type alias for
CenterIndexedArray{NumDenom}. The package also contains a shot-noise
image preprocessor (PreprocessSNF) and bandpass utilities.
Likely Design Issues
-
ColonFun is exported but is purely internal.
A zero-field singleton used inside paddedview/trimmedview for
type-stable colon generation. No docstring, no external use case,
name is not meaningful to a user. Looks like an accidental export.
Fix: remove from the export list.
-
PreprocessSNF is mutable struct but has no mutation API.
Fields: bias::Float32, sigmalp::Vector{Float32}, sigmahp::Vector{Float32}.
No mutation pattern is documented or used. The vector fields are
already mutable via their elements regardless of struct mutability.
The mutable keyword appears to be an oversight; struct would be correct.
-
copyto! and paddedview use error(...) rather than typed exceptions.
Every other size-mismatch guard in the package throws DimensionMismatch.
These two use the untyped error(...), preventing callers from catching
specific error types. Inconsistent with the package's own conventions.
-
mismatcharrays is exported despite the comment "mostly used just for testing."
Exporting a testing helper adds permanent API surface. Should be removed
from export (callers can use RegisterCore.mismatcharrays if needed).
Design Questions
-
Does the image-preprocessing subsystem belong in RegisterCore?
highpass, PreprocessSNF, paddedview, trimmedview, preprocess, and
sqrt_subtract_bias implement shot-noise standardization and bandpass
filtering — transforming images before mismatch is computed. The rest
of the package is about the algebraic structure of mismatch data.
Was the preprocessing added here because no better home existed, or is
it intentionally colocated with the mismatch types?
-
Is MismatchArray as a type alias the intended permanent design?
const MismatchArray{ND,N,A} = CenterIndexedArray{ND,N,A} is transparent
to the type system — not a distinct type for dispatch. Methods annotated
::MismatchArray also match any CenterIndexedArray{NumDenom,...} created
by other means. Was this chosen to keep coupling to CenterIndexedArrays
explicit, or would a distinct type be preferable for domain clarity?
-
Is the second method of indmin_mismatch still needed?
indmin_mismatch(r::CenterIndexedArray{T<:Number,N}) finds the interior
argmin of a pre-divided numeric array — essentially argmin restricted to
interior elements. Was this added for a specific calling convention that
has since been superseded?
-
Should separate(::AbstractArray{<:MismatchArray}) be exported?
The caller could write map(separate, mma) with nearly identical result.
Was this exported for performance or just for convenience?
-
Why does Base.round take the form round(::Type{NumDenom{T}}, p)?
The public Julia signature for rounding is round(x::NumDenom, r::RoundingMode=...).
The round(::Type{T}, x) form is an internal convention used by some
interpolation backends. Was this defined to satisfy a specific
Interpolations.jl or ImageFiltering.jl internal requirement?
Observations
-
NumDenom.show produces valid Julia constructor syntax (NumDenom(1.0,2.0)),
so copy-paste reconstruction from the REPL works.
-
Unary negation (-nd) for NumDenom is not defined — only binary (-).
A user writing (-nd) would get a MethodError, which is mildly surprising
given that +, -, *, / are all present.
-
preprocess(pp, A) appears to be effectively public (called by the functor,
referenced in the PreprocessSNF docstring). Should be annotated public.
-
The @require ImageMetadata extension in init predates Julia 1.9's
package extension system (ext/). Routine maintenance candidate.
-
ratio(r::Real, thresh, fillval=NaN) = r is a well-considered composability
convenience enabling uniform broadcasting over mixed arrays.
Overall
RegisterCore has a clear and principled algebraic core: NumDenom encodes
the discipline of not forming the mismatch ratio prematurely, enforced
consistently. The main structural tension is scope — a type-algebra library
bundled with a signal-processing preprocessor only loosely related at the
type level. The two highest-leverage changes would be: (1) remove ColonFun
from exports (clear accidental leak) and (2) decide whether PreprocessSNF/
highpass/paddedview/trimmedview belong here or in a sibling RegisterPreprocess
package, since that boundary question shapes several other findings.
Design Review: RegisterCore.jl
Date: 2026-04-28
Overview
RegisterCore provides NumDenom{T} — a packed (num, denom) pair that
behaves as a 2-vector under interpolation arithmetic without forming
the ratio prematurely — and MismatchArray, a type alias for
CenterIndexedArray{NumDenom}. The package also contains a shot-noise
image preprocessor (PreprocessSNF) and bandpass utilities.
Likely Design Issues
ColonFun is exported but is purely internal.
A zero-field singleton used inside paddedview/trimmedview for
type-stable colon generation. No docstring, no external use case,
name is not meaningful to a user. Looks like an accidental export.
Fix: remove from the export list.
PreprocessSNF is
mutable structbut has no mutation API.Fields: bias::Float32, sigmalp::Vector{Float32}, sigmahp::Vector{Float32}.
No mutation pattern is documented or used. The vector fields are
already mutable via their elements regardless of struct mutability.
The
mutablekeyword appears to be an oversight;structwould be correct.copyto! and paddedview use error(...) rather than typed exceptions.
Every other size-mismatch guard in the package throws DimensionMismatch.
These two use the untyped error(...), preventing callers from catching
specific error types. Inconsistent with the package's own conventions.
mismatcharrays is exported despite the comment "mostly used just for testing."
Exporting a testing helper adds permanent API surface. Should be removed
from export (callers can use RegisterCore.mismatcharrays if needed).
Design Questions
Does the image-preprocessing subsystem belong in RegisterCore?
highpass, PreprocessSNF, paddedview, trimmedview, preprocess, and
sqrt_subtract_bias implement shot-noise standardization and bandpass
filtering — transforming images before mismatch is computed. The rest
of the package is about the algebraic structure of mismatch data.
Was the preprocessing added here because no better home existed, or is
it intentionally colocated with the mismatch types?
Is MismatchArray as a type alias the intended permanent design?
const MismatchArray{ND,N,A} = CenterIndexedArray{ND,N,A}is transparentto the type system — not a distinct type for dispatch. Methods annotated
::MismatchArrayalso match any CenterIndexedArray{NumDenom,...} createdby other means. Was this chosen to keep coupling to CenterIndexedArrays
explicit, or would a distinct type be preferable for domain clarity?
Is the second method of indmin_mismatch still needed?
indmin_mismatch(r::CenterIndexedArray{T<:Number,N})finds the interiorargmin of a pre-divided numeric array — essentially
argminrestricted tointerior elements. Was this added for a specific calling convention that
has since been superseded?
Should separate(::AbstractArray{<:MismatchArray}) be exported?
The caller could write
map(separate, mma)with nearly identical result.Was this exported for performance or just for convenience?
Why does Base.round take the form round(::Type{NumDenom{T}}, p)?
The public Julia signature for rounding is round(x::NumDenom, r::RoundingMode=...).
The
round(::Type{T}, x)form is an internal convention used by someinterpolation backends. Was this defined to satisfy a specific
Interpolations.jl or ImageFiltering.jl internal requirement?
Observations
NumDenom.show produces valid Julia constructor syntax (NumDenom(1.0,2.0)),
so copy-paste reconstruction from the REPL works.
Unary negation (-nd) for NumDenom is not defined — only binary (-).
A user writing (-nd) would get a MethodError, which is mildly surprising
given that +, -, *, / are all present.
preprocess(pp, A) appears to be effectively public (called by the functor,
referenced in the PreprocessSNF docstring). Should be annotated
public.The @require ImageMetadata extension in init predates Julia 1.9's
package extension system (ext/). Routine maintenance candidate.
ratio(r::Real, thresh, fillval=NaN) = r is a well-considered composability
convenience enabling uniform broadcasting over mixed arrays.
Overall
RegisterCore has a clear and principled algebraic core: NumDenom encodes
the discipline of not forming the mismatch ratio prematurely, enforced
consistently. The main structural tension is scope — a type-algebra library
bundled with a signal-processing preprocessor only loosely related at the
type level. The two highest-leverage changes would be: (1) remove ColonFun
from exports (clear accidental leak) and (2) decide whether PreprocessSNF/
highpass/paddedview/trimmedview belong here or in a sibling RegisterPreprocess
package, since that boundary question shapes several other findings.