soma.cell

E0026: foreign_slot

E0026 foreign_slot — a handler touches a memory slot of another cell.

A compile-time error of soma check, the checker of the Soma programming language (soma explain E0026).

The rule

A cell's memory slots are private to it: Inventory.stock read from another cell is refused, and the message says it would raise "undefined variable: Inventory" at run time. This keeps every read and write of a slot inside the cell that owns its invariants. Add a handler to the owning cell that returns what you need, and call that handler (Inventory.level(sku)).

A program that triggers it

wrong.cell

cell Inventory {
    memory {
        stock: Map<String, Int> [persistent]
    }
    on restock(sku: String, qty: Int) {
        stock.set(sku, (stock.get(sku) ?? 0) + qty)
    }
}

cell Storefront {
    on available(sku: String) {
        return (Inventory.stock.get(sku) ?? 0) > 0
    }
}

What soma check prints:

$ soma check wrong.cell
error: `Inventory.stock` reads the memory of another cell — a cell's slots are private to it (this raises "undefined variable: Inventory" at run time); add a handler to Inventory that returns what you need (`on get_stock(k: String) { return stock.get(k) }`) and call `Inventory.get_stock(k)`
  --> wrong.cell:12:9
   |
12 |         return (Inventory.stock.get(sku) ?? 0) > 0
   |         ^
  = code: E0026
✗ 1 error(s), 0 warning(s).

The fix field of soma check --json: a cell's slots are private to it (this raises "undefined variable: Inventory" at run time); add a handler to Inventory that returns what you need (`on get_stock(k: String) { return stock.get(k) }`) and call `Inventory.get_stock(k)`

3 lines are added after line 7; on line 12, return (Inventory.stock.get(sku) ?? 0) > 0 becomes return Inventory.level(sku) > 0.

wrong.cell → right.cell

--- wrong.cell
+++ right.cell
@@ -6,9 +6,12 @@
         stock.set(sku, (stock.get(sku) ?? 0) + qty)
     }
+    on level(sku: String) {
+        return stock.get(sku) ?? 0
+    }
 }
 
 cell Storefront {
     on available(sku: String) {
-        return (Inventory.stock.get(sku) ?? 0) > 0
+        return Inventory.level(sku) > 0
     }
 }

With the fix, soma check accepts the program:

$ soma check right.cell
✓ All checks passed.