2018/01/29

À conversa com Fernando Mário Martins


A FCA deu-nos a oportunidade de conversar um pouco com alguns dos seus autores, e desta vez o escolhido para a rubrica "À conversa com" foi Mário Martins, autor do livro JAVA 8 - POO + Construções Funcionais.

O que é a programação orientada a objetos?

A resposta completa a esta questão ocuparia certamente, no mínimo, um capítulo de um livro, tal como no livro "Java 8: POO + Construções Funcionais", mas vamos tentar dizer o essencial. A programação orientada "aos objetos" ou "pelos objetos" - do inglês object-oriented programming, OOP -, ou seja, a POO é, antes de mais, um dos muitos paradigmas de programação existentes, e assim um dos muitos modelos da programação de computadores que foram desenvolvidos com o objetivo de mais facilmente se conceptualizarem as computações a realizar por um computador, em especial como representar e guardar as informações e como organizar as tarefas que permitem realizar operações sobre esses dados (consultas e modificações).

Os paradigmas de programação mais conhecidos são o imperativo (cf. Assembly, Pascal, C, Basic, Modula), o funcional (cf. Lisp, ML, Haskell), o lógico (cf. Prolog), o relacional (cf. tabelas e Sql) e o de objectos (cf. Smalltalk, C++, Object-Pascal, Java, C#, Python, Ruby, Scala). Todos estes paradigmas são muito antigos, tendo-se desenvolvido entre os anos 40 e 80 do século XX, e tendo dado origem a várias linguagens ao longo do tempo, sendo muitas delas multi-paradigma.

A "orientação aos objetos" surge nos anos 60/70 como uma proposta adicional para a então designada "crise do software" resultante dos problemas que os programadores começavam então a sentir no desenvolvimento dos seus projetos de software, entre outras razões, por má
documentação do código, por dificuldade em realizar manutenção e alterações em código disperso e pouco seguro, e dificuldades de extensibilidade e escalabilidade do código, em geral por falta de modularidade.

Alan Kay, um dos criadores da linguagem Smalltalk, usou pela primeira vez nos anos 70 a expressão "object-oriented" procurando definir as características fundamentais dessa nova perspetiva de criar programas, ou seja, de representar os problemas para os quais pretendemos soluções. As ideias fundamentais foram recolhidas na área da simulação. As principais entidades e conceitos do problema real devem ser caracterizadas pelos seus atributos ou propriedades (os seus dados) e também pelas operações que conseguem realizar (o seu comportamento). Desta forma, e seguindo as correntes então em vigor sobre modularidade e encapsulamento (cf. abstrações de dados, etc.), surge a noção de objeto como sendo, idealmente, uma cápsula de dados unicamente acedidos pelas operações definidas para esse objeto. Surge assim a fórmula Objeto = estrutura de dados protegida + comportamento, que corresponde à noção de módulo de dados.

Porém, é necessário definir a estrutura e comportamento dos objetos da mesma categoria ou tipo. A noção de Classe surge então como a construção onde se define a estrutura e o comportamento dos objetos similares de uma dada categoria ou tipo. As Classes permitirão criar tais objetos (cada um com os seus valores particulares) e todos são instâncias da sua respetiva classe. As Classes são assim os seus identificadores de tipo. A forma de solicitar os serviços de um objeto, ou seja, de solicitar a execução de uma das suas operações internas, consiste no envio de uma Mensagem ao objeto a partir de um outro objeto. O que envia a mensagem chama-se emissor e o que a recebe recetor. Da avaliação da mensagem e dos seus argumentos resultará a execução de uma operação no recetor e o
eventual envio de um resultado. Assim se realiza uma computação ao nível básico.

Num programa OO definem-se as Classes necessárias para a criação do universo de objetos relacionados com o problema e programam-se, na maioria das vezes de forma sequencial, as mensagens que os objetos devem trocar entre si para se atingir a ou as soluções. Portanto, das interações programadas entre os objetos resultam as computações necessárias à solução.

Para que o comportamento dos vários objetos da mesma categoria (comportamento ou funcionalidade que é igual para todos) não seja multiplicado um sem número de vezes, o comportamento de uma categoria de objetos é guardado num único repositório que é a sua Classe, e corresponde à sua API. As Classes relacionam-se entre si de forma hierárquica podendo uma classe ser subclasse de outra. Cria-se assim, em geral, uma Hierarquia de Classes muito importante já que a esta hierarquia se associam mecanismos de Herança que permitem que estrutura e comportamento definido numa classe superior seja adicionado (tornado acessível) às suas subclasses, o que proporciona definição incremental, especialização e reutilização de código.

Finalmente, o Polimorfismo, que resulta diretamente das noções de classe e subclasse, sendo que qualquer instância de uma subclasse é compatível com a sua superclasse (é um subtipo).

Em síntese: Objetos, Mensagens, Classes, Hierarquia, Herança e Polimorfismo. A POO tem a ver fundamentalmente com a utilização destes conceitos para criar programas e não com a sintaxe da linguagem que os implementa.

O JAVA é uma linguagem puramente orientada a objetos?

Existem muitas opiniões, umas mais radicais do que outras sobre o que se deve entender por "puramente" OO. São académicas e irrelevantes neste e noutros contextos, pelo que vou responder à questão que creio que era a que se pretendia ver respondida, ou seja, se em Java todas as construções linguísticas ao dispor do programador são objetos. A resposta é não. Existem em Java construções linguísticas que não são objetos. Tal como noutras linguagens de POO, em JAVA os tipos primitivos e respetivos operadores não são objetos. Os arrays são em JAVA entidades referenciadas (cf. endereço) mas não são instâncias de qualquer classe. Curiosamente, e ao contrário do que muitos autores dizem, as classes de JAVA são objetos e
são também objetos as funções e as expressões lambda de JAVA 8.

Nos anos 80 lecionei Smalltalk80 e posso garantir que essa é uma linguagem puramente OO. Tudo são objetos. Até para criar uma nova classe teríamos que enviar uma mensagem. A linguagem Squeak, a derivada moderna de Smalltalk, é também uma linguagem puramente OO.

O JAVA é também uma linguagem imperativa (procedimental) e funcional?

JAVA é uma linguagem que foi criada para ser uma linguagem onde todas as noções OO são suportadas e em que se desenvolvem programas OO. No entanto, JAVA possui no seu núcleo básico os elementos que possibilitam programar imperativamente, designadamente tipos primitivos e operadores, estruturas de controlo típicas e arrays, e com estes programar pequenas aplicações sem objetos (de forma muito similar a C mas sem apontadores nem mallocs).

Procurando reforçar a ideia anterior, quem analisar o código fonte de JAVA para a implementação do JCF (JAVA Collections Framework) verificará que tudo é implementado usando arrays, operações nativas sobre arrays, tipos primitivos e as estruturas de controlo usuais das linguagem imperativas, aliás como é comum em muitas outras linguagens que implementam estruturas do tipo coleções.

JAVA 8 continua a ser uma linguagem de POO mas que acrescenta às versões anteriores construções funcionais (em especial expressões lambda, funções e streams de dados, que serão referidas adiante) que foram integradas na linguagem de forma natural e com grandes vantagens, quer de clareza e simplicidade, quer de performance por poderem tirar partido dos múltiplos processadores das máquinas atuais.


Em suma, JAVA é uma linguagem de POO que possui construções imperativas de base e construções funcionais que foram agora adicionadas, tal como já o haviam sido noutras linguagens de POO (cf. C#, Scala, Python e Ruby). Finalmente, os programas JAVA são compilados para bytecode que é interpretado e executado na JAVA Virtual Machine (JVM). Qualquer dispositivo que tenha instalada uma JVM pode correr aplicações JAVA.

A linguagem JAVA é a linguagem mais usada pelos programadores a nível mundial, segundo o índice da TIOBE. A que se deve esta popularidade, na sua opinião?

Sim, de facto sites e índices como TIOBE, PYPL, Indeed, Monster, Trendy Skills e outros, mostram que JAVA, C#, C/C++ são as linguagens generalistas mais usadas e nas quais mais competências são procuradas. Para além das suas inerentes qualidades, para além de todas serem fundamentalmente linguagens OO, todas possuem inúmeras e diversificadas tecnologias de suporte bem sedimentadas nas respetivas comunidades, e as roturas tecnológicas (ou mudanças) são em geral acompanhadas de ruturas de conhecimento de custos elevadíssimos.

No caso de JAVA, que lançará em setembro deste ano JAVA 9, estamos a falar de dezenas de milhões de programadores e engenheiros, e de dezenas de milhares de milhões de dispositivos em todo o mundo.

Quais as grandes modificações introduzidas em JAVA 8?

Do ponto de vista linguístico e semântico a grande inovação foi a introdução das construções funcionais, nomeadamente as expressões lambda, as funções e as streams de dados (cf. a API Stream) cujas operações podem ser combinadas permitindo criar "pipelines" de tratamento de dados, em especial a partir de coleções de JCF (cf. Sets, Lists, Maps). Estas novas construções permitem processamento paralelo sendo o código gerado otimizado ao nível da JVM. São também inovações, ainda que de tipo mais sintático, as Interfaces Funcionais (Functional Interfaces) e os "Default Methods", bem como a sintaxe agora disponível para referenciar métodos de instância ou métodos de classe ("Method References") que podem mesmo ser parâmetros de outros métodos.

Para além da Stream API, foi criada a API Date-Time e desenvolvido o Nashorn Javascript Standalone Engine como parte da plataforma JSE 8, que permite executar código JavaScript dinâmico na JVM.

O que são Expressões lambda (Lambda Expressions)? Qual a sua função?

Todos aprendemos no ensino secundário a definir e trabalhar com funções do tipo f(x) = x + 2. Estas funções têm um nome e representam uma transformação do(s) parâmetro(s) num resultado. Se não necessitássemos de lhes dar um nome bastaria escrever algo como x: x + 2. Na sua forma mais simples, expressões lambda são funções anónimas da forma anterior. Em JAVA 8 usa-se a seta para separar parâmetros de entrada do corpo da função, como por exemplo: x -> x + 2 ou (x, y) -> x + y. Os tipos dos parâmetros e do resultado podem ser declarados ou inferidos pelo compilador, e existe uma sintaxe simples para escrever estas expressões.

No entanto, o mais importante das expressões lambda não é a sua sintaxe mas sim as suas possibilidades de utilização e a sua semântica. Em JAVA, e até JAVA 8, apenas valores de tipos primitivos e objetos podiam ser passados como argumentos dos métodos. Um método não pode ser parâmetro de um método e tal impunha uma grande restrição quando se pretendia passar comportamento (enfim, código apenas) para um método. A solução usada em JAVA para se realizar a passagem de tal comportamento consistia em criar uma classe com um único método que codificava esse comportamento, criar uma instância dessa classe e passar tal objeto como parâmetro, invocando-se o seu método posteriormente. Muitas das vezes a classe era definida e instanciada no momento da passagem do parâmetro usando-se a técnica das "anonymous inner classes". Em JAVA os argumentos de um método são passados por valor pelo que são calculados no momento da invocação do método.

Porém, o que se pretende muitas vezes é passar um pedaço de código que seja apenas avaliado no momento e no contexto da sua utilização. Com métodos tal é impossível mas passou a ser possível em JAVA 8 porque as expressões lambda (e as funções identificadas) podem ser passadas como parâmetros de métodos de forma literal, ou seja, sem serem nesse momento avaliadas, e sendo-o apenas aquando da sua efetiva utilização ou invocação. Assim, as expressões lambda e as funções representam comportamento (ou funcionalidade) que está encapsulado nessa construção ("code as data" tal como por exemplo em C), que pode ser passado como parâmetro e produzir o seu resultado apenas aquando da sua efetiva invocação. O resultado de uma função poderá ser um valor de um tipo simples, um objeto ou até uma função.

As funções, anónimas ou não, dado representarem comportamento que pode ser de forma simples passado como parâmetro e dado todas as operações que podem ser realizadas com elas (cf. composição de funções, etc.) são construções fundamentais em JAVA 8, e correspondem a uma "modernização atrasada" de JAVA tendo em atenção que já existiam em C#, Ruby, Scala e Python, sendo estas duas últimas executáveis na JVM.

 O que são as Functional Interfaces de JAVA 8?

As Interfaces de JAVA são, desde o seu início, definições sintáticas de tipos, que, até JAVA 8, podiam apenas conter declarações de constantes e de métodos abstratos. As Interfaces fazem, desde JAVA 5, parte do sistema de tipos de JAVA, sendo o seu bytecode guardado num ficheiro .class, tal como as classes. As Interfaces de JAVA 8 podem também conter métodos completamente codificados, designados "default methods", que serão herdados pelas classes que implementam a interface ou por subinterfaces desta.

Do ponto de vista exclusivamente sintático as Functional Interfaces são normais Interfaces de JAVA mas que têm a propriedade particular de definirem apenas um método abstrato, sendo tal propriedade verificada pelo compilador se o programador usar a anotação @FunctionalInterface antes da sua definição. Porém, JAVA 5 já tinha interfaces com esta propriedade, as designadas SAM interfaces ("single abstract method interfaces") ou "callback interfaces", que declaram os designados SAM types. São exemplos destas as interfaces Runnable, Comparator<T> e outras, que, por possuírem apenas um método abstrato passam agora a designar-se também por Functional Interfaces.

Porém, as Interfaces Funcionais de JAVA 8 são muito mais do que isto. Todas elas representam os tipos estáticos (para o compilador portanto) das funções que o programador pode criar e que as expressões lambda de JAVA 8 implementam. Em síntese o tipo de uma função ou de uma expressão lambda é uma Interface Funcional e tal significa que não foi necessário modificar o sistema de tipos de JAVA para acomodar as funções e as expressões lambda introduzidas em JAVA 8, o que é  extremamente relevante.

Assim, a partir de JAVA 8, todas as interfaces que especificam um só método abstrato designam-se por interfaces funcionais (Functional Interfaces) e podem ser implementadas pelas expressões lambda que são muito simples de escrever. Desta forma, e porque interfaces são tipos, funções e expressões lambda podem ser passadas como parâmetros de métodos, que passam em JAVA 8 a poder aceitar como argumentos valores, objetos, funções, expressões lambda e referências a métodos. A biblioteca java.util.function oferece mais de 50 tipos pré-definidos para as funções e expressões lambda, ou seja, mais de 50 interfaces funcionais utilizáveis pelo programador no seu código.


Porquê estas mudanças em JAVA 8 e quais as vantagens?

Todas as mudanças anteriormente referidas têm mais de 10 anos de atraso. Eram para ser feitas na versão JAVA 5, de 2004, mas não foi possível por razões técnicas. Não ter construções funcionais e, como consequência, não poder explorar a capacidade de processamento paralelo das mais diversas máquinas "multi-core" atualmente existentes quase levava JAVA à extinção. Assim, JAVA 8 veio trazer a JAVA a simplicidade da expressão declarativa dada pelas construções funcionais aliada à melhoria de performance subjacente ao paralelismo de processamento. Era crucial para a tecnologia JAVA.

 O que é que o atrai mais nesta linguagem de programação?

Leciono e programo em JAVA desde os finais dos anos 90 quando após 10 anos a lecionar POO em Smalltalk decidir introduzir JAVA. Na altura, pragmaticamente, ou escolhia C++ ou JAVA. Escolhi então JAVA por várias razões. Acompanhei as diversas evoluções da linguagem JAVA e das suas plataformas de desenvolvimento de software e respetivas tecnologias. A plataforma JSE (JAVA Standard Edition) em JAVA 2 tinha 59 bibliotecas e 1520 classes. JAVA 5, que foi a primeira grande modificação da linguagem, passou a ser fortemente tipada e foram introduzidos os Tipos Genéricos (Generics) e desenvolvidas as Coleções (JCF), e JSE5 tinha 166 bibliotecas e 3293 classes. Agora, com as novas construções e APIs, JSE8 tem 217 bibliotecas e 4240 classes.

O que mais me atrai em JAVA é, antes de mais, suportar a conceção OO. A sintaxe tem heranças pesadas de C e de C++, tais como a keyword "static" e outras, mas com regras de estilo precisas e agora com as construções funcionais podemos escrever programas muito "disciplinados", claros e com performance estável e melhorada. Adicionalmente atraem-me as suas plataformas JSE e JEE (JAVA Enterprise Edition), com as suas bibliotecas, bem como todo um enorme conjunto de tecnologias disponíveis para as mais diversas áreas aplicacionais atuais (negócios, web, jogos, interfaces gráficas, dispositivos móveis, etc.) em diferentes plataformas e dispositivos.

Considera que o seu livro “JAVA 8 – POO + Construções Funcionais” é uma boa ferramenta, tanto para aqueles que se iniciam no paradigma da POO como para aqueles mais experientes em JAVA?

Este livro tem, em comparação com outros, a virtude de explicar antes de mais todos os conceitos fundamentais da POO e não apenas JAVA. Estes conceitos, quando adquiridos, podem ser  implementados em qualquer linguagem OO. Porém, neste caso, o objetivo é ensinar como se implementa uma conceção OO usando as construções da linguagem JAVA e, em particular, JAVA 8. Quanto ao ensino de JAVA 8, o livro vai das construções mais simples às mais completas construções do núcleo da linguagem, daí a sua extensão. Por causa da sua extensão, e relativamente ao meu livro anterior de JAVA 6, não foi possível incluir o capítulo sobre Tipos Genéricos.

Assim, para os que se iniciam na POO e em JAVA o livro é completo e deve ser lido em sequência do princípio ao fim. Para os mais experientes em JAVA contém todas as novidades de JAVA 8 que, depois de estudadas e exploradas, farão com que passem a programar em JAVA de uma forma completamente diferente, tendo-se mesmo a sensação de que se está a programar numa nova linguagem. Esta nova forma de programar em JAVA, em especial com Coleções, designa-se por "programação horizontal" ou "pipeline programming", e, apesar de conduzir a código extremamente compacto, é de uma enorme clareza semântica.


O Prof. Mário Martins é uma das maiores referências em JAVA a nível nacional e pude constatar que os seus alunos lhe têm grande estima e consideração. O ensino e a programação são duas das suas paixões?

Pertenço a uma geração que se licenciou em Engenharia Eletrotécnica ou algo parecido, aí pelos anos 70. Estudámos e usámos os primeiros sistemas digitais, assistimos ao aparecimento dos microprocessadores e programámos os primeiros computadores sem sistema operativo e introduzindo os 0 e 1 ligando ou desligando interruptores e, mais tarde, usando consolas básicas.

Para os que como eu lecionaram as mais diversas linguagens de programação que iam aparecendo, as mais diversas metodologias de desenvolvimento, as mais rigorosas regras da Engenharia de Software, as mais diversas tecnologias, etc., a vista é muito mas muito panorâmica. E é muito agradável, ao iniciar os 38 anos de ensino destas matérias, ter assistido a todo este desenvolvimento e ainda fazer parte dele.

A Engenharia de Software e o seu ensino nas mais diversas vertentes é o que ainda me cativa. Gosto de lecionar e tento sempre que os meus alunos saibam muito. Nas dedicatórias dos meus livros refiro sempre os meus alunos, ainda que eles sejam os meus piores clientes já que lhes dou sempre apontamentos. Eles, na sua maioria, reconhecem o meu esforço e dedicação e retribuem com a sua estima e consideração, o que me satisfaz muito.

E é tudo, o nosso obrigado pelo tempo dispensado, e ficamos aguardar pelos seus próximos livros. :)


Fernando Mário Martins
Professor Associado do Departamento de Informática da Universidade do Minho (DI/UM). Criou e presidiu o Centro de Competência da JAVA do DI/UM – Sun Portugal. Desde 1980 leciona disciplinas de linguagens imperativas e funcionais, tendo introduzido a POO na UM usando Smalltalk. Nos anos 1990 iniciou o ensino de JAVA na UM, tendo lecionado em diversos cursos disciplinas das áreas de POO usando JAVA, Modelação Orientada por Objetos usando UML e Tecnologias JAVA Web. Foi presidente do Colégio de Informática da Região Norte da Ordem dos Engenheiros e avaliador de Cursos de Informática pela Ordem dos Engenheiros. Foi também membro do Júri da FCT no painel de avaliação de candidaturas a programas de Doutoramento e Pós-Doutoramento em Engenharia Informática. É autor dos livros Projetos de POO em JAVA e JAVA6 e Programação Orientada pelos Objectos, também editados pela FCA.




Para quem chegou até aqui, temos uma surpresa. Temos para oferecer dois exemplares do livro "JAVA 8 - POO + Construções Funcionais" e para te habilitares a ganhar um deles só tens que participar preenchendo o seguinte formulário:

Passatempo encerrado: os vencedores foram:

  • Rui Neiva
  • Tânia Rocha

Fica atento aos próximos passatempos.

2 comentários:

  1. Foi meu professor na Universidade do Minho! Aprendi a programar em Java 5 com ele por volta de 2007/2008!

    ResponderEliminar
  2. Grande estima e consideração? Cuidado com o que dizem! Mentir é feio! Talvez se fossem a apresentações de trabalhos com este senhor mudassem de opinião...

    ResponderEliminar

[pub]