T4.5: Decision and Control Structures

Knowledge Review - InterSystems ObjectScript Specialist

1. Post-condicionales

Puntos Clave

  • Sintaxis: COMMAND:condition arguments -- dos puntos entre el comando y la condición
  • Código compacto: Ejecuta un solo comando condicionalmente sin bloques IF/ELSE
  • SET:condition: SET:condition var = value -- solo establece si la condición es verdadera
  • QUIT:condition: Sale de un bucle o método condicionalmente
  • DO:condition: Llama a un método condicionalmente
  • WRITE:condition: Muestra salida condicionalmente
  • Cualquier comando: La mayoría de los comandos de ObjectScript soportan post-condicionales
  • Sin ELSE: Los post-condicionales no tienen contraparte ELSE -- use IF/ELSE para eso

Notas Detalladas

Descripción general

Los post-condicionales son una característica distintiva de ObjectScript que permite ejecutar cualquier comando condicionalmente agregando dos puntos y una expresión booleana directamente después de la palabra clave del comando. Esto produce código conciso y legible para operaciones condicionales simples sin la sobrecarga de bloques IF/ELSE completos.

Sintaxis básica de post-condicional

 SET x = 10

 // SET with post-conditional
 SET:x>5 message = "x is large"
 WRITE message, !                  // x is large

 // Equivalent to:
 IF x > 5 SET message = "x is large"

 // WRITE with post-conditional
 WRITE:x>5 "Greater than 5", !

 // Multiple post-conditionals (each independent)
 SET:x>20 category = "very large"
 SET:x>10 category = "large"
 SET:x>5 category = "medium"
 SET:x<=5 category = "small"
 WRITE category, !                 // medium

QUIT con post-condicional

 // Early exit from a FOR loop
 SET sum = 0
 FOR i = 1:1:100 {
     SET sum = sum + i
     QUIT:sum>100
 }
 WRITE "Sum: ", sum, " at i=", i, !
 // Output: Sum: 105 at i=14

 // In method: return early if precondition fails
 ClassMethod Divide(a As %Numeric, b As %Numeric) As %Numeric
 {
     QUIT:b=0 ""    // Return empty if division by zero
     QUIT a / b
 }

DO con post-condicional

 // Call a method only if condition is met
 DO:status'=$$$OK ..LogError(status)

 // Multiple conditional calls
 DO:age>=18 ..ProcessAdult(name)
 DO:age<18 ..ProcessMinor(name)

Post-condicional con expresiones complejas

 // Parentheses for complex conditions
 SET:(x>0)&&(x<100) range = "valid"

 // String conditions
 SET name = "Alice"
 WRITE:name="Alice" "Found Alice!", !

 // Negation
 SET:(obj'="") result = obj.Calculate()

 // Post-conditional on KILL
 KILL:cleanup tempVar

Patrones comunes

 // Default value assignment
 SET:('$DATA(config)) config = "default"

 // Conditional increment
 SET:isValid count = count + 1

 // Guard clause in a method
 ClassMethod Process(input As %String) As %Status
 {
     QUIT:input="" $$$ERROR($$$GeneralError, "Input required")
     // ... rest of processing
     QUIT $$$OK
 }

 // Conditional THROW
 THROW:status'=$$$OK ##class(%Exception.StatusException).CreateFromStatus(status)

Referencias de Documentación

2. QUIT vs RETURN

Puntos Clave

  • QUIT: Sale del contexto actual -- cuerpo de bucle, método o bloque DO
  • RETURN: Siempre sale del método/rutina actual, incluso desde dentro de un bucle
  • QUIT en bucle: Sale solo del bucle más interno, continúa después del bucle
  • RETURN en bucle: Sale del método completo desde dentro del bucle
  • Valor de retorno: Tanto QUIT expr como RETURN expr pueden devolver valores desde métodos
  • QUIT desde método: Cuando se usa fuera de un bucle, QUIT sale del método (igual que RETURN)

Notas Detalladas

Descripción general

QUIT y RETURN ambos salen del código, pero difieren en de qué salen. QUIT sale del contexto envolvente más cercano (bucle o método), mientras que RETURN siempre sale del método. Esta distinción es crítica cuando necesita salir de un método desde dentro de un bucle anidado.

QUIT en bucles vs métodos

 ClassMethod Example1()
 {
     WRITE "Before loop", !
     FOR i = 1:1:10 {
         QUIT:i=3         // Exits the FOR loop only
     }
     WRITE "After loop, i=", i, !    // Prints! i=3
     WRITE "Method continues", !      // Also prints
 }
 ClassMethod Example2()
 {
     WRITE "Before loop", !
     FOR i = 1:1:10 {
         RETURN:i=3       // Exits the ENTIRE METHOD
     }
     WRITE "After loop", !            // NEVER reached
 }

QUIT vs RETURN en bucles anidados

 ClassMethod NestedExample()
 {
     FOR i = 1:1:5 {
         FOR j = 1:1:5 {
             IF (i = 3) && (j = 2) {
                 QUIT    // Exits inner FOR loop only
                 // Outer loop continues with i=3, then i=4, i=5
             }
         }
         WRITE "i=", i, !    // Prints for all i values
     }
     WRITE "Done", !          // Prints
 }
 ClassMethod NestedReturn()
 {
     FOR i = 1:1:5 {
         FOR j = 1:1:5 {
             IF (i = 3) && (j = 2) {
                 RETURN   // Exits the ENTIRE method immediately
             }
         }
         WRITE "i=", i, !    // Prints for i=1, i=2 only
     }
     WRITE "Done", !          // NEVER reached
 }

Devolver valores

 // QUIT with return value (in a method returning a value)
 ClassMethod Add(a, b) As %Integer
 {
     QUIT a + b
 }

 // RETURN with return value
 ClassMethod FindFirst(list As %ListOfDataTypes) As %String
 {
     FOR i = 1:1:list.Count() {
         SET item = list.GetAt(i)
         IF item [ "target" {
             RETURN item    // Exit method immediately with value
         }
     }
     RETURN ""              // Not found
 }

 // QUIT in a method with no return value
 ClassMethod Process()
 {
     QUIT:errorCondition    // Exit method (no return value)
     // ... processing
 }

QUIT en bloques DO

 // QUIT exits a DO block (argumentless DO with code block)
 DO {
     SET x = $RANDOM(10)
     QUIT:x=5              // Exits the DO block, not any outer loop
     WRITE x, " "
 } WHILE x '= 5

Referencias de Documentación

3. Evaluación booleana

Puntos Clave

  • Verdadero: Cualquier valor numérico distinto de cero es verdadero (1, -1, 42, 3.14)
  • Falso: Cero (0) es falso
  • Cadena vacía: "" se evalúa como 0, que es falso
  • Cadenas no numéricas: "abc" se evalúa como 0 (falso) porque su valor numérico es 0
  • Cadenas con número inicial: "5abc" se evalúa como 5, que es verdadero
  • Canónico: La veracidad depende de la interpretación numérica del valor
  • Resultado booleano: Los operadores de comparación y lógicos siempre devuelven 0 o 1

Notas Detalladas

Descripción general

ObjectScript no tiene un tipo booleano dedicado. En su lugar, usa evaluación numérica: cero es falso, cualquier valor distinto de cero es verdadero. Cuando una cadena se evalúa como booleano, primero se convierte a su valor numérico. Comprender esta coerción es crítico para escribir condiciones correctas.

Reglas de veracidad

 // Nonzero = true
 IF 1 WRITE "1 is true", !            // prints
 IF -1 WRITE "-1 is true", !          // prints
 IF 42 WRITE "42 is true", !          // prints
 IF 0.001 WRITE "0.001 is true", !    // prints

 // Zero = false
 IF 0 WRITE "0 is true", !            // does NOT print
 IF '0 WRITE "0 is false", !          // prints

 // Empty string = 0 = false
 IF "" WRITE "empty is true", !       // does NOT print
 SET x = ""
 IF 'x WRITE "empty is false", !      // prints

 // Non-numeric strings = 0 = false
 IF "abc" WRITE "abc is true", !      // does NOT print
 IF "hello" WRITE "hello is true", !  // does NOT print

 // Leading numeric strings = their numeric value
 IF "5abc" WRITE "5abc is true", !    // prints (5 is nonzero)
 IF "0abc" WRITE "0abc is true", !    // does NOT print (0)

Resultados booleanos de comparaciones

 // Comparisons return exactly 0 or 1
 WRITE 5 > 3, !             // 1
 WRITE 3 > 5, !             // 0
 WRITE "A" = "A", !         // 1
 WRITE "A" = "B", !         // 0

 // Can store boolean results
 SET isAdult = (age >= 18)
 SET isValid = (name '= "") && (age > 0)

 // Boolean arithmetic
 SET total = (a > 0) + (b > 0) + (c > 0)
 WRITE "Number of positive values: ", total, !

Errores comunes de veracidad

 // PITFALL: Testing a string that should be boolean
 SET flag = "yes"
 IF flag WRITE "flag is true", !      // does NOT print!
 // "yes" has numeric value 0, so it is false in boolean context

 // Correct approach: test against specific values
 IF flag = "yes" WRITE "flag is yes", !  // prints

 // PITFALL: Empty string vs zero
 // In boolean context (IF), "" acts like 0 (false)
 // But "" and 0 are NOT equal with the = operator!
 SET val = ""
 IF val WRITE "truthy", !             // does NOT print ("" is falsy)
 IF val = 0 WRITE "equal to zero", !  // does NOT print! ("" '= 0)
 IF val = "" WRITE "equal to empty", ! // prints

 SET zero = 0
 IF zero WRITE "truthy", !            // does NOT print (0 is falsy)
 IF zero = "" WRITE "equal to empty", ! // does NOT print! (0 '= "")
 IF zero = 0 WRITE "equal to zero", ! // prints

 // To coerce "" to numeric before comparison, use unary +
 WRITE +"" = 0, !            // 1 (+"" gives 0, then 0 = 0)
 WRITE "" = 0, !             // 0 ("" is not 0)

 // PITFALL: Non-numeric strings are all falsy
 IF "yes" WRITE "yes", !     // does NOT print ("yes" = 0 numerically)
 IF "true" WRITE "true", !   // does NOT print
 IF "abc" WRITE "abc", !     // does NOT print
 WRITE "yes" = 0, !          // 0 ("yes" is not 0 -- different values)
 WRITE +"yes" = 0, !         // 1 (+"yes" coerces to 0, then 0 = 0)

Operador NOT

 SET x = 5
 WRITE 'x, !                // 0 (NOT 5 = false)

 SET y = 0
 WRITE 'y, !                // 1 (NOT 0 = true)

 // Double negation
 WRITE ''x, !               // 1 (NOT NOT 5 = true)
 WRITE ''y, !               // 0 (NOT NOT 0 = false)

 // '' can normalize any value to 0 or 1
 SET normalized = ''someValue
 // normalized is now exactly 0 or 1

Veracidad en control de flujo

 // IF uses truthiness
 SET name = "Alice"
 IF name WRITE "name has a value", !    // does NOT print ("Alice" = 0)

 // Correct: check for non-empty
 IF name '= "" WRITE "name is not empty", !  // prints

 // $DATA returns 0 (falsy) or 1/10/11 (truthy)
 IF $DATA(^config("key")) WRITE "key exists", !

 // $LENGTH returns 0 for empty, positive for non-empty
 IF $LENGTH(name) WRITE "name has length", !  // prints (5 > 0)

Resumen de Preparación para el Examen

Conceptos críticos a dominar:

  1. Sintaxis post-condicional: COMMAND:condition -- dos puntos directamente después del comando, sin espacio
  2. QUIT vs RETURN: QUIT sale del contexto más cercano (bucle o método); RETURN siempre sale del método
  3. QUIT en bucles anidados: Solo sale del bucle más interno -- use RETURN para salir del método
  4. Evaluación booleana: 0 = falso, distinto de cero = verdadero; "" es falso; "abc" es falso (valor numérico 0)
  5. Trampa de veracidad de cadenas: "yes", "true", "abc" son todos FALSOS porque su valor numérico es 0
  6. "" vs 0: Ambos son falsos en contexto booleano, pero `"" = 0` es FALSO -- son valores diferentes. Use el `+` unario para coaccionar cadenas a números antes de la comparación numérica
  7. Post-condicionales en cualquier comando: SET, QUIT, DO, WRITE, KILL, THROW todos los soportan
  8. Valores de retorno: Tanto QUIT expr como RETURN expr pueden devolver valores desde métodos

Escenarios comunes de examen:

  • Predecir si QUIT sale de un bucle o método según el contexto
  • Determinar la salida de código con post-condicionales
  • Evaluar expresiones booleanas con valores de cadena (trampas de veracidad)
  • Elegir entre QUIT y RETURN para una necesidad dada de control de flujo
  • Escribir cláusulas de guarda con QUIT:condition en métodos
  • Comprender que "" y 0 son ambos falsos pero `"" = 0` es falso
  • Determinar qué líneas se ejecutan después de QUIT en un bucle anidado

Recomendaciones de práctica:

  • Escribir métodos usando post-condicionales en lugar de bloques IF y verificar el comportamiento
  • Crear bucles anidados y probar QUIT vs RETURN en diferentes niveles
  • Experimentar con veracidad de varios valores: "", "abc", "0", "1", 0, 1, "5abc"
  • Probar `"" = 0`, `0 = ""`, `+"" = 0` para comprender coerción vs comparación
  • Escribir un método que use QUIT:condition como cláusula de guarda
  • Practicar el patrón de QUIT:errorCondition $$$ERROR(...)
  • Probar doble negación ('') para normalizar valores a booleano 0/1

Report an Issue