Fenner
A linguagem

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:

Fenner
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 nomeado

A 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) e Area(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/out continuam exigindo uma variável.
rc-named-args.fxp
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.
Saída
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 = 7

Demo 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ódigoSituaçãoMensagem (resumo)
FE2420posicional depois de nomeadoescreva primeiro os posicionais e depois os Nome := valor
FE2421nome que não é parâmetro"Conn" não tem parâmetro chamado "ATime"
FE2422mesmo nome duas vezeso parâmetro "APort" foi nomeado mais de uma vez
FE2423nome de parâmetro que já recebeu argumento posicional
FE2424omitido sem valor padrãofalta o argumento do parâmetro "AA": sem valor padrão, não pode ser omitido
FE2425posicionais demais
FE2426 / FE2427nenhuma sobrecarga serve / empate
FE2428método genérico sem <T> explícitoescreva 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#