Method
Métodos são receitas que podem receber argumentos para "preencher as lacunas em branco".
no FatScript, nos referimos a todas as funções como Métodos, independentemente do contexto de sua 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 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.
Tratamento de argumentos
Chamadas de métodos em FatScript são projetadas para aceitar o fornecimento de mais argumentos do que o requerido; argumentos extras são simplesmente ignorados. Este comportamento faz parte do design da linguagem para aumentar a flexibilidade e desempenho.
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')
Chamadas automáticas
O FatScript introduz um recurso único que simplifica as chamadas de métodos quando não envolvem argumentos. Esse recurso é conhecido como "truque de chamada automática" e oferece várias vantagens principais:
Redução de Código Desnecessário: Reduz a necessidade de parênteses, tornando o código mais limpo e conciso, para métodos sem parâmetros que agem como propriedades ou procedimentos.
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.
Implementação antiga (descontinuado)
No FatScript, um método definido sem parâmetros é executado "automágicamente" quando referenciado:
foo = {
bar = -> 'Olá!'
}
# Ambas as linhas abaixo produzem 'Olá!'
foo.bar() # chamada explícita
foo.bar # chamada automática
Procedimentos (novidade)
A partir da versão
3.4.0
O símbolo <>
declara explicitamente um método como um procedimento, uma função sem argumentos que executa automaticamente quando referenciada.
meth = (): Text -> 'yo' // sintaxe clássica de método
proc = Text <> 'yo' // nova sintaxe de procedimento
A partir da versão
4.0.0
Métodos clássicos não serão mais executados automaticamente e exigirão parênteses ()
para a execução. Somente procedimentos suportarão a execução automática sem parênteses. Passar argumentos para um procedimento resultará em erro, pois procedimentos não aceitam argumentos.
Esta é uma mudança profunda, mas que pretende tornar o código mais seguro e facilitar a distinção, ao mesmo tempo em que reduz a confusão causada por passagem de métodos como argumentos.
Referenciando
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')
Evitando uma chamada automática
O operador til ~
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
Ou você pode simplesmente encapsular a chamada do procedimento em outro procedimento:
<> foo.bar
Aviso: passando métodos como argumentos
Há uma exceção importante com relação a passagem de métodos como argumentos, especificamente quando se trata de um método local:
outro(bar) # passa `bar` como uma referência, sem executá-lo
no entanto, isso não se aplica com encadeamento:
outro(foo.bar)
passa o resultado debar
, e não a referência
Para passar o valor resultante do método local bar
, uma chamada explícita tem que ser feita:
outro(bar())
este comportamento pode parecer contra-intuitivo, mas é extremamente útil em diversos casos de uso, como, por exemplo, ao passar métodos para reduce, para uma tarefa assíncrona, para uma operação de mapeamento etc.
Argumento implícito
Uma conveniência oferecida pelo FatScript é a possibilidade 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.
Otimização de Recursão de Cauda
a partir da versão
3.2.0
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