From iris-dev
Worked fix examples for 6 common ObjectScript LLM mistakes: Return vs Quit in loops, HTML escaping order, SQL date filters, list operations, postfix conditions. Uses Bug Pattern → Root Cause → Fix structure.
How this skill is triggered — by the user, by Claude, or both
Slash command
/iris-dev:objectscript-fewshot-fixesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**HOW TO USE THESE**: Before generating any fix, first identify which pattern matches
HOW TO USE THESE: Before generating any fix, first identify which pattern matches the bug, state the root cause explicitly, THEN generate the fix. Research shows this "identify-then-fix" order reduces errors by ~15%.
BUGGY CODE:
ClassMethod IsNameUnique(name As %String, existingNames As %ListOfDataTypes) As %Boolean
{
For i=1:1:existingNames.Count() {
If (existingNames.GetAt(i) = name) {
Quit 1
}
}
Quit 0
}
BUG PATTERN: Quit value inside a For loop exits the loop, not the method.
ROOT CAUSE: After Quit 1, execution continues AFTER the loop — the method returns
the value of Quit 0 at the bottom, or empty string if Quit had a value (IRIS-specific).
The return values are also logically swapped (found = not unique = should return 0).
FIXED CODE:
ClassMethod IsNameUnique(name As %String, existingNames As %ListOfDataTypes) As %Boolean
{
For i=1:1:existingNames.Count() {
If (existingNames.GetAt(i) = name) {
Return 0
}
}
Return 1
}
KEY RULE: Return value always exits the method. Quit value inside a loop only exits the loop.
BUGGY CODE:
ClassMethod DisplayMessage(message As %String) As %String
{
Set safe = $REPLACE(message, "<", "<")
Set safe = $REPLACE(safe, ">", ">")
Set safe = $REPLACE(safe, "&", "&")
Return "<div>" _ safe _ "</div>"
}
BUG PATTERN: Wrong escaping order causes double-encoding.
ROOT CAUSE: Escaping < first produces <. Then escaping & turns < into
&lt; — the ampersand in the entity gets escaped again.
FIXED CODE:
ClassMethod DisplayMessage(message As %String) As %String
{
Set safe = $REPLACE(message, "&", "&")
Set safe = $REPLACE(safe, "<", "<")
Set safe = $REPLACE(safe, ">", ">")
Return "<div>" _ safe _ "</div>"
}
KEY RULE: Always escape & FIRST, then <, then >.
BUGGY CODE:
ClassMethod SearchItems(category As %String) As %ListOfDataTypes
{
Set results = ##class(%ListOfDataTypes).%New()
Set stmt = ##class(%SQL.Statement).%New()
Set sc = stmt.%Prepare("SELECT Name FROM Catalog.Item WHERE Category = ?")
Set rs = stmt.%Execute(category)
While rs.%Next() { Do results.Insert(rs.%Get("Name")) }
Return results
}
BUG PATTERN: Query missing filter to exclude expired records.
ROOT CAUSE: No ActiveUntil date check — returns both active and expired items.
ActiveUntil = "" (NULL) means never expires; ActiveUntil < today means expired.
FIXED CODE:
ClassMethod SearchItems(category As %String) As %ListOfDataTypes
{
Set results = ##class(%ListOfDataTypes).%New()
Set stmt = ##class(%SQL.Statement).%New()
Set sc = stmt.%Prepare("SELECT Name FROM Catalog.Item WHERE Category = ? AND (ActiveUntil IS NULL OR ActiveUntil >= ?)")
Set rs = stmt.%Execute(category, +$HOROLOG)
While rs.%Next() { Do results.Insert(rs.%Get("Name")) }
Return results
}
KEY RULE: +$HOROLOG = today as integer. Pattern: AND (field IS NULL OR field >= ?).
BUGGY CODE:
ClassMethod ProcessItems(items As %ListOfDataTypes) As %Integer
{
For i=1:1:items.Count() {
If (items.GetAt(i) [ "DELETE") { Do items.RemoveAt(i) }
}
Return items.Count()
}
BUG PATTERN: Removing items during forward iteration causes index skipping.
ROOT CAUSE: After RemoveAt(2), the old item 3 becomes item 2 — but i advances to 3,
skipping the newly-shifted item.
FIXED CODE:
ClassMethod ProcessItems(items As %ListOfDataTypes) As %Integer
{
For i=items.Count():-1:1 {
If (items.GetAt(i) [ "DELETE") { Do items.RemoveAt(i) }
}
Return items.Count()
}
KEY RULE: Iterate backwards (Count():-1:1) when removing items in-place.
BUGGY CODE:
ClassMethod GetPatientAge(id As %String) As %Integer
{
Set patient = ##class(Patient).%OpenId(id)
Set birthYear = $PIECE(patient.DOB, "-", 1)
Return +$EXTRACT($ZDATE($HOROLOG, 3), 1, 4) - birthYear
}
BUG PATTERN: No null check after %OpenId — crashes when record not found.
ROOT CAUSE: %OpenId returns "" when ID doesn't exist. Accessing .DOB on ""
causes <INVALID OREF> runtime error.
FIXED CODE:
ClassMethod GetPatientAge(id As %String) As %Integer
{
Set patient = ##class(Patient).%OpenId(id)
If '$IsObject(patient) { Return -1 }
Set birthYear = $PIECE(patient.DOB, "-", 1)
Return +$EXTRACT($ZDATE($HOROLOG, 3), 1, 4) - birthYear
}
KEY RULE: Always If '$IsObject(obj) { Return <default> } immediately after %OpenId.
BUGGY CODE (causes #5559 parse error):
For {
Set key = $ORDER(users(key))
Quit:key = ""
If ($ZCONVERT(key, "U") = searchName) { Return users(key) }
}
BUG PATTERN: Spaces in postfix condition cause parse error.
ROOT CAUSE: Quit:key = "" — the space before = causes IRIS UDL parser error #5559.
Postfix conditions must be written without any spaces.
FIXED CODE:
For {
Set key = $ORDER(users(key))
Quit:key=""
If ($ZCONVERT(key, "U") = searchName) { Return users(key) }
}
KEY RULE: Postfix conditions: Quit:condition — NO spaces anywhere in the condition.
Quit:key="" not Quit:key = "". Also never append postfix to other statements.
BUGGY CODE:
ClassMethod BuildCSV(values As %ListOfDataTypes) As %String
{
Set result = ""
For i=1:1:values.Count() {
If (i > 1) { Set result = result _ "," }
Set result = result _ values.GetAt(i)
}
Return result
}
BUG PATTERN: O(n²) string concatenation — fails performance test for large lists.
ROOT CAUSE: Each result _ value creates a new string copying all previous data.
For 1000 items this copies ~500,000 total characters.
FIXED CODE:
ClassMethod BuildCSV(values As %ListOfDataTypes) As %String
{
Set lst = ""
For i=1:1:values.Count() {
Set lst = lst _ $LISTBUILD(values.GetAt(i))
}
Return $LISTTOSTRING(lst, ",")
}
KEY RULE: Accumulate into $LIST then convert once with $LISTTOSTRING(lst, ",").
For every bug fix request:
This structure is mandatory — stating the pattern before generating code prevents the most common errors.
npx claudepluginhub intersystems-community/iris-agentic-devHard gate checklist that catches common ObjectScript mistakes before showing code to the user. Covers Quit/Return, postfix syntax, $IsObject checks, SQL table names, SQLCODE, HTML escaping, arithmetic, $ListBuild, %Status, transactions, storage blocks, %INLIST, and '= in SQL strings.
Save, organize, search, and retrieve code snippets using tags, categories, smart search, and context suggestions. Invoke via /snippet-manager for commands like --search or --category.
Checks ABAP code against Clean ABAP principles (naming, language constructs, constants, variables, error handling, formatting). Useful for code reviews and quality audits.