$ cat null-en-genero-lo-anula-todo-sfmt-no.md

i4GL

NULL en Genero: || lo anula todo, SFMT no

05 Nov 2026 · 5 min de lectura

El problema: una cadena que desaparece

Montas un texto juntando campos y, de vez en cuando, sale vacío entero. No le falta un trozo: no queda nada. Casi siempre es un NULL en uno de los operandos de ||.

La causa: NULL contagia toda la expresión

El manual lo dice en dos sitios:

  • En la página de NULL: si un elemento de una expresión es NULL, la expresión entera se evalúa como NULL.
  • En la del operador ||: si cualquiera de los miembros de una concatenación es NULL, la cadena resultante es NULL.

Hay una tercera regla que agrava la segunda: en Genero, el literal de cadena vacía "" equivale a NULL.

Las cuatro formas de juntar cadenas

MAIN
  DEFINE l_nombre, l_apellido, l_texto STRING

  LET l_nombre = "Ana"
  -- l_apellido se queda en NULL

  LET l_texto = l_nombre || " " || l_apellido
  DISPLAY "||     [", l_texto, "]"

  LET l_texto = l_nombre, " ", l_apellido
  DISPLAY "coma   [", l_texto, "]"

  LET l_texto = SFMT("%1 %2", l_nombre, l_apellido)
  DISPLAY "SFMT   [", l_texto, "]"

  LET l_texto = l_nombre.append(l_apellido)
  DISPLAY "append [", l_texto, "]"

  LET l_texto = NVL(l_apellido, "")
  DISPLAY "NVL(x, \"\") sigue siendo NULL: ", l_texto IS NULL
END MAIN
||     []
coma   [Ana ]
SFMT   [Ana ]
append [Ana]
NVL(x, "") sigue siendo NULL:      1
  • || pierde la cadena entera por un solo operando NULL.
  • La coma (LET a = b, c) y SFMT tratan el NULL como si no hubiera nada. Ask Reuben (#3) recomienda SFMT porque la plantilla completa se lee de un vistazo.
  • .append() tampoco devuelve NULL. No modifica la variable: devuelve una cadena nueva que hay que asignar. CALL l_nombre.append(...) no compila, da -6611.
  • NVL(x, "") no arregla nada, porque "" es NULL. Si se quiere un valor por defecto, tiene que ser uno que no esté vacío, por ejemplo NVL(x, "-").

Un caso real: la línea vacía que no llevaba CR

En el cliente SMTP de la entrada sobre enviar correo, cada línea se escribía con su CRLF así:

CALL ch.writeLine(p_texto || "\r")

Funcionaba en todas las líneas menos en la vacía. linea(ch, "") recibe NULL, NULL || "\r" da NULL, y writeLine escribe solo el salto de línea, sin el CR. Esa línea vacía era la que separa las cabeceras del cuerpo del mensaje. No se ve leyendo el código: apareció en un volcado de los bytes enviados. La solución fue tratar el NULL aparte y escribir "\r" directamente.

Otro caso real: un BOOLEAN que no entra en ningún IF

NULL no solo afecta a las cadenas. Una comparación con un operando NULL da NULL, y un BOOLEAN puede quedarse en NULL sin que se note:

MAIN
  DEFINE l_seguir BOOLEAN

  LET l_seguir = (arg_val(1) == "seguir")
  IF l_seguir THEN
    DISPLAY "rama IF"
  END IF
  IF NOT l_seguir THEN
    DISPLAY "rama IF NOT"
  END IF
  DISPLAY "l_seguir IS NULL: ", l_seguir IS NULL

  LET l_seguir = NVL(l_seguir, FALSE)
  IF NOT l_seguir THEN
    DISPLAY "rama IF NOT, tras NVL"
  END IF
END MAIN

Sin argumentos, arg_val(1) devuelve NULL:

l_seguir IS NULL:      1
rama IF NOT, tras NVL

No se imprime ni «rama IF» ni «rama IF NOT». NOT NULL sigue siendo NULL, y un IF con NULL no entra. Este caso salió al escribir el ejemplo de la entrada sobre WHENEVER: el programa tenía que pararse sin argumentos y seguía. Con NVL(l_seguir, FALSE), o con un LET l_seguir = FALSE y un IF que lo ponga a TRUE, el valor queda definido.

Comparar con NULL: IS NULL, nunca ==

x == NULL nunca es verdadero: da NULL. El manual pide usar IS NULL, y el compilador lo recuerda con -W all:

warning:(-6636) Invalid usage of NULL in an expression. Do you mean IS NULL?

Conclusión

En Genero, un NULL en cualquier operando anula toda la expresión, y "" también es NULL. Para concatenar, SFMT o la coma. Para valores por defecto, NVL con un valor que no esté vacío. Y para un BOOLEAN que viene de una comparación, darle un valor explícito antes de usarlo en un IF.

Fuentes

  • Manual Genero BDL 6.00: NULL (expresiones con NULL, "" equivale a NULL, IS NULL); operador || (Concatenate); ||=.
  • Ask Reuben #3, Append or Concatenate: https://4js.com/ask-reuben/ig-3/

Qué está comprobado y qué no

Que NULL anula la expresión, que "" equivale a NULL, el comportamiento de || y el uso de IS NULL están contrastados con el manual de Genero 6.00. Que la coma y SFMT no devuelven NULL viene de Ask Reuben #3; la página de SFMT del manual no lo menciona.

Compilado y ejecutado en Genero 5.01.04. Los listados se copiaron tal cual del texto de la entrada:

  • Las cuatro formas de concatenar y NVL(x, ""), con la salida de arriba.
  • El BOOLEAN a NULL: no entra en ninguna rama, y NVL(l_seguir, FALSE) lo arregla.
  • CALL l_nombre.append(...) no compila (-6611).
  • El aviso -6636 al comparar con == NULL.

El caso de la línea vacía se comprobó en un volcado de bytes del cliente SMTP de la entrada sobre correo.

0 comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *