Erlang ( ) é uma linguagem de programação de propósito geral, de alto nível, funcional e concorrente. Seu sistema de tempo de execução (runtime) é especificamente arquitetado para o desenvolvimento de sistemas escaláveis, distribuídos, tolerantes a falhas, de tempo real suave, de alta disponibilidade e uptime. Erlang é compilada para bytecode e interpretada pela máquina virtual BEAM, executada junto ao Erlang Run-Time System (ERTS) — responsável por interfacear o código com o sistema operacional, providenciando gerenciamento dinâmico de memória através de um coletor de lixo, entrada e saída de dados, escalonamento de processos, comunicação em rede, integração com sistema de arquivos, dentre demais recursos. Seu runtime suporta ainda hot swapping — alteração do código da aplicação sob execução de forma ininterrupta — para conveniência em ambientes de alta disponibilidade e tempo real, onde elevado uptime se faz necessário.

Erlang é uma linguagem de programação funcional, de tipagem dinâmica e forte, com dados imutáveis, funções de primeira classe, funções de alta ordem e suporte a casamento de padrões (pattern matching). A imutabilidade de dados possibilita que estados de execução do programa sejam revertidos em casos de falhas e previne a ocorrência de condições de corrida e deadlocks em contextos de concorrência, bem como fornecem maior integridade e facilidade na paralelização de operações computacionais ao eliminar a necessidade da presença de mecanismos de sincronização de estado compartilhado e exclusão mútua como locks ou semáforos.

Uma aplicação Erlang é tipicamente composta por dezenas, centenas ou milhares de processos leves (light-weight processes) — unidades de computação multitarefa executadas pela máquina virtual e gerenciadas pelo runtime. Diferentemente dos habituais processos ou threads do sistema operacional, os processos leves presentes em Erlang são arquitetados para serem facilmente e rapidamente criados, inicializados, reinicializados ou finalizados; são executados de forma isolada dos demais processos existentes; alocam por padrão pouca quantidade de memória e são escalonados para execução de forma automática pelo runtime. Processos comunicam-se entre si de forma assíncrona através de troca de mensagens, que em Erlang são denominadas sinais (signals). Processos podem ainda ser gerenciados por um processo supervisor, responsável por monitorá-los e reinicializá-los em caso de falhas ou conforme outras políticas de execução. Supervisores podem ser monitorados por outros supervisores de forma hierarquizada, formando dessa forma árvores de supervisão que conferem maior robustez e resiliência para a execução da aplicação. A plataforma OTP fornece ainda supervisores capazes de monitorar uso de recursos como CPU, armazenamento em massa e memória de processos filhos.

Erlang/OTP (Open Telecom Plataform), escrita na linguagem de programação C, é a principal implementação de facto da linguagem e do runtime da linguagem Erlang, cuja concepção e desenvolvimento iniciou-se em 1986 no Computer Science Laboratory da multinacional sueca Ericsson através de uma equipe formada pelos engenheiros e cientistas da computação Joe Armstrong, Robert Virding, e Mike Williams. Inicialmente desenvolvida de forma fechada e proprietária por mais de uma década, a plataforma Erlang/OTP foi publicada em dezembro de 1998 como software livre e de código aberto. Dentre outras implementações de código aberto da máquina virtual e do runtime Erlang, destacam-se ainda a AtomVM, escrita em C para microcontroladores e demais dispositivos embarcados, bem como a Firefly — escrita em Rust para WebAssembly.

Sistemas e aplicações escritas em Erlang tem sido extensivamente utilizadas em produção em inúmeras áreas há mais de três décadas. Erlang/OTP é uma peça fundamental na infraestrutura de telecomunicações GPRS, 3G, 4G e 5G da Ericsson, sendo também a linguagem na qual é escrito o back end da rede social e plataforma de mensagens instantâneas WhatsApp, o agente de mensagens de código aberto RabbitMQ, o banco de dados NoSQL distribuído de código aberto Apache CouchDB, a plataforma de trading de fundos de cobertura do banco de investimentos e serviços financeiros multinacional americano Goldman Sachs, o serviço de notificações push que oferece suporte a operação online do console de jogos eletrônicos Nintendo Switch, bem como os sistemas do Serviço Nacional de Saúde (National Health Service - NHS) do Reino Unido — são alguns exemplos notáveis de seu emprego na indústria.

História

Antecedentes O desenvolvimento de Erlang foi precedido pelas pesquisas relacionadas a questões de escalabilidade, concorrência e tolerância a falhas presentes em sistemas de telecomunicações — especialmente em centrais de comutação de circuitos de telefonia — durante as décadas de 1970 e 1980, e se originou nas instalações de pesquisa da companhia Ellemtel, na Suécia. A Ellemtel era uma empresa estabelecida em maio de 1970 como Ellemtel Utvecklings AB e de propriedade conjunta (uma joint venture) da Ericsson e da Televerket — essa última a empresa estatal sueca de telecomunicações. No início da década de 1970, a Ellemtel avançava em trabalhos de pesquisa e desenvolvimento uma SPCs (Stored Program Control) — centrais telefônicas controladas por computadores e circuitos digitais. miniaturadaimagem|Uma central telefônica Ericsson AXE. O domínio de problemas de escalabilidade, concorrência e tolerância a falhas presentes em centrais de comutação de circuitos de telefonia motivaram o desenvolvimento da linguagem PLEX e influenciaram diretamente a concepção de Erlang. Centrais telefônicas são compostas por vários dispositivos denominados switches (comutadores) individuais, que usualmente lidam com dezenas a centenas de milhares de chamadas telefônicas simultâneas. O sistema de comutação deve ser capaz de escalar para suportar uma grande quantidade de chamadas, bem como tolerar a falha de switches individuais, garantindo que as chamadas prossigam de forma ininterrupta para os usuários. Usualmente, em uma SPC, o software realiza o controle de execução das chamadas telefônicas, enquanto que o hardware atua como responsável pela transmissão de dados e sinais. De forma geral, na perspectiva do software que realiza o controle de chamadas, uma chamada telefônica é uma máquina de estados finito que altera seu estado em resposta a mensagens de um protocolo de comunicação. O sistema necessita lidar com uma grande coleção dessas máquinas ou processos simultâneos aguardando por um evento disparado pela recepção de uma mensagem ou outros tipos de sinais. Ao receber um evento, o processo realiza uma pequena quantidade de computação, altera seu estado, possivelmente envia mensagens para outros processos e então entra em espera pelo próximo evento. Processos devem ser vistos individualmente pelo sistema de forma isolada, de forma com que erros em um processo devido a uma falha de software ou hardware não ocasionem na parada total do sistema, prejudicando os demais processos. Em todo caso, a quantidade de computação executa é tipicamente menor que em sistemas de propósito geral, com trocas de mensagens, alteração de estados/contextos e decodificação de mensagens de rede desempenhando papeis mais relevantes.

Através dos esforços de pesquisa e desenvolvimento da Ellemtel, em 1976 surgiu a Ericsson AXE-10, uma central telefônica digital para comutação de circuitos. A AXE era programada em PLEX (Programming Language for EXchanges), uma linguagem de programação pseudo concorrente, assíncrona, orientadas a eventos e de tempo real desenvolvida por Göran Heimdahl na Ericsson para operar sistemas de comutação de circuitos telefônicos. PLEX é uma linguagem de domínio específico, de alto nível, desenvolvida especificamente para controlar centrais telefônicas, carecendo de construções comuns de linguagens de propósito geral como estruturas de repetição, suporte para valores numéricos negativos ou números reais. Em vez disso, PLEX dispõe de um paradigma orientado a eventos (como quando um usuário retira o telefone de seu suporte para fazer a discagem de um número) que, codificados como sinais, ativavam a execução de rotinas de código — e somente eventos permitiam a execução de código. PLEX dispõe ainda de jobs, unidades de execução de código pseudo concorrentes implementadas em hardware na AXE que podem ser escalonadas para execução periódica ou em um momento posterior. Embora aparentemente paralelos para o programador, Jobs não são executados de forma genuinamente concorrente; em vez disso, uma vez ativados por uma rotina (que prossegue normalmente com sua execução), jobs são movidos para uma fila (queue) e são executados em ordem de entrada — e não de forma paralela (concorrente).

Estima-se que o emprego de PLEX tornou o processo de programação do sistema da AXE três vezes mais rápido comparado ao emprego de linguagem de máquina, bem como reduziu o custo total do projeto em 20 a 30%. O sistema contava com cerca de cinco milhões de linhas de código escritas em PLEX e era designada para manter um downtime de até três minutos anualmente. A AXE tornou-se um dos principais produtos de sucesso da Ericsson durante as décadas de 1980 e 1990, sendo amplamente empregado na indústria de telecomunicações em todos os continentes. Entretanto, a linguagem PLEX estava intimamente acoplada ao hardware da AXE, o que significada que ela não poderia ser portada para outros sistemas e aplicações.

Concepção Por volta de 1985, funcionários do Computer Science Laboratory (CSLab) — estabelecido no ano anterior na Ericsson — estavam desenvolvendo estudos e experimentos para determinar as características desejáveis em uma linguagem de programação para programar sistemas de telecomunicações. Algumas linguagens disponíveis na época foram selecionadas para análise, dentre elas Concurrent Euclid, CHILL e Ada (imperativas), PFL e Prolog (declarativas), OPS4 (baseada em regras), Frames e CLU (orientadas a objetos). Tendo a disposição no laboratório uma central telefônica PABX Ericsson MD110 conectada a uma rede de workstations executando Unix, a equipe escreveu diversos programas experimentais para lidar com POTS (Plain Old Telephone Service) com as linguagens selecionadas. Eventualmente a equipe de trabalho chegou a conclusão que os programas para operar com POTS eram significativamente mais sucintos e fáceis de serem lidos quando escritos em linguagens declarativas em comparação com aqueles escritos em linguagens imperativas; todavia, as linguagens declarativas analisadas careciam de recursos para concorrência e os mecanismos de tratamento de erros disponíveis eram demasiadamente simples. Além disso, os seguintes requisitos foram estabelecidos como desejáveis para programação de sistemas de telecomunicações:

Concorrência massiva e granular: assim como jobs em PLEX, processes em CHILL e tasks em Ada, uma linguagem destinada a sistemas de telecomunicações deveria possuir de forma explícita (embutida em si mesma) um conceito de unidade de execução concorrente ("processos"), sem depender de abstrações de baixo nível oferecidas pelo sistema operacional (como threads em C). Idealmente, processos deveriam ser executados de forma isolada uns dos outros e interagirem somente através de troca de mensagens.Joe Armstrong, "History of Erlang", em HOPL III: Proceedings of the third ACM SIGPLAN conference on History of programming languages, 2007, ISBN 978-1-59593-766-X A granularidade permitiria adequar a concorrência a partes menores do sistema, oferecendo maior escalabilidade com menor uso de recursos. Trocas assíncronas de mensagens: os processos deveriam ser capazes de trocar mensagens e informações entre si através de operações assíncronas. Esse conceito contraria a ideia de manter recursos e estados compartilhados (como a passagem de ponteiros de memória). Devido ao isolamento, processos deveriam operar somente com os recursos que lhes foram explicitamente delegados.