Argumentos nomeados
Rotina(1, Nome := valor): pular parâmetros com valor padrão, qualquer ordem e escolha de sobrecarga pelos nomes.
O que é e por que existe#
Uma rotina com vários parâmetros de valor padrão obriga a repetir os padrões intermediários só para informar o último: Connect('x', 80, 5) para mudar apenas o timeout. Com argumento nomeado você escreve só o que importa, e a chamada se lê sozinha:
function Connect(const AHost: UString; APort: Int32 = 80; ATimeout: Int32 = 30;
AVerbose: Bool8 = False): UString;
Connect('a.com'); // tudo padrão
Connect('c.com', ATimeout := 5); // pula APort, que tem padrão
Connect('d.com', AVerbose := True, APort := 443); // qualquer ordem
Connect(ATimeout := 2, AHost := 'e.com'); // até o primeiro pode ser nomeadoA sintaxe usa := (e não :) para não colidir com o formato do Write(X:5). Nome := só é reconhecido dentro dos parênteses de uma chamada, e só quando o identificador é seguido de :=.
Regras#
- Posicionais primeiro, depois os nomeados, em qualquer ordem.
- O nome é de um parâmetro formal da rotina (as maiúsculas contam).
- O parâmetro omitido usa o valor padrão declarado; agora ele pode estar no meio da lista, desde que todo omitido tenha padrão.
- Ordem de avaliação = ordem escrita.
Subtract(ASubtrahend := Trace('subtraendo', 3), AMinuend := Trace('minuendo', 10))avalia primeiro o subtraendo, mesmo que o minuendo venha antes no cabeçalho. - Sobrecarga: os nomes (e os tipos dos valores) escolhem a versão:
Area(AWidth := 3, AHeight := 4)eArea(ARadius := 2). - Vale em funções, procedimentos, métodos (virtuais e de interface), construtores (
TFoo.Create(Nome := …),inherited Create(…)) e ponteiros de rotina (os nomes são os do tipo procedural).var,out,const, vetor aberto e a lambda curta funcionam nomeados;var/outcontinuam exigindo uma variável.
program ArgumentosNomeados;
// Demo 11 - Argumentos nomeados: Rotina(1, Nome := valor).
// Útil quando há vários parâmetros com valor padrão e você quer informar só alguns.
function Connect(const AHost: UString; APort: Int32 = 80; ATimeout: Int32 = 30; AVerbose: Bool8 = False): UString;
begin
Result := AHost + ':' + IntToUStr(APort) + ' timeout=' + IntToUStr(ATimeout);
if AVerbose then
Result := Result + ' (detalhado)';
end function;
// Sobrecarga: os NOMES usados também ajudam a escolher a versão.
function Area(AWidth, AHeight: Int32): Int32; overload;
begin
Result := AWidth * AHeight;
end function;
function Area(ARadius: Int32): Int32; overload;
begin
Result := 3 * ARadius * ARadius; // pi aproximado por 3, só para o exemplo
end function;
// Para provar a ORDEM de avaliação: os argumentos são calculados na ordem em que foram ESCRITOS.
function Trace(const ALabel: UString; AValue: Int32): Int32;
begin
WriteLn(' avaliando ', ALabel);
Result := AValue;
end function;
function Subtract(AMinuend, ASubtrahend: Int32): Int32;
begin
Result := AMinuend - ASubtrahend;
end function;
begin
// Sem nomes: só dá para omitir o final da lista.
WriteLn(Connect('a.com'));
WriteLn(Connect('b.com', 8080));
// Com nome: dá para pular o parâmetro do meio (APort usa o padrão).
WriteLn(Connect('c.com', ATimeout := 5));
// Qualquer ordem, depois dos posicionais.
WriteLn(Connect('d.com', AVerbose := True, APort := 443));
// Até o primeiro parâmetro pode ser nomeado.
WriteLn(Connect(ATimeout := 2, AHost := 'e.com'));
// Sobrecarga escolhida pelos nomes.
WriteLn('Área do retângulo: ', Area(AWidth := 3, AHeight := 4));
WriteLn('Área do círculo: ', Area(ARadius := 2));
// Ordem de avaliação = ordem escrita, mesmo trocando a ordem do cabeçalho.
WriteLn('Subtract:');
WriteLn(' resultado = ', Subtract(ASubtrahend := Trace('subtraendo', 3), AMinuend := Trace('minuendo', 10)));
end.a.com:80 timeout=30
b.com:8080 timeout=30
c.com:80 timeout=5
d.com:443 timeout=30 (detalhado)
e.com:80 timeout=2
Área do retângulo: 12
Área do círculo: 12
Subtract:
avaliando subtraendo
avaliando minuendo
resultado = 7Demo 11. Pular o parâmetro do meio, qualquer ordem, sobrecarga pelos nomes e a prova da ordem de avaliação.
Erros típicos#
Cada um desses saiu do compilador de verdade (com --diag-codes):
| Código | Situação | Mensagem (resumo) |
|---|---|---|
FE2420 | posicional depois de nomeado | escreva primeiro os posicionais e depois os Nome := valor |
FE2421 | nome que não é parâmetro | "Conn" não tem parâmetro chamado "ATime" |
FE2422 | mesmo nome duas vezes | o parâmetro "APort" foi nomeado mais de uma vez |
FE2423 | nome de parâmetro que já recebeu argumento posicional | |
FE2424 | omitido sem valor padrão | falta o argumento do parâmetro "AA": sem valor padrão, não pode ser omitido |
FE2425 | posicionais demais | |
FE2426 / FE2427 | nenhuma sobrecarga serve / empate | |
FE2428 | método genérico sem <T> explícito | escreva Obj.Maior<Int32>(B := 2, A := 1) |
Limites#
Construção nomeada de record (TP(A := 1, B := 'x')) não existe (record não tem forma de construtor); nomeados em chamadas geradas pelo compilador e no bytecode/VM também não. O fc fmt espaça Nome := valor como qualquer :=, e a dica de parâmetros do servidor de linguagem marca o parâmetro do nome.
Veja também#
- Rotinas, Fatias e concatenação.
- Demos
11-argumentos-nomeadose55-conforto; manualnamed-args.md.