No passado recente, as aplicações móveis viraram o mundo do avesso e já mudaram a forma como usamos a internet para trabalho e lazer. Inúmeras tecnologias surgiram para criar aplicativos móveis e processos de desenvolvimento começam a considera-los como cidadãos de primeira-classe. Contudo, embora o Mobile já pareça ser onipresente, o futuro está prestes a começar. Estamos diante de novas gerações de dispositivos móveis de vestir (wearables) ou diversos gadgets que compõem a Internet das Coisas (Internet of Things, IoT). Seremos confrontados com novos tipos de interfaces de usuário para mostrar dados bem como aceitar comandos. E presenciaremos cada vez mais empresas realmente priorizando a mobilidade. Tudo isso influenciará a forma como projetamos, codificamos e testamos software nos anos vindouros.
Este artigo do InfoQ faz parte de uma série, no vertiginoso mundo da tecnologia móvel. É possível receber notificações sobre novos artigos dessa série aqui.
A Apple recentemente promoveu o Swift - uma nova linguagem de programação para desenvolvimento iOS e OSX, para a versão 1.0. O Swift da Apple não deve ser confundido com a antiga linguagem de scripting em paralelo. Swift vem para tornar o desenvolvimento iOS e OSX mais simples e divertido. Nesse artigo, explicarei o que acredito ser as cinco melhores funcionalidades Swift; e porque vale muito a pena dar uma conferida.
A Apple já tinha uma linguagem de programação, o Objective-C. Então, por que introduzir uma nova linguagem? Bem, embora o Objective-C possa ter sido bem diferente e moderna quando lançada, ela não apetece ao gosto atual por linguagens. Do lado do varejo por exemplo, linguagens de script como o Ruby tem sido amplamente adotadas graças à sintaxe limpa que a linguagem oferece. No mundo corporativo, linguagens fortemente tipadas (type safe) com inferência de tipo parecem ser preferidas e grandes esforços tem sido vistos em linguagens como C# e Java (ou Scala) para trazer conceitos tipicamente encontrados em linguagens funcionais, tais como: funções como objetos e Lambdas. No Objective-C faltam algumas dessas coisas, como sintaxe limpa (e syntatic sugar) e inferência de tipo. O Swift tenta preencher essa lacuna.
Isso não quer dizer que Objective-C não é uma boa linguagem de programação. De fato, é uma grande linguagem. Mas vejo sinais claros de espaço suficiente para alternativas ao Objective-C prosperarem. Para levar as coisas ainda mais adiante, e graças a quão bom Swift é, não ficaria surpreso se a adoção do Swift espalhasse como um incêndio.
Agora vamos focar naquilo que o Swift tem a oferecer. Do ponto de vista da linguagem, Swift é incrível. A Apple observou linguagens modernas, como Scala ou C# e construiu uma linguagem super simples e no entanto poderosa. Ele oferece uma mistura bem interessante entre paradigmas de orientação a objetos e programação funcional - embora dizer que Swift é uma linguagem funcional é um grande exagero. Vamos passar para as cinco melhores características do Swift.
#1: Vantagens da sintaxe
Sintaticamente falando, Swift é soberbo. É uma linguagem extremamente simples e limpa com uma leitura incrível mesmo para os padrões atuais. Pode-se ver de cara que a simplicidade foi chave na hora de projetar a linguagem. Tome como exemplo o famoso ponto e vírgula ao final de cada declaração. A Apple decidiu torna-lo opcional. Embora isso não seja extremamente relevante, mostra o esforço que eles tiveram para deixar a sintaxe o mais limpa possível.
Outros exemplos são interpolação de string e o suporte da linguagem para tratar arrays e loops.
Interpolação de Strings
var message = "Hello World" "A mensagem é \(message)" //A mensagem é Hello world var a = 1, b = 2 "A soma é \(a + b)" //A soma é 3
Loops
var length = 10 for i in 0..
Arrays
var list = ["a", "b"] list += ["c", "d"]
Esses são apenas alguns exemplos de como a linguagem Swift tem suporte para fazer essas coisas. Note, por exemplo, que concatenar arrays também pode ser feito com o método "append" na classe Array, mas o fato da Apple se superar para construir isso como parte da linguagem demonstra qual é seu objetivo com o Swift.
Se quiser aprender Swift, e testar alguns desses pedaços de código, não poderia deixar de abordar o novo Playground no Xcode 6. O Playground permite testar o código enquanto estamos digitando, em tempo real. Ele executará tudo que digitar no Playground, e apresenta informações detalhadas sobre valores de variáveis, os valores de retorno das chamadas de funções e quantas vezes um determinado bloco de código foi executado. Abrir o Playground no Xcode 6 é bem simples:
E aqui está a tela do Playground:
#2: Funções são objetos de primeira linha
Funções como objetos de primeira classe e funções de alta ordem, podem ser encontrados em cada vez mais linguagens. Por exemplo, o Java 8 introduziu recentemente Lambdas. O conceito é simples, permitir que funções aceitem outras funções como parâmetros e que também retornem funções. Em sua simplicidade reside o poder deste conceito, uma vez que permite maiores abstrações. Por exemplo, pegue uma função de "filter" aplicada no array. A função de filtro permite filtrar um determinado array com base em qual desses itens satisfazem determinados critérios passados como parâmetro. A chave para ter um método super genérico é ser capaz de receber uma função como parâmetro. Vamos analisar a sintaxe para definir funções.
Swift tem uma sintaxe para definir funções que de alguma forma se assemelham àquelas de linguagens tipicamente funcionais como Haskell (não exatamente igual, mas parecida). Do lado esquerdo da flecha (->) temos os parâmetros e do lado direito da flecha temos o tipo de retorno. Em nosso exemplo, queremos filtrar uma lista de números, então baseado em um determinado número queremos retornar um booleano. Nesse caso, o tipo da função será:
(Item:Int) -> Bool
Então, receberá um Int e retornará um Bool. Obviamente, pode ter vários parâmetros, mas não tão óbvio assim. Também pode retornar vários valores sem ter que criar um objeto de recipiente. Neste último caso, a função retorna uma tupla.
A definição de uma função para filtrar inteiros poderia ser:
funct bigNumbersOnly (item:Int) -> Bool { return item > 3 }
Agora que temos a função, vamos olhar a função "filter" que recebe uma função como parâmetro.
var numbers = [1, 2, 3, 4, 5] var bigOnes = numbers.filter(bigNumbersOnly)
Nesse exemplo, o filtro é uma função de ordem mais alta, porque recebe uma função como parâmetro. No Swift, funções são como objetos, o que significa que podemos definir a função em linha …
var numbers = [1, 2, 3, 4, 5] var bigOnes = numbers.filter({(item:Int) -> Bool in return item > 3})
…. ou podemos atribuir a função a uma variável e usá-la depois.
//defina duas variáveis de tipo function var biggies = {(item:Int) -> Bool in return item > 3 } var threes = {(item:Int) -> Bool in return item == 3 } //decidar qual usar em tempo de execucao var result = numbers.filter(onlyThrees ? threes : biggies)
Tratar funções como objetos que podem ser referenciados e passados como parâmetro é bastante comum hoje em dia. Mas de novo, pode-se dizer que pela simplicidade como isso é feito no Swift é um conceito básico que fica ainda melhor com inferência de tipo
#3: Fortemente tipada com inferência de tipo
No mundo corporativo, estamos acostumados a trabalhar em cima da nossa rede de segurança fortemente tipada. Enquanto linguagens fortemente tipadas podem dar aquela segurança extra que as coisas (geralmente) não vão quebrar se compiladas, é uma experiência bem melhor quando essas linguagens também fazem inferência de tipo. Dessa forma, por exemplo, podemos fazer:
//Sem Type inference var x:String = "bar" //Com Type inference var y = "bar"
Repare na ausência do tipo no segundo exemplo. Como o Swift sabe que "bar" é uma String, não é necessário definir explicitamente (embora seja possível, como no primeiro exemplo). Isso pode parecer algo simples, mas certamente torna mais interessante quando é o tipo da função que é inferido.
Então, como podemos definir as funções do nosso exemplo anterior sem definir o tipo? Vamos ver como o Swift resolve:
//$0 sera mapeado para o primeiro parametro, $1 para o segundo... var result = numbers.filter({ return $0 == 3})
Doesn't get much cleaner than that! If you had more than one parameter and would like to reference parameters by name instead, you could do it like this:
Difícil ficar mais limpo que isso! Se tem mais de um parâmetro e quiser referenciar parâmetros por nome, é possível fazer isso da seguinte forma:
{a, b in return a > b }
#4 Generics
Outra característica disponível na linguagem, que pode ser extremamente útil, é o generics. No mundo corporativo, os generics foram primeiramente introduzidos em C#, e mais tarde em Java, depois de ter ganho muita força. Usar generics pode evitar as conversões entre tipos. Pois permite que o compilador execute certas checagens de tipo geralmente não disponíveis em linguagens sem generics (também é verdade que generics de fato geraram algumas controvérsias quando introduzidos no C#, mas foi totalmente aceito nas comunidades C# e Java).
Generics fornecem uma maneira de distinguir a definição de um tipo, geralmente (mas não limitado a) parâmetros e tipos de retorno. Embora isso pareça complexo, é realmente bastante fácil de entender com um simples exemplo.
//No momento de criação dessa função //Eu nao estou definindo o que T eh. O tipo real //de T sera deferido na chamada //da funcao doNothing. func doNothing(item:T) -> T { return item } //Quando chamo doNothing, estou implicitamente //atribuindo o tipo de T ao tipo do //parametro sendo enviado. Nesse caso, //um Array. //Note como o compilador sabe que o //tipo de retorno eh um Array. doNothing([1, 2, 3]).count
Mesmo que não seja um exemplo muito realista, pode-se ver a conveniência de conhecer em tempo de compilação o tipo do objeto dentro do Array. Para um exemplo mais simples, note como o compilador sabe que o Array contêm Strings:
var list = ["hello", "world"] list[0].uppercaseString //HELLO
Generics não estão limitados a parâmetros, pode-se definir classes, enumerações e estruturas genéricas. Na verdade, no exemplo anterior, o tipo da lista é Array<String>.
Podemos pensar que generics em Swift são como protocolos em Objective-C, contudo, apesar das similaridades na sintaxe, os conceitos são bem diferentes. Objective-C não suporta generics. Protocolos fornecem uma maneira de declarar que uma determinada implementação se adequa a um contrato de mensagens, mas esse contrato tem que ser especificado antes. Por exemplo, não se pode usar protocolos para impor que cada item no array seja do mesmo tipo (não importa qual tipo), mas pode fazer isso com generics. Além do fato de que estes dois conceitos são diferentes, Swift suporta protocolos praticamente da mesma forma que o Objective-C o faz.
#5 Tuplas
Tuplas são um conceito bem simples, pode-se definir um agrupamento ordenado de valores. Tuplas podem ser bastante úteis quando é necessário passar mais de um valor - como parâmetro ou como resultado de uma chamada de função. Tuplas não necessitam de definição de tipo para seus valores, tudo é inferido e tem seu tipo checado em tempo de compilação. A sintaxe para definir uma tupla é a seguinte:
(1, "Two", ["Three"])
No caso, temos uma tupla com três valores, o primeiro é um inteiro, o segundo uma String e o terceiro um array de Strings. A primeira vista isso pode parecer muito similar a Arrays, contudo o conceito é diferente. Não podemos adicionar ou remover um item de uma Tupla, e note como o compilador sabe exatamente os tipos de cada valor:
Podemos referenciar os diferentes valores da tupla tanto pela sua localização dentro da tupla, como a imagem sugere, ou podemos dar nomes a cada um desses valores. Isto vem bem a calhar quando uma função necessita retornar vários valores, e pode ser um exagero definir uma classe ou estrutura apenas para atender essa função. Vejamos um exemplo desse caso:
func info(items:[Int]) -> (avg:Int, min:Int, max:Int) { var sum = items.reduce(0, { $0 + $1 }) var min = items.reduce(Int.max, { $0 > $1 ? $1 : $0}) var max = items.reduce(Int.min, { $0 < $1 ? $1 : $0}) return (sum / items.count, min, max) } var result = info([1, 2, 3, 4, 5, 6]) result.avg //3 result.min //1 result.max //6
Tuplas fornecem uma forma simples para trabalhar com múltiplos valores sem ter o trabalho extra de declarar uma classe ou estrutura.
E tem mais…
A linguagem já vem com algumas grandes funcionalidades que valem a pena conferir, como observadores (observers) de propriedades, encadeamento opcional e extensões.
Acredito que o Swift tem todas as condições necessárias para rapidamente se tornar uma linguagem popular para iOS e OSX, tanto no âmbito empresarial, quanto no varejo. Sua característica de linguagem fortemente tipada com inferência de tipo à fará especialmente adequada para as empresas, enquanto a sintaxe limpa e simples atrairá aqueles em projetos para o varejo.
Sobre o autor
Gustavo Machado é o Vice-Presidente de engenharia da KidoZen, na qual lidera a execução da plataforma móvel de próxima geração da empresa. Ele tem vasta experiência desenvolvendo sistemas altamente distribuídos com diferentes tecnologias e utilizando práticas ágeis. Ele mantem um blog e sua conta no Twitter é @machadogj.