Kotlin
A concise multiplatform language developed by JetBrains
Lançamento do Kotlin 1.4.20
O Kotlin 1.4.20 chegou com novos recursos experimentais para você avaliar. Manter-se aberta para o feedback da comunidade é um dos princípios básicos da equipe do Kotlin, e precisamos de sua opinião sobre os protótipos dos novos recursos. Experimente-os e compartilhe seu feedback no Slack (receba um convite aqui ou no YouTrack.
Aqui estão alguns dos principais destaques:
- Suporte para novos recursos de JVM, como concatenação de strings via invokedynamic.
- Melhor desempenho e tratamento de exceções para projetos KMM.
- Extensões para JDK Path:
Path(“dir”) / “file.txt”
.
Também estamos enviando várias correções e melhorias de recursos existentes, incluindo aqueles adicionados na versão 1.4.0. Portanto, se você encontrou problemas com qualquer um desses recursos, agora é um bom momento para testá-los novamente.
Continue lendo para saber mais sobre os recursos do Kotlin 1.4.20. Você também pode encontrar uma breve visão geral do lançamento na página What’s new in Kotlin 1.4.20Novidades no Kotlin 1.4.20 na documentação do Kotlin. A lista completa de alterações está disponível no log de alterações.
Como sempre, gostaríamos de agradecer aos nossos colaboradores externos que nos ajudaram com esse lançamento.
Agora vamos mergulhar nos detalhes!
Kotlin/JVM
Na JVM, adicionamos o novo destino JVM 15 e nos concentramos principalmente em melhorar a funcionalidade e o desempenho existentes, bem como em corrigir bugs.
Concatenação de strings invokedynamic
Desde o Java 9, a concatenação de strings na JVM é feita por meio da invocação de métodos dinâmicos (a instrução invokedynamic
no bytecode). Isso funciona mais rápido e consome menos memória do que a implementação anterior, além de deixar espaço para otimizações futuras sem exigir alterações de bytecode.
Começamos a implementar esse mecanismo no Kotlin para obter melhor desempenho e agora ele pode compilar concatenações de strings em invocações dinâmicas em destinos JVM 9+.
Atualmente, esse recurso é experimental e abrange os seguintes casos:
String.plus
no formatos de operador (a + b
), explícito (a.plus(b)
) e referência ((a::plus)(b)
).toString
em classes inline e de dados.- Modelos de string, exceto para aqueles com um único argumento não constante (consulte KT-42457).
Para ativar a concatenação de strings invokedynamic
, adicione a opção de compilador -Xstring-concat
com um dos seguintes valores:
indy-with-constants
para realizar a concatenação deinvokedynamic
em strings com StringConcatFactory.makeConcatWithConstants() (planejado para ser o padrão para destinos JVM 9+ na versão 1.5).indy
para realizar a concatenaçãoinvokedynamic
em strings com StringConcatFactory.makeConcat().inline
para retornar à concatenação clássica viaStringBuilder.append()
.
Kotlin/JS
O Kotlin/JS continua evoluindo em um ritmo rápido, e este lançamento traz uma variedade de melhorias, incluindo novos modelos para seu assistente de projeto, DSL aprimorado para melhor controle sobre a configuração do projeto e muito mais. O novo compilador IR também recebeu uma maneira totalmente nova de compilar projetos com erros.
Alterações no Gradle DSL
O Kotlin/JS Gradle DSL recebeu várias atualizações que simplificam a configuração e a personalização de projetos, incluindo ajustes de configuração do webpack, modificações no arquivo package.json gerado automaticamente e controle aprimorado sobre dependências transitivas.
Ponto único para configuração do webpack
O Kotlin 1.4.20 apresenta um novo bloco de configuração para o destino de browser
, chamado commonWebpackConfig
. Dentro dele, você pode ajustar as configurações comuns de um único ponto, em vez de duplicar as configurações para webpackTask
, runTask
e testTask
.
Para habilitar o suporte CSS por padrão para todas as três tarefas, você só precisa incluir o seguinte snippet no build.gradle(.kts)
do seu projeto:
Personalização de package.json no Gradle
O arquivo package.json
geralmente define como um projeto JavaScript deve se comportar, identificando scripts que estão disponíveis para execução, dependências e muito mais. Ele é gerado automaticamente para projetos Kotlin/JS durante o tempo de compilação. Como o conteúdo de package.json
varia de caso para caso, recebemos várias solicitações para uma maneira fácil de personalizar esse arquivo.
A partir do Kotlin 1.4.20, você pode adicionar entradas ao arquivo de projeto package.json
a partir do script de compilação do Gradle. Para adicionar campos personalizados ao seu package.json
, use a função customField
no bloco de compilações packageJson
:
Quando você compilar o projeto, isso adicionará o seguinte bloco ao arquivo de configuração build/js/packages/projectName/package.json
:
"hello": { "one": 1, "two": 2 }
Seja para adicionar um campo de scripts à configuração, facilitando a execução do seu projeto na linha de comando, ou para incluir informações de outras ferramentas pós-processamento, esperamos que você considere útil essa nova maneira de especificar campos personalizados.
Resoluções seletivas de dependência yarn (experimental)
Ao incluir dependências npm, há ocasiões em que você deseja ter controle refinado sobre suas dependências (dependências transitivas). Existem vários motivos para isso. Você pode querer aplicar um upgrade importante a uma das dependências de uma biblioteca que está usando. Ou você pode querer reverter uma atualização de uma dependência transitiva que atualmente interrompe sua aplicação. As resoluções seletivas de dependências do Yarn permitem substituir as dependências especificadas pelo autor original, para que você possa continuar desenvolvendo.
Com o Kotlin 1.4.20, oferecemos uma maneira preliminar (experimental) de configurar esse recurso a partir do script de compilação Gradle de um projeto. Embora ainda estejamos trabalhando em uma perfeita integração da API com o restante das opções do Kotlin/JS, você já pode usar o recurso por meio do YarnRootExtension
dentro do YarnPlugin
. Para afetar a versão resolvida de um pacote para o seu projeto, use a função resolution
. Em seus argumentos, especifique o seletor de nome do pacote (conforme especificado pelo Yarn) e a versão desejada.
Um exemplo de configuração para resolução seletiva de dependências no seu arquivo build.gradle.kts
seria o seguinte:
Aqui, todas as suas dependências npm que exigem react
receberão a versão 16.0.0
, e processor
receberá sua dependência decamelize
como a versão 3.0.0
. Além disso, você também pode transmitir invocações include
e exclude
ao bloco resolution
, o que permite especificar restrições sobre as versões aceitáveis.
Desabilitando espaços de trabalho granulares (experimental)
Para acelerar os tempos de compilação, o plug-in Kotlin/JS Gradle instala apenas as dependências necessárias para uma tarefa específica do Gradle. Por exemplo, o pacote webpack-dev-server
é instalado apenas quando você executa uma das tarefas *Run
e não quando você executa a tarefa assemble
. Embora isso signifique que downloads desnecessários são evitados, ele pode criar problemas ao executar vários processos Gradle em paralelo. Quando os requisitos de dependências entram em conflito, as duas instalações de pacotes npm podem causar erros.
Para resolver esse problema, o Kotlin 1.4.20 inclui uma nova opção (experimental) para desabilitar esses chamados espaços de trabalho granulares. Como o suporte experimental para resoluções de dependência seletiva, esse recurso também está acessível por meio do YarnRootExtension
, mas provavelmente será integrado mais estreitamente com o restante do Kotlin/JS Gradle DSL. Para usá-lo, adicione o seguinte snippet ao seu arquivo build.gradle.kts
:
Com essa configuração, o plug-in Kotlin/JS Gradle instalará todas as dependências npm que podem ser usadas pelo seu projeto, incluindo aquelas usadas por tarefas que não estão sendo executadas atualmente. Isso significa que a primeira compilação Gradle pode demorar um pouco mais, mas as dependências baixadas estarão atualizadas para todas as tarefas que você executar. Dessa forma, você pode evitar conflitos ao executar vários processos Gradle em paralelo.
Novos modelos de assistente
Para fornecer maneiras mais convenientes de personalizar seu projeto durante a criação, o assistente de projeto para Kotlin acompanha novos modelos ajustáveis para aplicações Kotlin/JS. Existem modelos para os ambientes de tempo de execução do navegador e do Node.js. Eles servem como um bom ponto de partida para o seu projeto e possibilitam o ajuste fino da configuração inicial. Isso inclui configurações como habilitar o novo compilador IR ou configurar o suporte para bibliotecas adicionais.
Com o Kotlin 1.4.20, existem três modelos disponíveis:
- Browser Application: permite que você configure um projeto Kotlin/JS Gradle básico que é executado no navegador.
- React Application: contém tudo o que você precisa para começar a construir uma aplicação React usando os kotlin-wrappers apropriados. Ele fornece opções para permitir integrações para folhas de estilo, componentes de navegação e contêineres de estado.
- Aplicação Node.js: pré-configura seu projeto para ser executado em um tempo de execução Node.js. Ele vem com a opção de incluir diretamente o pacote experimental kotlinx-nodejs, que apresentamos em um post anterior.
Ignorar erros de compilação (experimental)
Com o Kotlin 1.4.20, também estamos entusiasmados em apresentar um novo recurso disponível no compilador Kotlin/JS IR – – ignorar erros de compilação. Esse recurso permite que você experimente sua aplicação mesmo quando ela está em um estado em que normalmente não compilaria. Por exemplo, quando você está fazendo uma refatoração complexa ou trabalhando em uma parte do sistema que não está totalmente relacionada a um erro de compilação. Com esse novo modo de compilador, o compilador ignora qualquer código incorreto e o substitui por exceções de tempo de execução em vez de se recusar a compilar.
O Kotlin 1.4.20 vem com duas políticas de tolerância para ignorar erros de compilação no seu código:
- No modo
SEMANTIC
, o compilador aceitará um código sintaticamente correto, mas que não faz sentido semanticamente. Um exemplo para isso seria uma instrução contendo uma incompatibilidade de tipo (comoval x: String = 3
). - No modo
SYNTAX
, o compilador aceitará todo e qualquer código, mesmo que contenha erros de sintaxe. Independentemente do que você escrever, o compilador ainda tentará gerar um executável funcional.
Como um recurso experimental, ignorar erros de compilação requer aceitação por meio de uma opção do compilador. Ele está disponível apenas para o compilador Kotlin/JS IR. Para habilitá-lo, adicione o seguinte snippet ao seu arquivo build.gradle.kts
:
Esperamos que a compilação com erros ajude a restringir loops de feedback e aumentar a velocidade de iteração ao trabalhar em projetos Kotlin/JS. Também esperamos receber seu feedback e quaisquer problemas que você encontrar ao experimentar esse recurso. Para isso, use o nosso YouTrack.
À medida que continuamos a refinar a implementação desse recurso, também ofereceremos uma integração mais profunda para ele com o Kotlin/JS Gradle DSL e suas tarefas posteriormente.
Kotlin/Native
O desempenho continua sendo uma das principais prioridades do Kotlin/Native na versão 1.4.20. Um recurso importante nessa área é um protótipo do novo mecanismo de análise de escape que planejamos aprimorar e melhorar nos próximos lançamentos. E, claro, também há melhorias de desempenho secundárias, como verificações de intervalo mais rápidas (in
).
Outro aspecto das melhorias no desenvolvimento com Kotlin/Native na versão 1.4.20 são os aprimoramentos e a correção de bugs. Corrigimos uma série de problemas antigos, bem como aqueles encontrados nos novos recursos da versão 1.4, como o mecanismo de compartilhamento de código. Um conjunto de melhorias corrige inconsistências de comportamento entre o Kotlin/Native e o Kotlin/JVM em casos extremos, como inicialização de propriedades ou a maneira como equals
e hashCode
funcionam em referências funcionais.
Finalmente, estendemos os recursos de interoperabilidade Objective-C com uma opção para agrupar exceções Objective-C em exceções Kotlin, tornando possível manipulá-las no código Kotlin.
Análise de escape
A Análise de escape é uma técnica que o compilador usa para decidir se um objeto pode ser alocado na pilha ou se deve “escapar” para o heap. A alocação na pilha é muito mais rápida e não requer coleta de lixo no futuro.
Embora o Kotlin/Native já tivesse uma análise de escape local, agora estamos introduzindo uma implementação de protótipo de uma nova análise de escape global mais eficiente. Ela é executada em uma fase de compilação separada para as compilações de versão (com a opção de compilador -opt
).
Esse protótipo já rendeu alguns resultados promissores, como um aumento médio de desempenho de 10% em nossos referenciais. Estamos pesquisando maneiras de otimizar o algoritmo para que ele encontre mais objetos para alocação de pilha e acelere ainda mais o programa.
Enquanto continuamos a trabalhar no protótipo, você pode nos ajudar muito avaliando e compartilhando os resultados que obtém nos seus projetos reais.
Se quiser desabilitar a fase de análise de escape, use a opção de compilador -Xdisable-phases=EscapeAnalysis
.
Optar pelo wrapping de exceções Objective-C
O objetivo das exceções no Objective-C é bastante diferente daquele no Kotlin. Seu uso é normalmente limitado a localizar erros durante o desenvolvimento. Porém, tecnicamente, as bibliotecas Objective-C podem lançar exceções em tempo de execução. Anteriormente, não havia a opção para lidar com essas exceções no Kotlin/Native, e encontrar uma NSException
lançada de uma biblioteca causava o encerramento de todo o programa Kotlin/Native.
Na versão 1.4.20, adicionamos uma opção para lidar com essas exceções em tempo de execução, para evitar travamentos do programa. Você pode optar pelo wrapping de NSException
na ForeignException
do Kotlin para tratamento posterior no código Kotlin. Essa ForeignExeption
contém a referência à NSException
original, que permite obter informações sobre a causa raiz.
Para habilitar o wrapping de exceções Objective-C, especifique a opção -Xforeign-exception-mode objc-wrap
na chamada cinterop
ou adicione a propriedade foreignExceptionMode = objc-wrap
ao arquivo .def
. Se você usa a integração com CocoaPods, especifique a opção no bloco de script de compilação pod {}
de uma dependência como esta:
O comportamento padrão permanece inalterado: o programa é encerrado quando uma exceção é lançada a partir do código Objective-C.
Melhorias no plug-in CocoaPods
Melhor execução de tarefas
Neste lançamento, melhoramos significativamente o fluxo de execução de tarefas. Por exemplo, se você adicionar uma nova dependência CocoaPods, as dependências existentes não serão reconstruídas. Adicionar um destino extra também não afeta a reconstrução de dependências para destinos existentes.
DSL estendida
No lançamento 1.4.20, estendemos a DSL para adicionar dependências CocoaPods ao seu projeto Kotlin.
Além de Pods e Pods locais do repositório CocoaPods, você pode adicionar dependências pelos seguintes tipos de bibliotecas:
- Uma biblioteca de um repositório de especificações personalizadas.
- Uma biblioteca remota de um repositório Git.
- Uma biblioteca de um arquivo (também disponível por endereço HTTP arbitrário).
- Uma biblioteca estática.
- Uma biblioteca com opções personalizadas de cinterop.
A sintaxe DSL anterior ainda é compatível.
Vamos examinar algumas mudanças de DSL nos exemplos a seguir:
-
Uma dependência em uma biblioteca remota de um repositório Git. Você pode especificar uma tag, submissão ou branch usando palavras-chave correspondentes, por exemplo:
Você também pode combinar essas palavras-chave para obter a versão necessária de um Pod.
-
Uma dependência de uma biblioteca de um repositório de especificações personalizadas. Use o parâmetro especial
specRepos
para ela:
Você pode encontrar mais exemplos na amostra do Kotlin com CocoaPods.
Integração atualizada com o Xcode
Para funcionar corretamente com o Xcode, o Kotlin requer algumas alterações no Podfile:
-
Se seu Pod Kotlin tiver dependências por pods Git, HTTP ou specRepo, você também deverá especificá-las no Podfile. Por exemplo, se você adicionar uma dependência por
AFNetworking
do repositório CocoaPods, declare-a também no Podfile:pod 'AFNetworking'
-
Ao adicionar uma biblioteca da especificação personalizada, você também deve especificar a localização das especificações no início do seu Podfile:
source 'https://github.com/Kotlin/kotlin-cocoapods-spec.git' target 'kotlin-cocoapods-xcproj' do // ... other Pods ... pod 'example' end
Agora, os erros de integração têm descrições detalhadas no IntelliJ IDEA. Portanto, se você tiver qualquer problema com o seu Podfile, receberá imediatamente informações sobre como corrigi-lo.
Dê uma olhada no branch withXcproject
da amostra do Kotlin com CocoaPods. Ele contém um exemplo de integração Xcode com o projeto Xcode existente denominado kotlin-cocoapods-xcproj
.
Suporte para bibliotecas Xcode 12
Adicionamos suporte para novas bibliotecas fornecidas com o Xcode 12. Sinta-se à vontade para usá-las no seu código Kotlin!
Estrutura atualizada de publicações de bibliotecas multiplataformas
Antes do Kotlin 1.4.20, publicações de bibliotecas multiplataformas incluíam publicações específicas da plataforma e uma publicação de metadados. No entanto, não havia necessidade de depender exclusivamente da publicação de metadados e, portanto, esse artefato nunca foi usado explicitamente.
A partir do Kotlin 1.4.20, não há mais uma publicação separada de metadados. Agora, artefatos de metadados estão incluídos na publicação raiz, que representa a biblioteca inteira e é resolvida automaticamente para os artefatos específicos da plataforma apropriada quando adicionados como uma dependência ao conjunto de origem comum.
Observe que você não deve adicionar um artefato vazio sem um classificador ao módulo raiz da sua biblioteca para atender aos requisitos de repositórios como o Maven Central, pois isso resultará em um conflito com artefatos de metadados que agora estão incluídos nesse módulo.
Compatibilidade com bibliotecas publicadas no lançamento 1.4.20
Se você habilitou o suporte para estrutura hierárquica de projetos e deseja usar uma biblioteca multiplataforma publicada com esse suporte no Kotlin 1.4.20 ou superior, também precisará atualizar o Kotlin no seu projeto para a versão 1.4.20 ou superior.
Se você é um autor de biblioteca e publica sua biblioteca multiplataforma no Kotlin 1.4.20+ com suporte para a estrutura hierárquica de projetos, lembre-se de que os usuários com versões anteriores do Kotlin que também têm suporte habilitado para a estrutura hierárquica de projetos não poderão usar a sua biblioteca. Eles precisarão fazer upgrade do Kotlin para a versão 1.4.20 ou superior.
No entanto, se você ou os usuários da sua biblioteca não habilitarem o suporte para a estrutura hierárquica de projetos, aqueles com versões anteriores do Kotlin ainda poderão usar a sua biblioteca.
Saiba mais sobre como publicar uma biblioteca multiplataforma.
Alterações na biblioteca padrão
Extensões para java.nio.file.Path
A partir da versão 1.4.20, a biblioteca padrão fornece extensões experimentais para java.nio.file.Path
.
Trabalhar com a API de arquivo JVM moderna ao estilo idiomático do Kotlin agora é semelhante a trabalhar com extensões java.io.File
do pacote kotlin.io
. Não há mais necessidade de chamar métodos estáticos de Files
, pois a maioria deles agora está disponível como extensões no tipo Path
.
As extensões estão localizadas no pacote kotlin.io.path
. Como o próprio Path
está disponível no JDK 7 e superior, as extensões são colocadas no módulo kotlin-stdlib-jdk7
. Para usá-las, você precisa optar pela anotação experimental ExperimentalPathApi
.
Queremos agradecer especialmente ao nosso contribuidor AJ Alt por enviar o PR inicial com essas extensões.
Desempenho aprimorado da função String.replace
Sempre ficamos entusiasmados quando a comunidade Kotlin sugere melhorias, como no caso a seguir. Neste lançamento, mudamos a implementação da função String.replace()
.
A variante com distinção entre maiúsculas e minúsculas usa um loop de substituição manual baseado em indexOf
, enquanto a variante sem distinção entre maiúsculas e minúsculas usa a correspondência de expressão regular.
Esta melhoria acelera a execução da função em certos casos.
Suspensão de uso de extensões do Kotlin para Android
Desde que criamos as extensões do Kotlin para Android, elas têm desempenhado um papel importante no crescimento da popularidade do Kotlin no ecossistema Android. Com essas extensões, fornecemos aos desenvolvedores ferramentas convenientes e eficientes para reduzir o código boilerplate:
- Visualizações sintéticas (
kotlinx.android.synthetics
) para interação com a UI. - Gerador de implementação
Parcelable
(@Parcelize
) para transmitir objetos comoParcel
.
Inicialmente, pensamos em adicionar mais componentes ao kotlin-android-extensions
. Mas isso não aconteceu e até mesmo recebemos solicitações de usuários para dividir o plug-in em partes independentes.
Por outro lado, o ecossistema Android está sempre evoluindo, e os desenvolvedores estão obtendo novas ferramentas que facilitam o trabalho. Algumas lacunas que as extensões do Kotlin para Android preenchiam foram agora cobertas por mecanismos nativos do Google. Por exemplo, em relação à sintaxe concisa para interação com a UI, agora existe o Android Jetpack, que tem uma associação de exibições que substitui findViewById
, assim como os sintéticos Kotlin.
Considerando esses dois fatores, decidimos retirar os sintéticos em favor da associação de exibições e mover o gerador de implementação Parcelable para um plug-in separado.
No lançamento 1.4.20, extraímos o gerador de implementações Parcelable de kotlin-android-extensions
e iniciamos o ciclo de suspensão para o restante dele, que atualmente é apenas sintético. Por enquanto, eles continuarão trabalhando com um aviso de suspensão de uso. No futuro, você precisará mudar seu projeto para outra solução. Aqui estão as diretrizes para migrar projetos do Android de sintéticos para visualizar associações.
O gerador de implementação Parcelable agora está disponível no novo plug-in kotlin-parcelize
. Aplique esse plug-in em vez ou além de kotlin-android-extensions
se decidir continuar usando sintéticos. A anotação @Parcelize
é movida para o pacote kotlinx.parcelize
.
Como atualizar
Antes de atualizar seus projetos para a versão mais recente do Kotlin, você pode experimentar a nova linguagem e os recursos da biblioteca padrão online em play.kotl.in.
No IntelliJ IDEA e no Android Studio, você pode atualizar o plug-in do Kotlin para a versão 1.4.20. Saiba como fazer isso aqui.
Se quiser trabalhar em projetos existentes que foram criados com versões anteriores do Kotlin, use a versão 1.4.20
do Kotlin na sua configuração de projeto. Para obter mais informações, consulte os documentos para Gradle e para Maven.
Você pode baixar o compilador de linha de comando na página de lançamento do Github.
Você pode usar as seguintes versões de biblioteca com este lançamento:
- kotlinx.atomicfu versão 0.14.4
- kotlinx.coroutines versão 1.4.1
- kotlinx.serialization versão 1.0.1
- ktor versão 1.4.1
- kotlinx.html versão 0.7.2
- kotlinx-nodejs versão 0.0.6
As versões das bibliotecas de kotlin-wrappers
(kotlin-react
etc.) podem ser encontradas no repositório correspondente.
Os detalhes do lançamento e a lista de bibliotecas compatíveis também estão disponíveis aqui.
Se tiver problemas com a nova versão, você poderá encontrar ajuda no Slack (receba um convite aqui ) e reportar issues no nosso YouTrack.
Colaboradores externos
Gostaríamos de agradecer a todos os nossos contribuintes externos cujos pull requests foram incluídos neste lançamento:
Jinseong Jeon Toshiaki Kameyama Steven Schäfer Mads Ager Mark Punzalan Ivan Gavrilovic pyos Jim Sproch Kristoffer Andersen Aleksandrina Streltsova cketti Konstantin Virolainen AJ Alt Henrik Tunedal Juan Chen KotlinIsland, Valeriy Vyrva Alex Chmyr Alexey Kudravtsev Andrey Matveev Aurimas Liutikas Dat Trieu Dereck Bridie Efeturi Money Elijah Verdoorn Enteerman fee1-dead Francesco Vasco Gia Thuan Lam Guillaume Darmont Jake Wharton Julian Kotrba Kevin Bierhoff Matthew Gharrity Matts966 Raluca Sauciuc Ryan Nett Sebastian Kaspari Vladimir Krivosheev n-p-s Pavlos-Petros Tournaris Robert Bares Yoshinori Isogai Kris Derek Bodin Dominik Wuttke Sam Wang Uzi Landsmann Yuya Urano Norbert Nogacki Alexandre Juca