Skip to content

Conversation

@osteele
Copy link
Owner

@osteele osteele commented Nov 12, 2025

Fixes #109

Previously, arithmetic filters (minus, plus, times) always converted operands to float64, causing large integers to be displayed in scientific notation (e.g., 1.743096446e+09).

This change implements type-aware arithmetic that:

  • Preserves integer types when both operands are integers
  • Returns integers for integer operations (matching Ruby Liquid)
  • Returns floats when at least one operand is a float
  • Prevents scientific notation for large integer results

Example:
{{ 1743096453 | minus: 7 }} Before: 1.743096446e+09 After: 1743096446

This aligns the Go implementation with Shopify's Ruby Liquid, where integer arithmetic preserves integer types.

Checklist

  • I have read the contribution guidelines.
  • make test passes.
  • make lint passes.
  • New and changed code is covered by tests.
  • Performance improvements include benchmarks.
  • Changes match the documented (not just the implemented) behavior of Shopify.

…havior

Fixes #109

Previously, arithmetic filters (minus, plus, times) always converted
operands to float64, causing large integers to be displayed in
scientific notation (e.g., 1.743096446e+09).

This change implements type-aware arithmetic that:
- Preserves integer types when both operands are integers
- Returns integers for integer operations (matching Ruby Liquid)
- Returns floats when at least one operand is a float
- Prevents scientific notation for large integer results

Example:
  {{ 1743096453 | minus: 7 }}
  Before: 1.743096446e+09
  After:  1743096446

This aligns the Go implementation with Shopify's Ruby Liquid, where
integer arithmetic preserves integer types.
…cerns

The gosec linter (G115) flagged potential integer overflow when converting
uint and uint64 to int64. To address this, removed these types from
integer arithmetic support, aligning with the divided_by filter pattern.

These types will now fall back to float arithmetic, which is safe and
matches the existing pattern in the codebase.
Improved the integer type handling to properly support uint and uint64:

- Added runtime overflow checks in isIntegerType() to verify uint/uint64
  values fit within int64 range (<=math.MaxInt64)
- Values in range are treated as integers and preserve integer types
- Values out of range gracefully fall back to float arithmetic
- Added nolint directives with justification for gosec G115 warnings

This maintains Shopify Ruby Liquid compatibility (Ruby has no unsigned
types) while safely handling Go's uint/uint64 types that users might
pass as template bindings.

Example behavior:
- uint(1000) | minus: 1 → 999 (integer)
- uint64(MaxInt64) | minus: 1 → 9223372036854775806 (integer)
- uint64(MaxInt64+1) | minus: 1 → 9.223372036854776e+18 (float)

Fixes lint failures while preserving the fix for issue #109.
Added comprehensive test cases to verify that uint and uint64 types
are properly handled in arithmetic operations:

- Tests for uint type with plus, minus, and times operations
- Tests for uint64 type with plus, minus, and times operations
- All tests verify that values within int64 range preserve integer type

This ensures the overflow-safe handling from commit 1e0783c is working
correctly and prevents regressions.
@osteele osteele merged commit 81af0d4 into main Nov 14, 2025
8 checks passed
@osteele osteele deleted the claude/compare-shopify-ruby-behavior-011CUvV6xX127Y87zBAZwrbp branch November 14, 2025 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Simple mathematical operations on INT transforms them in FLOAT

3 participants