SizeCheck: Runtime Shape Validation for Size-Annotated Julia Code

This library provides sizecheck, a macro that automatically adds runtime shape checking to Julia functions based on size-annotated variable names.

When writing Julia code, it's common to use naming conventions that indicate tensor shapes, as in this Medium post. For example, if a tensor weights has shape N × K, you might name the variable weights_NK. This macro adds validation checks that tensors match their annotated shapes at runtime.

SizeCheck.@sizecheckMacro

Automatically adds runtime shape checking to Julia functions based on size-annotated variable names. Variables with underscores followed by dimension letters (e.g., x_NK) are validated to ensure consistent shapes.

Dimension annotations can contain:

  • Variable dimensions (uppercase letters): N, K, M - stored in variables of the same name
  • Constant dimensions (single digits): 3, 4, 2 - checked for exact size

The macro automatically adds shape validation for:

  • Function arguments with underscores in their names
  • Variable assignments to names containing underscores, including destructuring assignments

The dimensions are scoped to the function they are defined in. For example, if you define a function foo with a parameter x_NK, the dimension N is only valid within the scope of foo. If you define another function bar with a parameter y_NL, this dimension N can differ from the one in foo, but it is only valid within the scope of bar.

Examples:

@sizecheck function matrix_multiply(a_NK, b_KM)
    result_NM = a_NK * b_KM
    return result_NM, N, K, M  # Dimension variables accessible
end

# This works fine
a_NK = randn(3, 4)  # N=3, K=4
b_KM = randn(4, 5)  # K=4, M=5
result = matrix_multiply(a_NK, b_KM)  # size: (3, 5)

# This raises an error
a_NK = randn(3, 4)
b_KM = randn(5, 6)  # Wrong! K dimensions don't match
result = matrix_multiply(a_NK, b_KM)  # Error!

@sizecheck function with_constants(data_N3, weights_3K)
    # data_N3: first dim variable N, second dim exactly 3
    # weights_3K: first dim exactly 3, second dim variable K
    result_NK = data_N3 * weights_3K
    return result_NK, N, K
end
source