T1.3: Creates ObjectScript Methods

Knowledge Review - InterSystems ObjectScript Specialist

1. Diferencia entre métodos de instancia y métodos de clase (Method vs ClassMethod, sintaxis ..property)

Puntos Clave

  • Method: Método de instancia que opera sobre una instancia de objeto específica; tiene acceso a propiedades vía `..PropertyName`
  • ClassMethod: Se invoca sobre la clase misma sin requerir una instancia de objeto
  • Los métodos de instancia reciben una referencia implícita `%This` al objeto actual
  • La sintaxis ..PropertyName accede a las propiedades de la instancia actual (solo en métodos de instancia)
  • Los métodos de clase no pueden usar la sintaxis `..` porque no hay instancia de objeto

Notas Detalladas

Descripción general

InterSystems IRIS distingue entre dos tipos fundamentales de métodos. La elección entre ellos determina cómo se invoca el método y a qué datos puede acceder. Esta distinción es crítica para el diseño correcto de clases.

Métodos de Instancia

Class Sample.Person Extends %Persistent
{
    Property Name As %String;
    Property DOB As %Date;

    /// Instance method - operates on a specific person
    Method GetAge() As %Integer
    {
        Set today = +$HOROLOG
        Set birthDays = ..DOB
        Return (today - birthDays) \ 365.25
    }

    /// Instance method that modifies the object
    Method UpdateName(newName As %String) As %Status
    {
        Set ..Name = newName
        Return ..%Save()
    }
}

Llamar a un método de instancia requiere una referencia de objeto:

Set person = ##class(Sample.Person).%OpenId(1)
Set age = person.GetAge()
Write "Age: ", age, !

Métodos de Clase

Class Sample.Person Extends %Persistent
{
    /// Class method - no object instance needed
    ClassMethod FindByName(name As %String) As Sample.Person
    {
        &sql(SELECT ID INTO :id FROM Sample.Person WHERE Name = :name)
        If SQLCODE = 0 {
            Return ##class(Sample.Person).%OpenId(id)
        }
        Return ""
    }

    /// Class method - utility function
    ClassMethod GetCount() As %Integer
    {
        &sql(SELECT COUNT(*) INTO :count FROM Sample.Person)
        Return count
    }
}

Llamar a un método de clase usa la sintaxis de referencia de clase:

Set person = ##class(Sample.Person).FindByName("John Smith")
Set total = ##class(Sample.Person).GetCount()

La Sintaxis ..

La sintaxis de doble punto es azúcar sintáctico disponible solo en métodos de instancia:

  • ..PropertyName accede a una propiedad (equivalente a $THIS.PropertyName)
  • ..MethodName() llama a otro método de instancia sobre el mismo objeto
  • ..#ParameterName accede a un parámetro de clase (funciona tanto en métodos de instancia como de clase)
Method DisplayInfo()
{
    Write "Name: ", ..Name, !
    Write "Age: ", ..GetAge(), !         // calls instance method
    Write "Type: ", ..#OBJECTTYPE, !     // accesses class parameter
}

Cuándo Usar Cada Tipo

Usar Método de Instancia Cuando...Usar ClassMethod Cuando...
Se opera sobre los datos de un objeto específicoNo se necesita un objeto específico
Se accede o modifica propiedadesSe realizan búsquedas o consultas
Se computan valores derivados de propiedadesSe crean métodos de fábrica
Se implementa lógica de negocio para un objetoSe implementan funciones utilitarias

Referencias de Documentación

2. Usa parámetros de clase dentro de métodos (..#ParameterName)

Puntos Clave

  • ..#ParameterName accede a un parámetro de clase desde cualquier método (instancia o clase)
  • Los parámetros de clase actúan como constantes definidas a nivel de clase
  • Los parámetros pueden sobrescribirse en subclases, habilitando comportamiento polimórfico
  • Parámetros comunes del sistema: DEFAULTGLOBAL, USEEXTENTSET, MANAGEDEXTENT
  • Usar parámetros para valores de configuración que pueden variar por subclase

Notas Detalladas

Descripción general

Los parámetros de clase definen constantes asociadas a una clase. Proporcionan una forma de configurar el comportamiento de la clase sin codificar valores de forma fija en los métodos. Dado que los parámetros pueden sobrescribirse en subclases, habilitan un patrón poderoso donde los métodos de la clase base adaptan su comportamiento según la configuración de la subclase.

Definición y Acceso a Parámetros

Class Sample.Notification Extends %RegisteredObject
{
    Parameter MAXRETRIES = 3;
    Parameter TIMEOUT = 30;
    Parameter PROVIDER = "Email";

    Method Send(message As %String) As %Status
    {
        For i = 1:1:..#MAXRETRIES {
            // Attempt to send with timeout
            Set sc = ..DoSend(message, ..#TIMEOUT)
            If $$$ISOK(sc) Return sc
        }
        Return $$$ERROR($$$GeneralError, "Failed after " _ ..#MAXRETRIES _ " retries")
    }

    ClassMethod GetProvider() As %String
    {
        Return ..#PROVIDER
    }
}

Sobrescritura de Parámetros en Subclases

Class Sample.SMSNotification Extends Sample.Notification
{
    Parameter MAXRETRIES = 5;
    Parameter TIMEOUT = 10;
    Parameter PROVIDER = "SMS";
}

Cuando SMSNotification.Send() se ejecuta, ..#MAXRETRIES evalúa a 5 y ..#TIMEOUT a 10 (los valores sobrescritos), aunque el código del método esté definido en la clase padre. Esto se resuelve en tiempo de compilación.

Tipos de Parámetros

Los parámetros pueden tener opcionalmente una restricción de tipo:

Parameter BATCHSIZE As %Integer = 100;
Parameter ENABLED As %Boolean = 1;
Parameter PREFIX As %String = "APP";

Parámetros Comunes del Sistema

Varios parámetros del sistema controlan el comportamiento de las clases:

ParámetroPropósito
USEEXTENTSETUsar nombres de globals con hash para el almacenamiento
MANAGEDEXTENTPermitir que %ExtentMgr rastree la extensión
DEFAULTGLOBALSobrescribir el nombre de global por defecto para almacenamiento
READONLYPrevenir la modificación de objetos
DSTIMEHabilitar la sincronización BI

Uso de Parámetros para Comportamiento Configurable

Class Sample.BaseProcessor Extends %RegisteredObject
{
    Parameter LOGPREFIX = "PROC";
    Parameter LOGLEVEL = 2;

    Method Log(message As %String, level As %Integer = 1)
    {
        If level <= ..#LOGLEVEL {
            Write "[", ..#LOGPREFIX, "] ", message, !
        }
    }
}

Referencias de Documentación

3. Especifica argumentos de método y tipo de retorno (cláusula As, Output, ByRef)

Puntos Clave

  • As ClassName especifica el tipo de retorno de un método
  • Los argumentos del método se declaran con nombre, tipo opcional y valor por defecto opcional
  • La palabra clave Output indica que el argumento es solo de salida (no se pasa como entrada)
  • La palabra clave ByRef indica que el argumento se pasa por referencia (tanto entrada como salida)
  • Importante: `ByRef` y `Output` en la lista de parámetros formales son puramente indicativos — no tienen efecto intrínseco en cómo se pasa el argumento. Es el llamador quien decide usando el prefijo punto (`.`). El método funcionaría igual incluso sin `ByRef`/`Output` en la firma.
  • Los valores por defecto se especifican con `= value` en la lista de argumentos

Notas Detalladas

Descripción general

Las firmas de métodos bien definidas mejoran la claridad del código, habilitan mejor verificación en tiempo de compilación y generan documentación precisa. InterSystems IRIS soporta argumentos tipados, tipos de retorno, valores por defecto y parámetros por referencia.

Firma Básica de Método

Method Calculate(x As %Numeric, y As %Numeric) As %Numeric
{
    Return x + y
}

El As %Numeric después del paréntesis de cierre especifica el tipo de retorno. Los tipos de argumentos siguen a cada nombre de argumento.

Valores por Defecto

Method FormatDate(date As %Date, format As %String = "YYYY-MM-DD") As %String
{
    // format defaults to "YYYY-MM-DD" if not provided
    Return $ZDate(date, 3)
}

Llamando con o sin el parámetro opcional:

Set result = obj.FormatDate($HOROLOG)          // uses default format
Set result = obj.FormatDate($HOROLOG, "MM/DD") // overrides default

Parámetros Output

La palabra clave Output marca un argumento como solo de salida. El llamador no debe pasar un valor; el método lo establecerá:

ClassMethod Divide(a As %Numeric, b As %Numeric, Output result As %Numeric) As %Status
{
    If b = 0 Return $$$ERROR($$$GeneralError, "Division by zero")
    Set result = a / b
    Return $$$OK
}

Llamando con un parámetro de salida (usar el prefijo punto):

Set sc = ##class(Sample.Math).Divide(10, 3, .answer)
If $$$ISOK(sc) Write "Result: ", answer, !

Parámetros ByRef

La palabra clave ByRef marca un argumento como pasado por referencia. La variable del llamador se lee y se modifica:

ClassMethod Increment(ByRef counter As %Integer, amount As %Integer = 1)
{
    Set counter = counter + amount
}

Llamando:

Set myCount = 5
Do ##class(Sample.Util).Increment(.myCount, 3)
Write myCount  // Outputs: 8

Distinción Clave: Output vs ByRef

AspectoOutputByRef
Valor inicial pasado como entradaNo (indefinido dentro del método)Sí (valor del llamador disponible)
Valor devuelto al llamador
Sintaxis del llamador.variable.variable
Significado semánticoEl método produce un valorEl método lee y modifica un valor

Importante: ByRef y Output Son Puramente Indicativos

En ObjectScript, ByRef y Output en la lista de parámetros formales son solo indicaciones de documentación — no tienen efecto de aplicación ni en tiempo de ejecución. El mecanismo de paso se controla enteramente por el llamador usando el prefijo punto (.).

Esto significa:

  • Un llamador puede usar .variable incluso si el parámetro no está declarado como ByRef u Output — y funciona
  • Un llamador puede omitir el punto incluso si el parámetro está declarado como ByRef — y simplemente se pasa por valor
  • Podría eliminar ByRef/Output de cada firma de método y todo seguiría funcionando idénticamente
/// No ByRef or Output keyword — but pass-by-reference still works!
ClassMethod AddSuffix(text As %String, suffix As %String)
{
    Set text = text _ suffix
}
Set myText = "Hello"
Do ##class(Sample.Util).AddSuffix(.myText, " World")
Write myText  // "Hello World" — modified despite no ByRef in signature!

Mejor práctica: Siempre declarar ByRef u Output en la firma como documentación para el llamador, aunque las palabras clave en sí no tengan efecto. Señalan el contrato previsto del método.

Métodos que Devuelven %Status

Un patrón común es devolver %Status y usar parámetros Output para los resultados reales:

ClassMethod ProcessData(input As %String, Output result As %String, Output errorMsg As %String) As %Status
{
    If input = "" {
        Set errorMsg = "Input cannot be empty"
        Return $$$ERROR($$$GeneralError, errorMsg)
    }
    Set result = $ZCONVERT(input, "U")
    Return $$$OK
}

Referencias de Documentación

4. Pasa objetos a métodos (paso de oref)

Puntos Clave

  • Las referencias de objeto (orefs) se pasan por valor por defecto, pero el oref es un puntero al objeto
  • Modificar las propiedades de un objeto pasado afecta al objeto original (referencia compartida)
  • Asignar un nuevo objeto a la variable del parámetro NO afecta la variable del llamador
  • La verificación de tipos se realiza en tiempo de compilación cuando se especifican los tipos de argumentos
  • Los objetos tienen conteo de referencias; persisten mientras al menos una variable los referencie

Notas Detalladas

Descripción general

Cuando pasa un objeto a un método, está pasando la referencia de objeto (oref), que es esencialmente un puntero al objeto en memoria. Comprender esto es crítico para evitar errores relacionados con modificaciones no intencionadas o referencias perdidas.

Paso de Objetos

Class Sample.OrderProcessor Extends %RegisteredObject
{
    ClassMethod ApplyDiscount(order As Sample.Order, pct As %Numeric)
    {
        // This modifies the ORIGINAL order object
        Set order.Total = order.Total * (1 - (pct / 100))
    }

    ClassMethod ProcessOrder(order As Sample.Order) As %Status
    {
        // Validate the order
        If order.Total <= 0 {
            Return $$$ERROR($$$GeneralError, "Invalid total")
        }
        // Modify the order's status
        Set order.Status = "Processed"
        Return order.%Save()
    }
}

Uso:

Set order = ##class(Sample.Order).%OpenId(1)
Write "Before: ", order.Total, !         // e.g., 100
Do ##class(Sample.OrderProcessor).ApplyDiscount(order, 10)
Write "After: ", order.Total, !          // 90 (original object modified)

Semántica de Valor de la Referencia

El oref en sí se pasa por valor. Reasignar la variable del parámetro dentro del método no cambia la variable del llamador:

ClassMethod ResetOrder(order As Sample.Order)
{
    // This does NOT affect the caller's variable
    Set order = ##class(Sample.Order).%New()
    Set order.Total = 0
}
Set myOrder = ##class(Sample.Order).%OpenId(1)
Do ##class(Sample.OrderProcessor).ResetOrder(myOrder)
// myOrder still points to the original object (ID 1), unchanged

Para modificar realmente la variable del llamador, usar ByRef u Output:

ClassMethod ResetOrder(ByRef order As Sample.Order)
{
    Set order = ##class(Sample.Order).%New()
    Set order.Total = 0
}
// Now calling with: Do ##class(...).ResetOrder(.myOrder) changes myOrder

Paso de Objetos en Colecciones

ClassMethod ProcessAll(orders As %ListOfObjects) As %Status
{
    For i = 1:1:orders.Count() {
        Set order = orders.GetAt(i)
        Set order.Status = "Processed"
    }
    Return $$$OK
}

Verificación del Tipo de Objeto en Tiempo de Ejecución

ClassMethod HandleItem(item As %RegisteredObject)
{
    If item.%IsA("Sample.Order") {
        // Order-specific logic
    } ElseIf item.%IsA("Sample.Invoice") {
        // Invoice-specific logic
    }
}

Referencias de Documentación

5. Pasa variables por referencia (ByRef, sintaxis .variable en el sitio de llamada)

Puntos Clave

  • El prefijo punto (.) en el sitio de llamada es el único mecanismo que controla el paso por referencia — es decisión del llamador
  • `ByRef` en la firma del método es puramente indicativo (documentación) — no tiene efecto en tiempo de ejecución
  • Sin el punto, el valor se pasa siempre por valor, independientemente de `ByRef` en la firma
  • Con el punto, el valor se pasa siempre por referencia, incluso si la firma no tiene `ByRef`
  • ByRef pasa el valor existente COMO ENTRADA y permite un nuevo valor COMO SALIDA

Notas Detalladas

Descripción general

Por defecto, ObjectScript pasa los argumentos por valor. Cuando un método necesita modificar una variable en el ámbito del llamador, el llamador debe pasar por referencia usando el prefijo punto (.). La palabra clave ByRef en la firma es una mejor práctica para documentación pero no tiene efecto de aplicación — es enteramente responsabilidad del llamador usar el punto.

Patrón Básico de ByRef

ClassMethod Swap(ByRef a As %String, ByRef b As %String)
{
    Set temp = a
    Set a = b
    Set b = temp
}

Llamando:

Set x = "Hello"
Set y = "World"
Do ##class(Sample.Util).Swap(.x, .y)
Write x  // "World"
Write y  // "Hello"

Olvidar el Punto

Un error común es olvidar el punto en el sitio de llamada:

Set x = "Hello"
Set y = "World"
Do ##class(Sample.Util).Swap(x, y)  // NO dots - passed by value!
Write x  // Still "Hello" - unchanged
Write y  // Still "World" - unchanged

El método se ejecuta sin error, pero las variables del llamador no se modifican porque se pasaron copias.

Output vs ByRef Revisitado

Con Output, el valor inicial de la variable no se pasa al método:

ClassMethod GetInfo(Output name As %String, Output count As %Integer)
{
    Set name = "Test"
    Set count = 42
}

// Calling:
Do ##class(Sample.Util).GetInfo(.n, .c)
Write n   // "Test"
Write c   // 42

Con ByRef, el valor existente SÍ está disponible dentro del método:

ClassMethod AppendSuffix(ByRef text As %String, suffix As %String)
{
    Set text = text _ suffix
}

Set myText = "Hello"
Do ##class(Sample.Util).AppendSuffix(.myText, " World")
Write myText  // "Hello World"

Ejemplo Práctico: Recolección de Errores

ClassMethod ValidateRecord(record As Sample.Record, ByRef errors As %List) As %Boolean
{
    // errors may already contain items from prior validation
    If record.Name = "" {
        Set errors = errors _ $LB("Name is required")
    }
    If record.Age < 0 {
        Set errors = errors _ $LB("Age must be positive")
    }
    Return ($LISTLENGTH(errors) = 0)
}

Referencias de Documentación

6. Pasa variables multidimensionales por referencia (paso de arrays)

Puntos Clave

  • ObjectScript soporta variables multidimensionales (arrays con subíndices)
  • Pasar arrays por referencia usando el prefijo punto (.) para compartir todo el árbol de subíndices
  • El método recibe el array con todos sus subíndices intactos
  • Usar $ORDER para iterar sobre los subíndices
  • Los arrays no pueden pasarse por valor (solo se copiaría el nodo superior sin los subíndices)

Notas Detalladas

Descripción general

Las variables multidimensionales (arrays) son una estructura de datos fundamental en ObjectScript. Almacenan datos en múltiples niveles de subíndices dentro de un solo nombre de variable. Pasar arrays a métodos requiere paso por referencia para incluir todos los niveles de subíndices.

Fundamentos de Variables Multidimensionales

Set colors("red") = "#FF0000"
Set colors("green") = "#00FF00"
Set colors("blue") = "#0000FF"
Set colors("blue", "light") = "#ADD8E6"
Set colors("blue", "dark") = "#00008B"

Paso de Arrays a Métodos

ClassMethod DisplayColors(ByRef colors)
{
    Set key = ""
    For {
        Set key = $ORDER(colors(key))
        Quit:key=""
        Write key, ": ", colors(key), !
    }
}

Llamando:

Set colors("red") = "#FF0000"
Set colors("green") = "#00FF00"
Set colors("blue") = "#0000FF"
Do ##class(Sample.Util).DisplayColors(.colors)

Salida:

blue: #0000FF
green: #00FF00
red: #FF0000

Construcción de Arrays Dentro de Métodos

ClassMethod GetStateCounts(Output states)
{
    &sql(DECLARE C1 CURSOR FOR
         SELECT State, COUNT(*) FROM Sample.Person GROUP BY State)
    &sql(OPEN C1)
    For {
        &sql(FETCH C1 INTO :state, :cnt)
        Quit:SQLCODE'=0
        Set states(state) = cnt
    }
    &sql(CLOSE C1)
}

Llamando:

Do ##class(Sample.Util).GetStateCounts(.states)
Set st = "" For {
    Set st = $ORDER(states(st)) Quit:st=""
    Write st, ": ", states(st), !
}

Paso de Arrays Multi-Nivel

ClassMethod ProcessTree(ByRef tree, level As %Integer = 0)
{
    Set key = ""
    For {
        Set key = $ORDER(tree(key))
        Quit:key=""
        Write ?level*4, key, ": ", $GET(tree(key)), !
        // Recursively process sub-nodes
        // Note: must merge to a temp variable for recursive call
        Merge sub = tree(key)
        If $DATA(sub) > 1 {
            Do ..ProcessTree(.sub, level + 1)
        }
        Kill sub
    }
}

Uso de $DATA para Verificar Nodos de Array

// $DATA returns:
// 0 - node doesn't exist
// 1 - node has data, no children
// 10 - node has children but no data
// 11 - node has both data and children

If $DATA(arr("key")) > 9 {
    Write "Has child subscripts", !
}

Comando MERGE para Operaciones con Arrays

// Copy an entire array
Merge targetArr = sourceArr

// Copy a subtree
Merge targetArr = sourceArr("subtree")

Referencias de Documentación

7. Usa y sobrescribe métodos heredados (sobrescritura, llamada al padre)

Puntos Clave

  • Las subclases heredan todos los métodos de su(s) superclase(s)
  • Una subclase puede sobrescribir un método heredado definiendo un método con el mismo nombre
  • El método que sobrescribe debe tener una firma compatible (mismos argumentos y tipo de retorno)
  • La palabra clave Final previene que un método sea sobrescrito en subclases
  • La sobrescritura es la base del polimorfismo en programación orientada a objetos

Notas Detalladas

Descripción general

La herencia de métodos permite que las subclases reutilicen el comportamiento de la clase padre. Cuando una subclase necesita un comportamiento diferente, sobrescribe el método heredado con su propia implementación. Este es un mecanismo clave de la programación orientada a objetos que habilita el polimorfismo.

Herencia Básica

Class Sample.Shape Extends %RegisteredObject
{
    Property Color As %String;

    Method Describe() As %String
    {
        Return "A shape of color " _ ..Color
    }

    Method Area() As %Numeric
    {
        Return 0
    }
}

Una subclase hereda todos los métodos automáticamente:

Class Sample.Circle Extends Sample.Shape
{
    Property Radius As %Numeric;

    /// Override Area to compute circle area
    Method Area() As %Numeric
    {
        Return $ZPI * (..Radius ** 2)
    }

    /// Override Describe
    Method Describe() As %String
    {
        Return "A circle of radius " _ ..Radius _ " and color " _ ..Color
    }
}

Comportamiento Polimórfico

ClassMethod PrintShapeInfo(shape As Sample.Shape)
{
    // Calls the appropriate version based on actual object type
    Write shape.Describe(), !
    Write "Area: ", shape.Area(), !
}

// Works with any Shape subclass
Set c = ##class(Sample.Circle).%New()
Set c.Radius = 5
Set c.Color = "Red"
Do ##class(Sample.Util).PrintShapeInfo(c)
// Output: A circle of radius 5 and color Red
// Area: 78.5398...

La Palabra Clave Final

Marcar un método como Final previene que las subclases lo sobrescriban:

Class Sample.Base Extends %RegisteredObject
{
    /// This method cannot be overridden
    Method Validate() As %Status [ Final ]
    {
        // Validation logic that must not be changed
        Return $$$OK
    }
}

Intentar sobrescribir un método Final en una subclase causa un error de compilación.

Reglas de Sobrescritura

  • El método que sobrescribe debe tener los mismos tipos de argumentos y tipo de retorno
  • Un método de instancia solo puede sobrescribirse por un método de instancia (igual para ClassMethod)
  • Si el método padre es Final, no puede sobrescribirse
  • El método que sobrescribe puede llamar a la implementación padre usando ##super()

Referencias de Documentación

8. Determina cuándo usar ##super para llamar métodos de la superclase

Puntos Clave

  • ##super() llama a la implementación de la superclase del método actual
  • Usar ##super cuando se desea extender el comportamiento padre, no reemplazarlo completamente
  • Patrón común: llamar a ##super primero para inicialización, luego agregar lógica personalizada
  • ##super sigue la cadena de herencia (llama a la siguiente clase en el MRO)
  • Crítico en %OnNew(), %OnOpen(), %OnValidateObject() y otros métodos callback

Notas Detalladas

Descripción general

Al sobrescribir un método, a menudo se desea mantener el comportamiento del padre y agregarlo en lugar de reemplazarlo completamente. La macro ##super() llama a la versión del método de la clase padre. Esto es especialmente importante en métodos callback donde la clase padre realiza configuración esencial.

Uso Básico de ##super

Class Sample.Employee Extends Sample.Person
{
    Property Department As %String;

    Method Describe() As %String
    {
        // Get the parent description first
        Set desc = ##super()
        // Extend it with employee-specific info
        Return desc _ " (Dept: " _ ..Department _ ")"
    }
}

##super en Métodos Callback

Los métodos callback como %OnNew(), %OnValidateObject() y %OnAfterSave() están definidos en clases del sistema. Cuando los sobrescribe, típicamente debe llamar a ##super() para asegurar que el comportamiento del sistema se preserve:

Class Sample.AuditedRecord Extends %Persistent
{
    Property CreatedBy As %String;
    Property CreatedDate As %Date;
    Property ModifiedDate As %Date;

    Method %OnNew(initvalue As %String) As %Status
    {
        // Call parent's %OnNew first
        Set sc = ##super(initvalue)
        If $$$ISERR(sc) Return sc

        // Add custom initialization
        Set ..CreatedBy = $USERNAME
        Set ..CreatedDate = +$HOROLOG
        Set ..ModifiedDate = +$HOROLOG
        Return $$$OK
    }

    Method %OnBeforeSave(insert As %Boolean) As %Status
    {
        Set sc = ##super(insert)
        If $$$ISERR(sc) Return sc

        // Update modified date on every save
        Set ..ModifiedDate = +$HOROLOG
        Return $$$OK
    }
}

Cuándo Usar ##super

EscenarioUsar ##super?Razón
Extender el comportamiento padrePreservar la lógica padre, agregar la propia
Reemplazar completamente el comportamientoNoLa lógica padre no se necesita
Métodos callback (%OnNew, etc.)Generalmente síEl padre puede realizar configuración esencial
Sobrescritura de método abstractoNoEl padre no tiene implementación
Herencia múltipleSí (con cuidado)##super sigue la cadena MRO

##super con Argumentos

Pasar los mismos argumentos al padre:

Method Process(data As %String, options As %String = "") As %Status
{
    // Pre-processing
    Set data = $ZSTRIP(data, "<>W")

    // Call parent with the modified data
    Set sc = ##super(data, options)
    If $$$ISERR(sc) Return sc

    // Post-processing
    Do ..LogActivity("Processed: " _ data)
    Return $$$OK
}

##super en Herencia Múltiple

Con herencia múltiple, ##super() llama a la siguiente clase en el orden de resolución de métodos, no necesariamente al "padre" en un sentido de herencia simple:

Class MyApp.C Extends (MyApp.A, MyApp.B)
{
    Method Init() As %Status
    {
        // Calls MyApp.A's Init (leftmost superclass)
        Return ##super()
    }
}

Error Común: Olvidar ##super

Olvidar llamar a ##super() en %OnNew() o %OnValidateObject() puede romper la inicialización o validación de la clase padre. Siempre considere si el padre tiene lógica que necesita preservar.

Referencias de Documentación

Resumen de Preparación para el Examen

Conceptos Críticos a Dominar:

  1. Los métodos de instancia usan la sintaxis `..`; los métodos de clase no pueden acceder a propiedades de instancia
  2. `..#ParameterName` funciona tanto en métodos de instancia como de clase
  3. Los parámetros se resuelven en tiempo de compilación y pueden sobrescribirse en subclases
  4. `Output` vs `ByRef`: Output no pasa el valor inicial como entrada; ByRef sí
  5. `ByRef` y `Output` en las firmas son puramente indicativos — el prefijo punto (.) del llamador es lo que realmente controla el paso por referencia
  6. Siempre usar el prefijo punto (.) en el sitio de llamada para parámetros ByRef y Output
  7. Los objetos pasados a métodos comparten la referencia; modificar propiedades afecta al original
  8. Reasignar la variable del parámetro no afecta al llamador a menos que se use ByRef
  9. Los arrays multidimensionales deben pasarse por referencia para incluir los subíndices
  10. `##super()` llama a la implementación padre; esencial en métodos callback
  11. Olvidar `##super()` en %OnNew o %OnValidateObject puede romper el comportamiento heredado

Escenarios Comunes en el Examen:

  • Identificar si un método debe ser Method o ClassMethod
  • Predecir la salida cuando una variable se pasa con o sin el prefijo punto
  • Determinar qué valor de parámetro se usa cuando una subclase sobrescribe un parámetro
  • Predecir el comportamiento cuando un objeto se pasa a un método y sus propiedades se modifican
  • Decidir si debe llamarse ##super() en una sobrescritura de método

Recomendaciones de Práctica:

  • Crear una jerarquía de clases con métodos de instancia y de clase; probar la sintaxis `..`
  • Escribir métodos con parámetros ByRef y Output; probar con y sin el prefijo punto
  • Pasar objetos a métodos y verificar que las modificaciones de propiedades son visibles para el llamador
  • Construir e iterar sobre arrays multidimensionales pasados por referencia
  • Sobrescribir métodos callback con y sin ##super() y observar las diferencias

Report an Issue