Skip to content

Functional Programming ​

NeoObjectPascal incorporates ideas from functional programming so you can write code that is more concise, expressive, and easier to maintain. The central feature is the pipe operator |>, which chains transformations in a readable, left-to-right way.

The pipe operator |> ​

The |> operator passes the value on the left as the first argument of the function on the right. In other words, value |> func is equivalent to func(value):

npas
function dobrar(n: Integer): Integer
begin
    return n * 2;
end;

begin
    WriteLn(dobrar(5));      // chamada tradicional
    WriteLn(5 |> dobrar);    // com pipe — mesmo resultado
end.
Saída
 10 10 

Both styles produce the same result. The advantage of the pipe becomes clear when you chain several transformations.

Chaining functions ​

Because the pipe hands the result of one function as the input to the next, you can build a sequence of steps without nesting calls:

npas
function dobrar(n: Integer): Integer
begin
    return n * 2;
end;

function incrementar(n: Integer): Integer
begin
    return n + 1;
end;

function aoQuadrado(n: Integer): Integer
begin
    return n * n;
end;

begin
    // Leia da esquerda para a direita: 10 → 20 → 21 → 441
    WriteLn(10 |> dobrar |> incrementar |> aoQuadrado);
end.
Saída
 441 

Compare this with the nested form aoQuadrado(incrementar(dobrar(10))). The pipe removes the parentheses and makes the order of operations immediately visible.

Read it like a sentence

A chain built with |> reads in the order the steps happen. It is like a data "conveyor belt": each function receives the result of the previous one.

Small, composable functions ​

The pipe favors a style in which you build small functions with a single responsibility and combine them. Each function stays simple, testable, and reusable:

npas
function limpar(texto: String): String
begin
    // Remove um prefixo de espaço e normaliza
    return "[" + texto + "]";
end;

function emMaiusculas(texto: String): String
begin
    return java:(texto) {
        return ((String)param0).toUpperCase();
    };
end;

begin
    WriteLn("relatorio" |> emMaiusculas |> limpar);
end.
Saída
 [RELATORIO] 

Notice that emMaiusculas delegates the heavy lifting to a Java block. You can freely mix NeoObjectPascal functions and java:(...) { ... } blocks within a pipeline. See the details in Java Integration.

Combining pipe with arithmetic ​

The pipe has low precedence, so arithmetic expressions to its left are evaluated before being piped:

npas
function descrever(n: Integer): String
begin
    if n > 100 then
        return "grande"
    else
        return "pequeno";
end;

begin
    WriteLn(20 * 3 |> descrever);   // (20 * 3) = 60 → "pequeno"
    WriteLn(50 * 3 |> descrever);   // (50 * 3) = 150 → "grande"
end.
Saída
 pequeno grande 

Precedence

The |> sits just above the unary operators in the precedence table. See Operators for the full table, and use parentheses whenever you want to make the intent explicit.

Best practices ​

  • Prefer pure functions (no side effects) in your pipelines: given the same argument, they always return the same result.
  • Use names that describe the transformation (dobrar, emMaiusculas, descrever), not the step (passo1).
  • Keep each function short. If a step grows too large, break it into smaller functions and link them with |>.

These small functions are also easy to cover with the native testing framework — see Unit Testing.


Next, learn how to turn structured text into objects in Data Handling (JSON and CSV).