Handling Missing Values

Karl Falconer ·

In the real world, fields don’t always have a value. A customer order might come in without a shipping notes field, or an apartment number, or a custom tag. BGL has a small but specific set of tools for working with these missing values — the keyword blank, the optional-chaining ? suffix, and a few patterns that come up often.

What “missing” looks like

A missing value is blank. It’s BGL’s way of saying no value, similar to null in other languages. You can:

  • Set a field to blank to clear it: set order.notes to blank
  • Compare to blank: when order.notes is blank then ... end

Comparing a string field to "" is not the same as comparing to blank. Empty string is a value (the zero-character string); blank means there’s no value at all.

Setting a field to blank

set order.discount_amount to blank
set order.custom.special_instructions to blank

Use this when you want to clear a value rather than overwrite it with something else.

Detecting a blank field

when order.custom.shipping_notes is blank then
  set order.custom.shipping_notes to "(no special instructions)"
end

when order.subtotal is_not blank and order.subtotal > 100.0 then
  ...
end

The second example shows a defensive pattern — check the field exists before doing math on it. (Doing math on blank is generally fine but produces a blank result; a comparison against blank evaluates as you’d expect false.)

Optional chaining with ?

For a few fields, BGL exposes a question-mark form that returns true/false based on whether the field is set:

order.is_shipping_address_apartment?

Use this in a condition to check whether the field has a value, without needing to compare it explicitly.

when order.custom.shipping_notes? then
  set order.custom.priority to "review"
end

The ? form isn’t available on every field — it’s a per-attribute affordance and most useful for boolean-ish fields where “is it set?” is a meaningful question.

Common defensive patterns

Default-then-override:

set order.custom.tier to "standard"

when order.subtotal > 500.0 then
  set order.custom.tier to "premium"
end

Setting a default first means the field always has a value, regardless of whether the override matches.

Null-safe arithmetic:

when
  order.discount_amount is_not blank
  and order.discount_amount > 0
then
  set order.custom.had_discount to true
end

Null-safe string concatenation:

set $part to "(none)"

when order.notes is_not blank then
  set $part to order.notes
end

set order.custom.combined_note to "Notes: " & $part

If you concatenate blank with &, the result is also blank — which can quietly produce a blank field downstream. The pattern above avoids that.

What BGL doesn’t have

BGL is intentionally minimal here. There’s no:

  • Null-coalescing operator (?? in some languages). The default-then-override pattern is the workaround.
  • Optional chaining for arbitrary nested access. You can’t write order.shipping_address?.country? to safely walk a chain that might be missing. If you have a chain of fields that might not all exist, use a sequence of is_not blank checks before reading them.
  • null as a separate concept from blank. There’s just blank.

If your rule keeps running into “the field isn’t there” issues and the workarounds are getting complex, consider whether the source integration could be configured to always include the field — sometimes the cleanest fix is upstream of the rule.

Example: a complete defensive rule

rule "Tag orders with notes"
  when
    order.notes is_not blank
    and order.notes contains "fragile"
  then
    set order.custom.tag to "fragile"
  end
end

The is_not blank check guards the contains, so you don’t ask “does blank contain ‘fragile’?” — which would just return false but obscures intent. Being explicit about the missing case makes the rule easier to read and audit.

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.