Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 23, 2025

Overview

This PR modifies binary expression evaluation to return the left operand instead of boolean values, as specified in issue #695 and confirmed by @sebastienros to be part of the Liquid standard.

Implementation Approach

Following @sebastienros's guidance, created a custom BinaryExpressionFluidValue class that intelligently adapts its behavior based on context:

  • Returns the comparison result when ToBooleanValue() is called (for use in conditionals like {% if %})
  • Returns the left operand when WriteToAsync() is called (for output rendering in {{ }})
  • Returns "true"/"false" string when ToStringValue() is called (for filters and assignments)

This elegant proxy pattern ensures correct behavior across all usage contexts without breaking existing functionality.

Changes

Modified all comparison and logical binary expressions to return BinaryExpressionFluidValue:

  • Comparison operators: ==, !=, <>, >, >=, <, <=
  • Logical operators: and, or
  • String operators: contains, startswith, endswith

New file added: Fluid/Values/BinaryExpressionFluidValue.cs

Before/After Behavior

✅ Output Statements (Primary Requirement)

{{ 2 == 3 }}
  • Before: false
  • After: 2
{{ 2 == 3 | plus: 10 | minus: 3 }}
  • Before: 7 (false + 10 - 3 = 0 + 10 - 3)
  • After: 9 (2 + 10 - 3) ✅
{{ 5 == 5 }}
  • Before: true
  • After: 5

✅ Conditional Statements (Preserved)

{% if 2 == 3 %}true{% else %}false{% endif %}
  • Before: false
  • After: false ✅ (comparison result used for boolean evaluation)
{% if 5 == 5 %}true{% else %}false{% endif %}
  • Before: true
  • After: true

✅ Assignments with Filters

{% assign x = false or data | append: 'o' %}{{ x }}
  • Before: falseo
  • After: falseo ✅ (ToStringValue returns boolean string for filter chains)

Testing

Test Results: All 1221 tests passing ✅

  • Added comprehensive test coverage for binary expressions returning left operand in output statements
  • Added tests validating correct behavior with filter chains
  • Updated 1 existing test (ModelShouldNotImpactBlank) to align with new behavior
  • Verified conditional logic remains intact and functional
  • No security vulnerabilities detected (CodeQL scan clean)

The implementation successfully balances the new Liquid standard requirement with backward compatibility for conditional statements and existing functionality.

Fixes #695

Original prompt

This section details on the original issue you should resolve

<issue_title>Binary expressions should return the left operand</issue_title>
<issue_description>Expectations:

  • {{ 2 == 3 }} returns 2
  • {{ 2 == 3 | plus : 10 | minus : 3 }} returns 9
    </issue_description>

Comments on the Issue (you are @copilot in this section)

@sebastienros > Tho if this is part of the liquid standard that's fine. Just thought I should mention it.

It is part of the liquid standard ;) Was a shock to me too</comment_new>

Fixes #695


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Modified all comparison binary expressions to return the left operand instead of boolean values, as specified in the issue. This aligns with the Liquid standard according to the maintainer.

Changes:
- EqualBinaryExpression, NotEqualBinaryExpression
- GreaterThanBinaryExpression, LowerThanBinaryExpression
- AndBinaryExpression, OrBinaryExpression
- ContainsBinaryExpression, StartsWithBinaryExpression, EndsWithBinaryExpression

Added new tests demonstrating the expected behavior:
- {{ 2 == 3 }} returns "2"
- {{ 2 == 3 | plus : 10 | minus : 3 }} returns "9"

Note: This is a breaking change that causes 130+ existing tests to fail. These tests expect binary expressions to return boolean values for use in conditional statements. Further guidance needed on whether:
1. The existing tests should be updated to match this new behavior
2. There's a misunderstanding of the requirement
3. Binary expressions need different behavior in output vs conditional contexts

Co-authored-by: sebastienros <[email protected]>
Copilot AI changed the title [WIP] Fix binary expressions to return the left operand Implement binary expressions returning left operand per Liquid standard Oct 23, 2025
Copilot AI requested a review from sebastienros October 23, 2025 14:59
@sebastienros
Copy link
Owner

@copilot The BinaryExpression evaluation should return a custom FluidValue implementation's instance (for instance named ProxyFluidValue) that can return true/false when ToBoolean() is invoked with the result of the binary expression, and the left operand (another FluidValue) when rendered. It could have a property for each method of a FluidValue such that we can set what is returned for each method.

Created a custom FluidValue (BinaryExpressionFluidValue) that:
- Returns the comparison result when ToBooleanValue() is called (for conditionals)
- Returns the left operand when rendered via WriteToAsync() (for output)
- Returns boolean string ("true"/"false") in ToStringValue() (for filters/assignments)

This elegant solution ensures:
✅ Output statements like {{ 2 == 3 }} display "2" (left operand)
✅ Filters work correctly: {{ 2 == 3 | plus: 10 }} displays "9"
✅ Conditionals work: {% if 2 == 3 %} evaluates to false
✅ All 1221 tests pass (was 130+ failures before)

Updated test ModelShouldNotImpactBlank to match new behavior where binary expressions output the left operand.

Co-authored-by: sebastienros <[email protected]>
Copy link
Contributor Author

Copilot AI commented Oct 23, 2025

@copilot The BinaryExpression evaluation should return a custom FluidValue implementation's instance (for instance named ProxyFluidValue) that can return true/false when ToBoolean() is inv...

Implemented as suggested. Created BinaryExpressionFluidValue that wraps the left operand and comparison result, returning the boolean for conditionals (via ToBooleanValue()) and the left operand for output rendering (via WriteToAsync()). All 1221 tests now pass. Commit: 680c81e

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.

Binary expressions should return the left operand

2 participants