Los programadores suelen confundirse cuando intentan usar una variable como argumento en una función o mensaje JSL pero no obtienen el resultado esperado. Si bien existen muchas circunstancias en JSL en las que los programadores se encuentran con esta situación, la que los usuarios encuentran con frecuencia es cuando intentan establecer la propiedad de columna Spec Limits. Los valores que se usarán como Spec Limits se extraen a menudo de una tabla de búsqueda en un paso anterior donde se asignan a variables. Después de recopilar y asignar todos los valores límite a las variables, el siguiente paso lógico es usar estas variables para establecer la propiedad de columna en la tabla de análisis. Aquí hay un ejemplo representativo de lo que un programador podría intentar. Puede copiar este JSL en una ventana de programación y ejecutarlo para seguir.
Names Default to Here(1);
// Open a sample data table
dt = Open("$SAMPLE_DATA/Cleansing.jmp");
// Values previously obtained from a lookup table and assigned to variables as:
myLSL = 6;
myUSL = 8;
myTarget = 7;
// Use the variables to set the spec limits column property
Column(dt, "pH") << Set Property(
"Spec Limits",
{LSL( myLSL ), USL( myUSL ), Target( myTarget ), Show Limits( 1 )}
);
Cuando se ejecuta este script, aparece el ícono junto a la columna de pH, lo que indica que se ha configurado una propiedad de columna y al hacer clic en el ícono se confirma que se trata de la propiedad Límites de especificación.

Sin embargo, cuando abre la ventana de diálogo Información de columna para ver los valores de los Límites de especificación, ¡faltan!

¿Qué hizo JMP? Parecía que funcionaba, ¡pero solo parcialmente! ¿Por qué?
Para investigar, podemos usar JSL para ver la configuración de las propiedades. Tal vez esto nos brinde una pista. Evaluando la siguiente expresión,
Column(dt, "pH") << Get Property("Spec Limits");
da como resultado la siguiente información escrita en el registro:
{LSL( myLSL ), USL( myUSL ), Target( myTarget ), Show Limits( 1 )}
Bueno, ahí está, exactamente lo que especifiqué, pero ¿por qué no veo los valores que se asignaron a las variables en lugar de las variables en sí? La respuesta a esta pregunta llega al meollo de la confusión: JSL no siempre evalúa los argumentos suficientes veces para resolver el valor asignado, y la cantidad de veces que se evalúan los argumentos varía según las circunstancias en las que se utilizan las variables. Por ejemplo, en el contexto actual, JMP "analiza" el argumento de lista para comprender que hay elementos para especificar diferentes aspectos de la propiedad Spec Limits. Esa es una evaluación. En otra evaluación, JMP revisa los elementos de la lista para determinar qué límites (LSL, USL, Target, etc.) establecer en la propiedad Spec Limits. JMP no evalúa en absoluto los argumentos proporcionados dentro de los elementos de la lista (myLSL, myUSL, myTarget). JMP espera valores numéricos como argumentos para LSL, USL y Target. Cuando se proporciona una variable, JMP no la reconoce y no intenta resolver la variable para determinar el valor asociado.
Entonces, ¿puedo saber cuántas veces se evaluará un argumento en una circunstancia determinada? ¿Qué puedo hacer si necesito más evaluaciones, como en el ejemplo anterior? Como no tenemos acceso al código fuente de JMP, es muy difícil saber cuántas evaluaciones se realizarán en una circunstancia determinada. Sin embargo, eso es menos importante que saber si es suficiente para el uso actual. ¡Lo primero que hago es probar y verificar!
Sin tener conocimiento previo de cómo el mensaje Spec Limits espera valores, escribo mi script exactamente como se muestra inicialmente arriba. A continuación, verifico si Spec Limit se configuró revisándolo en el cuadro de diálogo Column Info o creando un gráfico con la columna para ver si las líneas de referencia del gráfico aparecen como deberían. Si la verificación falla, como en este caso, necesito editar mi expresión para eliminar las variables y codificar los valores numéricos en su lugar.
Column( dt, "pH" ) << Set Property(
"Spec Limits",
{LSL( 6 ), USL( 8 ), Target( 7 ), Show Limits( 1 )}
)
Luego ejecuto la expresión para verificar que el problema esté relacionado con el uso de variables y no con algún otro problema de sintaxis. Una vez que confirmé que la expresión proporciona el resultado esperado con los valores codificados, sé que me he encontrado con una circunstancia en la que mi variable no se está evaluando lo suficiente como para llegar al valor asignado. Por lo tanto, necesito que JMP cree la expresión dinámicamente en tiempo de ejecución para incorporar los valores de la variable en ella antes de evaluar la expresión.
Ahora bien, existen múltiples formas de evaluar previamente una variable, pero mi método preferido es utilizar la función Eval Expr(). Otros métodos incluyen el uso de la función Substitute() o la creación de la expresión JSL mediante la concatenación de cadenas y, a continuación, el análisis y la evaluación de la cadena final. Sin duda, mi método menos favorito es crear la expresión como una cadena. El código es muy difícil de leer porque es monocromático, por lo que pierdo el útil formato semántico proporcionado por el editor JSL y las comillas incrustadas deben escaparse. Peor aún, el código es difícil de depurar y solucionar problemas porque pierdo la capacidad de evaluar partes seleccionadas del código.
// An example of concatenating strings to dynamically write a JSL expression.
Parse(
"Column( dt, \!"pH\!" ) << Set Property(
\!"Spec Limits\!",
{LSL( " || Char(myLSL) || " ), USL( " || Char(myUSL) || " ), Target( " || Char(myTarget) || " ), Show Limits( 1 )}
)"
)
Usar la función Substitute() es mejor en este sentido, pero si la expresión es larga, me resulta difícil leerla y al mismo tiempo mirar los últimos argumentos que especifican qué sustituciones se están realizando y dónde.
// An example of using Substitute() to dynamically write a JSL expression.
Substitute(
Expr(Column(dt, "pH") << Set Property(
"Spec Limits",
{LSL( lll ), USL( uuu ), Target( ttt), Show Limits( 1 )}
))
,
Expr(lll), myLSL,
Expr(uuu), myUSL,
Expr(ttt), myTarget
)
Por el contrario, la función Eval Expr() permite la especificación de sustitución en línea y, dado que el argumento de la función es una expresión, el editor JSL puede mostrarlo con el formato semántico.
Entonces, ¿cómo funciona Eval Expr()? Es una función que toma una expresión como su único argumento y devuelve una expresión. Busca la expresión proporcionada para el token Expr(). Luego, JMP evalúa lo que está dentro de los paréntesis de Expr() y reemplaza el token completo con el valor de retorno. Volviendo al ejemplo anterior para establecer los límites de especificación, si "envuelvo" mis variables con Expr() y coloco la expresión completa dentro de una llamada Eval Expr(), JMP sustituirá mis variables (y el token Expr()) con los valores de las variables en tiempo de ejecución y devolverá la expresión modificada. Entonces,
// An example of using Eval Expr() to dynamically write a JSL expression.
Eval Expr(
Column(dt, "pH") << Set Property(
"Spec Limits",
{LSL( Expr(myLSL) ), USL( Expr(myUSL) ), Target( Expr(myTarget) ), Show Limits( 1 )} );
);
devoluciones:
Column( dt, "pH" ) << Set Property(
"Spec Limits",
{LSL( 6 ), USL( 8 ), Target( 7 ), Show Limits( 1 )}
)
¡Genial! Ahora tengo una expresión para establecer la propiedad Spec Limits que incluye los valores codificados deseados. ¡Acabo de escribir código JSL de forma dinámica! Ahora solo necesito evaluar esta expresión modificada. Para esto, la función Eval() es útil. Puedo encapsular Eval Expr(), llamar a una llamada Eval() y la expresión devuelta por Eval Expr() se evaluará inmediatamente. Aquí hay un script de ejemplo completo que establecerá la propiedad Spec Limits correctamente utilizando valores límite conocidos solo en tiempo de ejecución:
Names Default to Here(1);
// Open a sample data table
dt = Open("$SAMPLE_DATA/Cleansing.jmp");
// Values previously obtained from a lookup table and assigned to variables as:
myLSL = 6;
myUSL = 8;
myTarget = 7;
// Use the variables to set the spec limits column property
Eval(Eval Expr(
Column(dt, "pH") << Set Property(
"Spec Limits",
{LSL( Expr(myLSL) ), USL( Expr(myUSL) ), Target( Expr(myTarget) ), Show Limits( 1 )}
);
));
Ahora, cuando verifico este script, veo valores para los Límites de especificación en el cuadro de diálogo Información de columna.

Además, evaluando esta expresión
Column(dt, "pH") << Get Property("Spec Limits");
da como resultado la siguiente información escrita en el registro:
{LSL( 6 ), USL( 8 ), Target( 7 ), Show Limits( 1 )}
Finalmente, si creo un gráfico con la columna, veo las líneas de referencia de Spec Limit en las ubicaciones esperadas.

Escribir código JSL de forma dinámica es una habilidad útil que debe desarrollar un programador. Existen muchas circunstancias en las que JMP no evalúa un argumento en una expresión suficientes veces para llegar al valor real necesario. Si bien existen múltiples técnicas para escribir código JSL de forma dinámica, mi método preferido es el que llamo el método Eval(EvalExpr(Expr())). Permite la sustitución en línea y el formato semántico, lo que hace que la lectura y la depuración del código sean relativamente fáciles.