Tipos de dato
| Tipo | Sintaxis | Dónde | Descripción |
|---|---|---|---|
char | char(longitud) | @Fields, @Variables | Cadena de longitud fija. longitud requerida (1-32.766 en @Fields; 1-16.773.104 en @Variables). |
varchar | varchar(longitud) | sólo @Variables | Cadena de longitud variable. longitud requerida (1-16.773.100). Length(...) devuelve el contenido real en tiempo de ejecución, a diferencia de char. |
number | number(precisión, escala) | @Fields, @Variables | Numérico. precisión requerida (1-30 en @Fields; 1-63 en @Variables); escala opcional, default 0. |
date | date | @Fields, @Variables | Fecha, sin parámetros. En @Fields no puede llevar Default(...). |
time | time | @Fields, @Variables | Hora (hora/minuto/segundo), sin parámetros. En @Fields no puede llevar Default(...). |
timestamp | timestamp | @Fields, @Variables | Fecha y hora combinadas (con microsegundos), sin parámetros. En @Fields no puede llevar Default(...). |
field | field(NombreCampo) o field(Tabla.Campo) | sólo @Variables | Hereda el tipo de un campo de @Structure de alguna tabla referenciada. Ver field: heredar el tipo de un campo. |
list | list(tipo) | sólo @Variables | Lista dinámica de tipo (escalar, struct(Template) o field(...); no admite otro list ni matrix anidado, ver E00283). Sin tamaño en la declaración — la capacidad interna máxima es fija (9999 elementos) y no configurable. Se lee/escribe un elemento con &Variable[índice]; se agrega/quita/consulta con métodos (ver List: métodos). |
matrix | matrix(filas, cols, tipo) | sólo @Variables | Grilla 2D de tamaño fijo filas x cols de tipo. Se lee/escribe un elemento con &Variable[fila, col]. |
struct | struct(NombreTemplate) | sólo @Variables | Instancia de un template struct NombreTemplate [ ... ] definido inline en el ámbito global (ver Struct: templates y acceso a miembro). Se accede a un miembro con &Variable.Miembro. |
Las constantes (const Nombre tipo = valor) sólo admiten char, varchar y number; ver @Variables: Constantes.
Ejemplos
@Variables {
global {
Usuario char(10)
Destino varchar(200)
Saldo number(9,2)
FechaAlta date
HoraAlta time
FechaHoraAlta timestamp
Estado field(ADSTS50)
Lista1 list(number(5))
Tablero matrix(8, 8, char(1))
}
}
field: heredar el tipo de un campo
field(...) toma el tipo del campo indicado, buscándolo en las tablas declaradas en @References/Tables. Tiene dos formas:
field(Campo): busca el campo en todas las tablas referenciadas. Si existe en más de una, se reportaE00149(ambiguo): “El campo ‘{field}’ de la variable field(…) es ambiguo: existe en más de una tabla de @References/Tables; indique la tabla con field(Tabla.Campo).”field(Tabla.Campo): busca el campo sólo en esa tabla, para desambiguar. No distingue mayúsculas en la tabla ni en el campo. Si la tabla no está referenciada o el campo no existe en ella, se reportaE00148(campo no encontrado).
El tipo resultante es el del campo en ambas formas. Ambas valen en cualquier ámbito de @Variables y también como miembro de un struct.
// Las tablas Clientes y Proveedores (en @References/Tables) tienen un campo Codigo
@Variables {
global {
struct Contacto [
Codigo field(Clientes.Codigo)
]
CodCliente field(Clientes.Codigo)
CodProveedor field(Proveedores.Codigo)
Nombre field(Clientes.Nombre) // también válido si el campo no es ambiguo
}
}
Con field(Codigo) a secas, este ejemplo reportaría E00149.
Interoperabilidad char/varchar
char y varchar interoperan en asignaciones — la regla es sólo de longitud (el origen debe entrar en el destino), sin importar cuál de los dos es fijo o variable:
&VarcharDestino = &CharOrigen // válido si longitud(CharOrigen) <= longitud(VarcharDestino)
&CharDestino = &VarcharOrigen
List/Matrix: indexación
&Lista1[1] = 100
&Tablero[3, 5] = "X"
El índice es 1-based. List/Matrix sólo son válidos en @Variables, nunca en @Fields.
List: métodos
list no lleva tamaño en la declaración (list(tipo), sin parámetro de capacidad): la capacidad interna máxima es fija en 9999 elementos, definida por el compilador y no configurable desde el lenguaje. En vez de fijar el tamaño de antemano, se administra el contenido con métodos, con sintaxis de miembro (&Variable.Metodo(...)):
| Método | Uso | Descripción |
|---|---|---|
Add(valor) | sentencia | Agrega valor al final de la lista. valor debe ser compatible en tipo con el elemento de la lista (si el elemento es struct(Template), valor debe ser una &Variable de ese mismo template exacto). |
Clear() | sentencia | Vacía la lista: limpia los elementos en uso (blancos o ceros) y deja la cuenta en 0. |
Init() | sentencia | Deja todos los elementos de la lista (los 9999) en su valor vacío (blancos en char/varchar, ceros en number, valor inicial en date/time/timestamp, struct limpios) y la cuenta (Count()) en 0. No recibe argumentos (E00282) ni se usa como expresión (E00280). |
Remove(indice) | sentencia | Quita el elemento en la posición indice (1-based, tipo number), recorre los siguientes una posición hacia atrás y limpia el último espacio que queda libre. Un indice fuera de 1..Count() no hace nada. |
Split(texto[, separadores[, AllSep]]) | sentencia | Reemplaza el contenido de la lista (limpia lo anterior) con los trozos de texto. Ver Split(). |
Count() | expresión | Devuelve la cantidad actual de elementos (tipo number). Sólo se puede usar dentro de una expresión, nunca como sentencia suelta. |
Json() | expresión | Devuelve la lista como arreglo JSON (sólo list(struct(...))). Ver Json(). |
&Lista1.Add(10)
&Lista1.Add(20)
&Lista1.Add(30)
For &i = 1 To &Lista1.Count()
// ... &Lista1[&i] ...
EndFor
&Lista1.Remove(2)
&Lista1.Clear()
&Lista1.Init()
No existe un For Each sobre una lista en memoria — el recorrido se hace con el For clásico por contador (For &i = 1 To &Lista.Count()) más el indexado &Variable[&i] (For Each In sigue siendo exclusivo de tablas de base de datos, ver @Source: sentencias de control).
Borrado real. Clear(), Remove(indice) y JsonSplit (al reemplazar el contenido anterior) limpian de verdad las posiciones que dejan de usarse, no sólo ajustan el contador. Así se mantiene siempre esta invariante: todo elemento posterior al último está vacío (blancos o ceros). Un programa RPG que reciba el arreglo (ver @Parameters) puede leerlo hasta la primera línea vacía. Con 9999 elementos no queda ninguna posición vacía después del último.
Init() frente a Clear(). En RPG, Init() es un único clear del arreglo completo (más contador = 0), sin bucle. Clear() sólo limpia hasta el contador: es más rápido cuando se usa con pocas filas, pero deja intactos los elementos escritos por índice (&Lista[10] = x) sin pasar por Add(), porque esas escrituras no mueven el contador. Init() limpia toda la capacidad (con char(250) son unos 2,5 MB), por lo que conviene usarlo al inicio o cuando haga falta, no dentro de un bucle muy repetido.
El caso típico de Init() es usar una list como arreglo de tamaño fijo (&Trama[1], &Trama[10]) que luego se pasa a otro programa con Call:
&Trama.Init()
&Trama[1] = "Cabecera"
&Trama[10] = "Pie"
// Clear() no limpiaría &Trama[10]: se escribió por índice y Count() sigue en 0
&Trama.Init()
Ver el ejemplo completo en example/programs/PINIT01.warp.
Nota:
Clear(),Remove()yJsonSplitdejan vacío lo que queda después del último elemento.
Si Add(valor) se llama cuando la lista ya está en su capacidad máxima (9999 elementos), el programa emite un dsply visible con el mensaje Lista {nombre} alcanzó su capacidad máxima (9999) y no agrega el elemento — no aborta el programa completo.
list(struct(Template)) es válido (una lista de instancias de un mismo struct). Anidar list/matrix entre sí no lo es, en ninguna combinación: list(list(...)), list(matrix(...)), matrix(list(...)) y matrix(matrix(...)) reportan el error de compilación E00283 (“‘&{variable}’ es un {list/matrix} cuyo elemento no puede ser {list/matrix} (sin equivalente RPG generable): use un tipo escalar, struct(…) o field(…).”), detectado en el análisis semántico — no es posible declarar un arreglo cuyo elemento sea a su vez otro arreglo.
Split(): dividir un texto en una lista
&Lista.Split(texto[, separadores[, AllSep]]) es una sentencia (como Add/Clear; usada como expresión da E00280) y solo vale sobre list(char(n)) o list(varchar(n)) (E00363 si no).
- Reemplaza el contenido de la lista: limpia lo anterior y deja los trozos de
texto, hasta 9999. Al llenarse muestra «Lista X llena (max 9999)» condsplyy descarta el resto. Un trozo más largo que el elemento se recorta. - Sin
separadores, corta por blancos. - Cada carácter de
separadoreses un separador:"-;"separa por guion y por punto y coma. - Sin
AllSep, los separadores consecutivos, iniciales y finales se ignoran:"uno,dos,,tres"con","da 3 trozos. - Con
AllSep(tercer argumento, la palabraAllSep, que exige indicarseparadores), cada separador delimita dos trozos y aparecen los vacíos: el mismo texto da 4 trozos:uno,dos, `` ytres. - Un texto vacío da 0 trozos.
- Los blancos finales de un
charde origen se ignoran. Una variablecharde separadores se recorta: sus blancos finales no son separador (para un blanco como separador use un literal). textoyseparadoresdeben serchar/varchar(E00359); se admiten de 1 a 3 argumentos (E00358); el tercero debe ser la palabraAllSep(E00361).
&Partes.Split(&Texto, ",")
For &i = 1 To &Partes.Count()
// ... &Partes[&i] ...
EndFor
&Partes.Split("uno,dos,,tres", ",", AllSep) // 4 trozos, uno vacío
Requisito de release.
Splitgenerafor-each ... in %split(...). En IBM i 7.5 viene de base. En 7.3 y 7.4 hacen falta dos PTF de abril de 2021: el del compilador (5770WDS) y el del runtime (5770SS1), este último en cada sistema donde corra el programa.
Release PTF de compilador PTF de runtime 7.3 SI76100 SI76098 7.4 SI76101 (para TGTRLS V7R3M0: SI76109) SI76099 Sin el PTF de runtime el programa compila, pero falla al ejecutar con
MCH4437(export no encontrado). Es el mismo requisito que Upper y Lower.
AllSep(*ALLSEP) exige además 7.4 TR8 / 7.5 TR2 o sus PTF: 7.4, compilador SI83497 y runtime SI83471; 7.5, compilador SI83480 (para TGTRLS V7R4M0: SI83496) y runtime SI83468. Estos números provienen de un resumen de búsqueda: verifíquelos con IBM.
Json(): convertir un struct o una lista a JSON
&Variable.Json() devuelve el contenido de la variable como texto JSON (varchar). Se puede aplicar a un struct(...) (produce un objeto) o a una list(struct(...)) (produce un arreglo), incluidos los anidados por camino (&env.Json(), &env.Cab.Detalle.Json()). Se usa sólo como expresión, nunca como sentencia suelta (E00294), y no recibe argumentos (E00282):
&jsonObjeto = &unRegistro.Json()
&jsonArreglo = &listaRegistros.Json()
Para el template Registro [ codigo number(3,0), nombre char(20), monto number(7,2), fecha date ], los resultados tienen esta forma:
{"codigo":1,"nombre":"Ana","monto":1250.75,"fecha":"2026-10-16"}
[{"codigo":1,"nombre":"Ana",...},{"codigo":2,"nombre":"Luis",...}]
- Claves: el nombre del miembro tal como se declaró en el template, en el orden de declaración.
- Lista: el arreglo contiene sólo los elementos en uso (
Count()). char/varchar: cadena JSON entre comillas, con"y\escapados y los espacios finales recortados. Los caracteres de control no reciben tratamiento especial.number: número JSON, sin comillas.date: cadena"yyyy-mm-dd".- Anidados: un miembro
struct(...)genera un objeto y un miembrolist(struct(...))un arreglo, p.ej.{"Cab":{"epm":"a","Detalle":[{"Pgm":"P1","Libreria":"L1"}]},"Total":2}. - Los miembros escalares de un
structsólo pueden serchar/varchar/number/date/field; el generador también sabe emitirtime("hh:mm:ss") ytimestamp("yyyy-mm-ddThh:mm:ss.ffffff") por si el tipo de miembro se amplía.
Tamaño de la variable destino. Para un struct, la expresión tiene el tamaño del peor caso: por cada texto, 2 × largo + 2; por cada número, precisión + 2; por cada fecha, 12; más los nombres de clave, comillas, llaves y comas. Con structs anidados el peor caso crece con cada lista anidada (se calcula sobre sus 100 elementos). La variable que recibe el resultado debe poder contenerlo; si no, se reporta el error habitual de asignación incompatible (E00147). Declare el destino con holgura (p.ej. varchar(300) para un template pequeño). Para una list no se exige tamaño de destino, pero si el arreglo generado excede el máximo de un varchar de RPG (16 773 100 caracteres) el programa falla en ejecución, no trunca.
Errores: E00294 (usado como sentencia), E00295 (la variable no es struct ni list), E00296 (otro método sobre un struct; el único válido es Json), E00297 (list de tipos escalares: por ahora no soportado). Ver Diagnósticos.
No requiere librerías ni PTF en IBM i: cuando se usa .Json(), el compilador genera en el RPG los procedimientos de apoyo necesarios (Json_<Template> y JsonList_<Template>). Un ejemplo completo está en example/JSON01.warp.
Para partir el texto resultante en líneas (p.ej. para imprimirlo) ver JsonSplit.
Tramas de ancho fijo
Una trama de ancho fijo es una línea de texto donde cada miembro de un struct ocupa una cantidad fija de posiciones, en el orden de declaración, sin separadores. El ancho total es la suma de los anchos de los miembros.
| Forma | Uso | Descripción |
|---|---|---|
®.FixedWidth() | expresión | Devuelve la trama del struct: un char del ancho total. Usarlo como sentencia da E00306. |
®.FromFixedWidth(&texto) | sentencia | Llena el struct desde una trama (operación inversa). &texto es char/varchar o un literal. Usarlo como expresión da E00306. |
FixedWidthSplit(®istros, &lineas) | sentencia | Convierte una list(struct(...)) en una línea de trama por registro, dentro de una list(char)/list(varchar). Reemplaza el contenido de &lineas. |
FixedWidthParse(&lineas, ®istros) | sentencia | Operación inversa: lee cada línea de &lineas como un registro de ®istros. Reemplaza el contenido de ®istros. |
Formato por miembro:
| Tipo | Posiciones | Formato |
|---|---|---|
char(n) / varchar(n) | n | Alineado a la izquierda, relleno con blancos (se recorta si sobra). |
number(p,s) | p | Alineado a la derecha, con ceros a la izquierda y decimal implícito (sin punto). Un negativo lleva - en la primera posición, por lo que hay que dejar holgura de un dígito en p. |
date | 8 | YYYYMMDD. |
time | 6 | HHMMSS. |
timestamp | 20 | YYYYMMDDHHMMSSnnnnnn (con microsegundos). |
Al leer (FromFixedWidth, FixedWidthParse): una línea más corta que la trama se lee como si estuviera rellena con blancos; un número inválido da 0; una fecha inválida da la fecha mínima (0001-01-01).
FixedWidth() y FromFixedWidth() trabajan con UN struct; para una list use FixedWidthSplit / FixedWidthParse. Llamar a FixedWidth() sobre una list da E00305 con la sugerencia de usar FixedWidthSplit(&lista, &lineas).
FixedWidthSplit y FixedWidthParse aceptan también un camino a una list que es miembro de un struct, por ejemplo FixedWidthSplit(&pase.Items, &lineas) y FixedWidthParse(&lineas, &pase.Items). Una list miembro admite hasta 100 registros: FixedWidthParse se detiene al llenarse y emite el aviso FixedWidthParse: lista llena (max 100).
Sólo se admiten structs cuyos miembros sean char, varchar, number, date (o un field que resuelva a alguno de ellos). Un struct o list anidado, o una trama de más de 32766 posiciones, da E00305. Los elementos de la lista de líneas deben poder contener la trama completa (E00309).
Ejemplo con struct Cliente [codigo char(5) nombre varchar(12) saldo number(9,2) alta date]: la trama mide 34 posiciones (codigo 1-5, nombre 6-17, saldo 18-26, alta 27-34).
@Variables {
global {
struct Cliente [
codigo char(5)
nombre varchar(12)
saldo number(9,2)
alta date
]
c struct(Cliente)
otro struct(Cliente)
clientes list(struct(Cliente))
copia list(struct(Cliente))
lineas list(char(40))
trama char(40)
}
}
@Source {
&c.codigo = "A001"
&c.nombre = "Ana Perez"
&c.saldo = -1250.5
&c.alta = Today()
&trama = &c.FixedWidth()
&otro.FromFixedWidth(&trama)
&clientes.Add(&c)
&clientes.Add(&otro)
FixedWidthSplit(&clientes, &lineas)
FixedWidthParse(&lineas, &copia)
}
Un ejemplo completo está en example/FIXEDWIDTH01.warp. Errores: E00305 a E00309 (ver Diagnósticos).
Nota: los
numberse leen con decimal implícito y signo-en la primera posición; lasdateen formatoYYYYMMDD. Una trama más corta que el registro se lee como si tuviera blancos al final.
Struct: templates y acceso a miembro
Un template con nombre y miembros, definido inline dentro del ámbito global de @Variables:
@Variables {
global {
struct Person [
Id number(10, 0)
Nombre varchar(50)
Email varchar(100)
Edad number(3, 0)
]
personaGlobal struct(Person)
Nombre varchar(50)
}
ImprimirPersona {
persona struct(Person)
}
}
&personaGlobal.Nombre = "Su Nombre"
&Nombre = &personaGlobal.Nombre
Do ImprimirPersona(&personaGlobal)
-
Los miembros del template admiten
char/varchar/number/date/field(NombreCampo),struct(OtroTemplate)ylist(struct(OtroTemplate))(ver Structs anidados).timeytimestampno se admiten como miembro, nimatrixnilistde tipos escalares (E00237: “sólo se permiten char/varchar/number/date/field, struct(Template) y list(struct(Template)) (no se admite matrix ni list de tipos escalares)”). -
Se accede/asigna un miembro con
&Variable.Miembro(lectura y escritura). -
Se puede pasar como parámetro y devolver desde una
Procedure/Functionpropia — ver Procedure / Function. -
Un arreglo de
structse declara conlist(struct(NombreTemplate))— ver List: métodos. -
El indexado
&Lista[i]de unalist(struct(Template))es válido, pero sólo en dos formas exactas: como lectura, el valor completo de una asignación a otra&Variableque seastruct(...)del mismo template (&otraVariable = &Lista[i]); como escritura,&Lista[i] = &otraVariable(otra&Variablestruct(...)del mismo template, nunca una expresión o un literal). Si el lado de la asignación que debería ser la variable struct no es sintácticamente una&Variable, se reportaE00241; si el template no coincide exactamente con el de la lista, se reportaE00242. Los chequeos de índice (cantidad, tiponumber, rango 1..9999) aplican igual que para cualquier otralist:&otroRegistro = &Lista[1] &Lista[1] = &otroRegistro For &i = 1 To &Lista.Count() &actual = &Lista[&i] EndFor -
No soportado todavía:
structcomo parámetro de un programa externo (@Parameters/Call) — sólo como parámetro de unaProcedure/Functioninterna.
Structs anidados y listas dentro de un struct
Un miembro de un template puede ser a su vez struct(OtroTemplate) (struct anidado) o list(struct(OtroTemplate)) (lista de structs). El template referenciado puede estar declarado más abajo:
struct Detalle [
Pgm char(10)
Libreria char(10)
]
struct Cabecera [
epm char(10)
Estado char(10)
Detalle list(struct(Detalle))
]
struct Envio [
Cab struct(Cabecera)
Total number(9, 0)
]
&env struct(Envio)
&fila struct(Detalle)
El acceso es por camino, con tantos niveles como haga falta:
&env.Cab.epm = "x"
&x = &env.Cab.epm
&fila.Pgm = "PGM1"
&env.Cab.Detalle.Add(&fila)
&n = &env.Cab.Detalle.Count()
&fila = &env.Cab.Detalle[1]
&env.Cab.Detalle[2] = &fila
&env.Cab.Detalle.Remove(1)
&env.Cab.Detalle.Clear()
&texto = &env.Json()
&textoDet = &env.Cab.Detalle.Json()
- Capacidad: una
listque es miembro de unstructreserva 100 elementos (no los 9999 de unalistsuelta).Addsobre una lista llena muestra un mensaje y no agrega el elemento, igual que en lalistsuelta. Un índice literal mayor que 100 se reporta comoE00188. - Tamaño máximo: si la variable ocuparía más que el máximo de una variable RPG (16 773 104 bytes) se reporta
E00300(p.ej. unalist(struct)de 9999 elementos cuyo struct lleve una lista anidada grande). - Ciclos: un template que se contiene a sí mismo, directa o indirectamente, se reporta como
E00299. - Templates inexistentes:
struct(X)olist(struct(X))dentro de un miembro con unXno declarado se reporta comoE00238. - No admitido como miembro:
matrixylistde tipos escalares (E00237); tampocotimenitimestamp(E00237). - Procedures: se puede pasar un struct con anidados a una
Procedure; si la rutina modifica una lista anidada, el parámetro se pasa por referencia (noconst). - RPG generado: los templates se emiten en orden de dependencia; la lista miembro es un arreglo
dim(100)con un contador oculto como subcampo del mismo template (se copia junto con el struct), y las variables que contienen listas se inicializan coninz(*likeds). Json(): ver Json(); los anidados generan objetos y arreglos anidados.
Un ejemplo completo está en example/NSTJSON01.warp.