Novas syntaxes, novas linguagens 

Jun/17
28

Ha quase 2 anos que n√£o publico um post … √© t√° complicado arranjar um tempo, e um assunto. Faz ¬†tempo que tenho vindo a usar qualquer momento livre para dedicar ao estudo de compiladores e linguagens de programa√ß√£o.

Tudo come√ßou com a cria√ß√£o de um compilador. Foi interessante estudar este assunto apenas com os poucos recursos da internet. Comprei dois livros sobre o assunto ( sim, li o livro do drag√£o), mas s√£o muito pouco √ļteis para iniciantes. Depois que voc√™ sabe, ai faz sentido, mas ai √© tarde demais porque voc√™ j√° sabe o que o livro tenta ensinar. Al√©m disso eu n√£o queria um compilador qualquer. N√£o queria mais um YACC.¬†Queria algo em java em que a sintaxe fosse program√°vel o o resto viesse pronto.¬†Isto deu nascimento ao compilelittle. √Č um compilador bottom-up capaz de compilar bastantes tipos de sintaxe e auto-resolver conflitos. Porque √© gen√©rico talvez n√£o seja op√ß√£o para algo que precise de performance, mas tem a vantagem de fazer parse de sintaxes que outros compiladores mais r√°pidos n√£o fazem. As escolhas envolvidas no compilelittle tentaram seguir o state-of-the-art o mais pr√≥ximo possivel. Li v√°rios papers e livros sobre o assunto que sim ajudaram a entender mas o que ajudou mesmo foram as palestras deste senhor .

Com o compilador mais ou menos pronto queria p√ī-lo √† prova. Tanto em termos do que ele √© capaz de parsear, mas tamb√©m na extensibilidade e configurabilidade do framework. Afinal, a ideia √© que as pessoas incluam o compilelittle nos seus pr√≥prios projetos. Para isto precisa criar uma linguagem um pouco mais complexa. Esta linguagem √© a linguagem lense
Criar a minha linguagem √© uma experiencia bem divertida para mim embora alguns dias seja frustrante porque o esfor√ßo √© imenso. N√£o porque √© dif√≠cil, mas porque tenho pouqu√≠ssimo tempo para mexer com isso. Mas criar uma linguagem n√£o √© bem sobre criar um compilador. √Č sobre criar regras, estilos : design. Desenhar uma linguagem √© ainda mais interessante que criar o compilador dessa linguagem. Como voc√™ cria uma linguagem ?

Uma forma de fazer é simplesmente inventar uma linguagem e pronto. Esta forma de fazer é historicamente mais utilizada quando ha um problema a resolver. Esta forma tenta resolver um problema especifico. A outra forma de fazer é estabelecer princípios e derivar a linguagem deles. Como físico, obviamente, esta segunda forma me interessa mais. Por outro lado, vivemos uma época áurea para as linguagens de programação. Não ha como escapar da influencia de tantas linguagens por ai, como por exemplo: Java 8 , C# 7, Swift 3, Scala, Julia, Python, Javascript, TypeScript 2, Ceylon, Kotlin, Gosu e Fantom.

A primeira parte obvia √© que a linguagem deveria correr dentro de uma JVM e ser fortemente tipada. J√° foi provado que VM, e em especial a JVM s√£o capazes de performance igual ao superior a programas compilados estaticamente. A performance da JVM cresce a cada nova vers√£o e √© a VM mais avan√ßado do mercado. N√£o √© por acaso que a maior parte das linguagens modernas rodam na JVM. Por outro lado, mesmo as linguagens estaticamente compiladas como Julia ou Swift j√° fazem uso de um tipo de compila√ß√£o em duas fases usando a LLVM ( pese embora o nome n√£o √© bem um VM, mas um standard de compila√ß√£o est√°tica que suporta objectos). A segunda parte obvia para mim √© que n√£o basta rodar na JVM, tem que rodar dentro do browser. A forma mais simples hoje em dia √© compilar para javascript como fazem tantas outras linguagens como TypeScript , Kotlin, Ceylon e Fantom. Chega de projetos esquizofr√™nicos que falam v√°rias l√≠nguas. Na real, na pr√°tica, isso pode ser interessante para provas de conceito ou alavancas de start-ups que jogam o c√≥digo fora sempre que ha dinheiro novo. Eu acho que √© uma fal√°cia que desenvolvimento r√°pido significa desenvolvimento descart√°vel e mal feito. Claro que voc√™ pode criar sua start-up com javascript e node.js. O ponto √© que n√£o √© a escolha mais correta do ponto de vista econ√īmico a longo prazo. √Č necess√°ria uma tecnologia que possa produzir diferentes artefatos a partir do mesmo c√≥digo; o que nos leva ao Android. Hoje √© preciso compilar para .class para usar a tecnologia android, embora Android n√£o rode java. Os .class s√£o convertidos para .dex e transformados em aplica√ß√Ķes. Linguagens como Kotlin j√° provaram que ha vantagens em ter uma s√≥ base de c√≥digo, uma s√≥ linguagem, para manipular diferentes APIs em diferentes ambientes. √Č este tipo de linguagem que me interessa investigar. Uma linguagem OO, fortemente tipada, coesa que permite ter uma s√≥ base de c√≥digo em v√°rias plataformas. As plataformas principais s√£o Java e Javascript, mas se bem feito, n√£o seria dif√≠cil estender para .NET e Android e qui√ßa at√© iOS usando a LLVM tamb√©m.

Porqu√™ uma linguagem com tipagem forte ? Porque tipos tornam a linguagem mais segura e mais coesa. Ou seja, o uso de tipos significa menos bugs, menos testes e mesmos surpresas. Como as pessoas pensam em tipagem forte pensam em Java onde √© preciso declara os tipos a todo o momento. O que as novas linguagens mostram √© que, porque o c√≥digo √© sempre fortemente tipado, o compilador pode inferir os tipos a maior parte das vezes. Na realidade ningu√©m quer que o compilador infira o tipo de uma propriedade ou dos par√Ęmetros de um m√©todo. O que se quer √© que dados esses tipos ele infira todos os outros tipos dentro dos m√©todos. Infer√™ncia de tipos torna o c√≥digo mais simples de escrever, e muitas vezes acaba sendo o c√≥digo que escreveria em linguagens n√£o tipadas, mas sem abdicar da ajuda imensa que o compilador nos d√° durante a verifica√ß√£o de tipos. Porque os tipos s√£o inferidos durante a declara√ß√£o de vari√°veis o tipo deve ser optional e isto nos leva a ter que decidir a sintaxe de forma a que seja natural p√īr ou n√£o o tipo. Por isso que em lense os tipos v√™m depois do nome da vari√°vel, para que possam removidos quando a inferencia est√° sendo usada.

Outra coisa que queria ter na linguagem √© um conjunto coerente de tipos num√©ricos. Isto tem mais que ver com o design de API, mas tem que haver suporte da linguagem em alguns pontos. Durante o projeto MiddleHeaven √© que o tamanho de uma cola√ß√£o n√£o deve ser limitado pelo limite do tipo num√©rico usando . Em java √© int, o que significa que nunca poderemos ter cole√ß√Ķes maiores que o n√ļmero de inteiros positivos. Em C# existe um tamanho em int e um em long e o de long √© que √© considerado “o verdadeiro”, embora na pr√°tica uma m√°quina vai ter problemas em aguentar mais que um int. Mas isso √© hoje. No futuro as m√°quina podem ter muito mais mem√≥ria e aguentar muito mais valores. Por outro lado, int e long t√™m valores negativos. √Č absurdo que o tamanho de uma cole√ß√£o – a contagem de elementos dentro da cole√ß√£o – seja negativo. Portanto, lense conta com o tipo Natural que √© sempre positivo e serve para contar coisas de zero at√© o tamanho que a m√°quina aguentar. N√ļmeros sem limite m√°ximo imposto pela linguagem s√£o muito uteis como provam o BigDecimal e BigInteger do java, mas a linguagem tem que permitir usar tipos desses mais facilmente.
Interoperabilidade √© outra quest√£o importante. √Č ao mesmo tempo importante poder utilizar tecnologia nativa √† plataforma base como por exemplo JDBC em Java e JQuery em javascript mas sem que isso inunde seu c√≥digo e o torne todo o sistema n√£o port√°til. Esse tipo de intera√ß√£o deve ser poss√≠vel mas restringida. Por outro lado, se recebemos um objecto de uma biblioteca escrita na linguagem nativa da plataforma, tem que ser poss√≠vel manipul√°-lo diretamente. Manipular aqui significa invocar m√©todos e ler campos. Contudo, idealmente, o c√≥digo deve ser escrito em lense puro e apenas algumas partes serem escritas na linguagem base da plataforma. Isto tamb√©m significa que √© necess√°rio prover um conjunto de classes base como String, Boolean, Number e outras para o programador n√£o tenha que constantemente lan√ßar m√£o dos tipos nativos. Ceylon √© uma linguagem que vai por este caminho. Kotlin parece ir por este caminho, mas na realidade est√° fortemente ligada aos tipos nativos dos java e o programador n√£o tem que fazer nenhum esfor√ßo para os usar, o que torna o c√≥digo n√£o port√°vel muito facilmente (mas permite usar o Kotlin como um Java++). Por outro lado, o estilo Ceylon torna a cria√ß√£o de aplica√ß√Ķes mais complexas um pouco mais demorado porque v√°rias tipos de bibliotecas precisam ser recriadas em Ceylon.
Para que a base de código seja realmente reaproveitável é necessário este isolamento. O que nos leva ao conceito de módulo. Módulos são uma coisa nova no java 9, mas existem de raiz em outras linguagens como Ceylon e TypeScript. Eles realmente ajudam a organizar o código e de quebra ainda permite controlar que certos módulos só podem ser usados em certos ambientes.
Design de linguagens √© bem interessante, mas descobri que demanda um certo conhecimento caso contr√°rio erros no design v√£o ser cometidos que levam √† inconsist√™ncia. √Č necess√°rio tamb√©m uma distin√ß√£o entre o que o compilador pode fazer mecanicamente e o que a linguagem pode fazer teoricamente. Em java , por exemplo, o compilador tem que entender intersec√ß√£o de tipos porque √© poss√≠vel escrever:

public <T extends Serializable & Clonable> T copy(T obj)

Tudo bem que apenas podemos usar intersecção de tipos em genéricos, mas isso não importa para o compilador. Se ele precisa tem a lógica para saber lidar com esses tipos não importa muito onde a linguagem define que eles podem ser usados. Em Ceylon, por exemplo podemos escrever :

copy (Serializable & Clonable obj)

Sem usar tipos genéricos e o compilador vai entender exatamente a mesma coisa.
O design da linguagem , e ainda mais uma que √© fortemente tipada, depende fortemente de desenha um sistema de tipos (type system). Coisas como intersec√ß√£o de tipos, uni√£o de tipos, tipos e alg√©bricos s√£o alguns conceitos que come√ßam a aparecer em bastantes linguagens e tornam as coisa mais seguras sob pena de obrigar o programador a saber mais conceitos. Java √© um bom exemplo de como aumentar o n√ļmero de conceitos necess√°rios para come√ßar a linguagem n√£o √© um problema a longo prazo. Java obrigou pensamento OO em um tempo onde isso n√£o era exigido. Hoje ele conta com conceitos como gen√©ricos, tipos de intersec√ß√£o (embora limitado) , monads (Streams, Optional, CompletableFuture) , traits (as novas interfaces do java 8 em que se podem definir m√©todos s√£o traits), etc.. Algumas coisas passam at√© desapercebidas ao programador de hoje, mas jogar o java 9 nas m√£os de um programador em 1990 em vez do java 1.0 teria sido uma receita para o abandono da linguagem. Ent√£o, hoje, as novas linguagens t√™m que introduzir conceitos novos, mas de um jeito que seja simples e fa√ßa sentido, mesmo quando voc√™ n√£o conhece toda a teoria por detr√°s daquilo. E isso √© um desafio de design.

 

Comente

Artigos