Method
Métodos são receitas que podem receber argumentos para "preencher as lacunas".
no FatScript, nos referimos a funções como Métodos, sem considerar o contexto de definição
Definição
Um método é definido anonimamente com uma seta fina ->
, assim:
<parâmetros> -> <receita>
Os parâmetros podem ser omitidos se nenhum for necessário:
-> <receita> # aridade zero
Para registrar um método no escopo, atribua-o a um identificador:
<identificador> = <parâmetros> -> <receita>
Parâmetros carregado para dentro do escopo de execução de um método são imutáveis, garantindo que as operações do método não alterem seu estado original. Para um comportamento mutável, considere passar um escopo ou utilizar um tipo personalizado capaz de encapsular múltiplos valores e estados.
Parâmetros opcionais
Enquanto assinaturas de métodos tipicamente requerem um número fixo de parâmetros obrigatórios, FatScript suporta parâmetros opcionais através de valores padrão:
greet = (nome: Texto = 'Mundo') -> {
'Olá, {nome}'
}
greet() # 'Olá, Mundo'
Neste exemplo, o parâmetro nome
é opcional, assumindo 'Mundo' como valor padrão se não for fornecido. Esta característica permite invocações de métodos mais flexíveis.
Argumento implícito
Uma conveniência oferecida pelo FatScript é a capcaidade de fazer referência a um valor passado para o método sem precisar especificar um nome a ele explicitamente. Neste caso, o argumento implícito é então representado pelo sublinhado _
.
Aqui está um exemplo que ilustra o uso do argumento implícito:
dobro = -> _ * 2
dobro(3) # saída: 6
Você pode usar um argumento implícito sempre que precisar realizar uma operação simples em um único parâmetro sem atribuir um nome específico a ele, mas note que o método deve ter aridade zero para ativá-lo.
Tratamento de argumentos
No FatScript, embora haja suporte de parâmetros opcionais e argumento implícito, quaisquer outros argumentos extras são simplesmente ignorados para melhorar a flexibilidade e o desempenho.
A decisão de design de ignorar argumentos extras também significa que não há suporte nativo para argumentos de comprimento variável no senso tradicional. Para obter funcionalidade semelhante, você pode declarar parâmetros opcionais tal como:
vaMethod = (v1 = null, v2 = null, v3 = null, v4 = null) -> ...
tenha em mente que você precisa listar explicitamente cada parâmetro que deseja capturar e definir um número muito grande de parâmetros (por exemplo, mais de 10) pode reduzir a performance das chamadas ao método
Auto-retorno
FatScript usa o auto-retorno, ou seja, o último valor é retornado automaticamente:
resposta: Method = (aGrandeQuestao) -> {
# TODO: explicar a vida, o universo e tudo mais
42
}
resposta('6 x 7 = ?') # retorna: 42
Segurança do tipo de retorno
Em FatScript, uma peculiaridade é que, mesmo quando você declara um método com um tipo de retorno específico, a linguagem permite valores null
, como em:
fn = (arg: Text): Text -> ... ? ... : null
Isso significa que, embora o método esteja declarado para retornar Text
, o valor de retorno é, de certo modo, opcional, pois o método também pode retornar Void
. A única garantia estrita é que, se o método tentar retornar um tipo incompatível, como Number
ou Boolean
, um TypeError
será levantado. Essa escolha de design introduz uma flexibilidade implícita, mantendo, ao mesmo tempo, um certo nível de segurança de tipos.
Se você precisa garantir um resultado não nulo, pode envolver sua chamada com Option assim:
Option(fn(myArg)).getOrElse('fallbackVal')
Procedimentos
O FatScript introduz um recurso único que simplifica as chamadas de métodos quando não envolvem argumentos.
O símbolo <>
declara um procedimento (Procedure), uma função sem argumentos que executa automaticamente quando referenciada:
<identificador> = <tipo> <> <receita>
para a sintaxe de procedimento, o
tipo
precisa ser uma única palavra; se você precisar de um tipo composto, declare-o como um alias de antemão e use o aliaspassar argumentos para um procedimento resultará em erro, pois procedimentos não aceitam argumentos
Principais vantagens:
Redução de código: Reduz a necessidade de parênteses, tornando o código mais limpo e conciso, para procedimentos sem parâmetros que agem como propriedades.
Computação dinâmica: Permite a computação dinâmica com saídas que podem mudar com base no estado interno do objeto ou no estado global.
Execução diferida: Habilita a execução diferida, útil em programação assíncrona e padrões de inicialização complexos.
a partir da versão
4.0.0
, somente procedimentos suportam a execução automática sem parênteses; métodos clássicos de aridade zero não são mais executados automaticamente e exigem parênteses()
para a execução
Evitando uma chamada automática
Para referenciar um procedimento sem acionar o recurso de chamada automática, você pode usar a sintaxe de obtenção:
foo('bar') # gera uma referência para foo.bar, sem chamá-lo
O FatScript também oferece as palavras-chave self
e root
para referenciar procedimentos nos níveis local e global, respectivamente:
self('meuProcedimentoLocal')
root('meuProcedimentoGlobal')
O operador til ~
também permite que você contorne o recurso de chamada automática, proporcionando flexibilidade no manuseio de procedimentos:
# Ambas as linhas abaixo buscam a referência do procedimento, sem chamá-lo
foo.~bar
~ meuProcedimento
Rótulos de argumento
O FatScript suporta rótulos de argumento, que permitem que você especifique nomes para argumentos no local da chamada. Esses rótulos melhoram a legibilidade do código e a autodocumentação ao tornar a intenção de cada argumento explícita:
# Definindo um método com parâmetros
fn = (a: Número, b: Número) -> a + b
# Chamando o método com rótulos de argumento
fn(a = 1, b = 2) # saída: 3, o mesmo que fn(1, 2)
Se fornecidos, os rótulos são validados em relação aos nomes de parâmetros do método. Os argumentos devem ser passados na mesma ordem definida na assinatura do método. Usar rótulos incorretos gerará um erro:
fn(b = 1, a = 2) # CallError: invalid name 'b' at pos: 1
argumentos são resolvidos sequencialmente, não pelos rótulos; portanto, resolução fora de ordem não é permitida, mesmo quando rótulos são usados
Contraste com a instanciação de tipo
Embora rótulos de argumento em chamadas de método sejam praticamente decorativos, eles desempenham um papel funcional na instanciação de tipo. Ao criar instâncias de tipos, rótulos de argumento são correspondidos por nome às propriedades do tipo, permitindo resolução fora de ordem.
Ao manter a resolução sequencial para métodos, o FatScript garante melhor desempenho em chamadas de método, enquanto a instanciação de tipo se beneficia da flexibilidade da resolução de argumento nomeado.
Otimização de Recursão de Cauda
O FatScript suporta Otimização de Recursão de Cauda (TRO, do inglês Tail Recursion Optimization) para melhorar o desempenho, conservando espaço na pilha. Para se beneficiar desta otimização, várias condições devem ser atendidas:
Parâmetros explícitos: Os métodos devem declarar explicitamente os parâmetros; a funcionalidade de argumento implícito não é suportada para TRO.
Controle de fluxo: TRO é compatível apenas com as construções
If-Else
,Cases
eSwitch
para ramificação.Estrutura de chamada: Chamadas de métodos aninhadas, como
x(a)(b)(c)
, não são suportadas para TRO.Chamadas recursivas: O método deve se chamar recursivamente pelo nome como a operação final em seu caminho de execução.
Por exemplo, uma função configurada corretamente para TRO pode parecer assim:
tailRec = (n: Number, m: Number): Void -> {
n > m => console.log('concluído')
_ => {
console.log(n)
tailRec(n + 1, m)
}
}
Neste exemplo, tailRec
se chama recursivamente como a operação final em um dos ramos, tornando-a elegível para otimização.
Você pode verificar se TRO foi ativada para o seu método usando análise estática com a opção fry --probe
.
A TRO pode ser desativada envolvendo a chamada recursiva entre parênteses, conforme mostrado abaixo:
...
(tailRec(n + 1, m)) # sem TRO