Ybadoo - Soluções em Software Livre
Turmas
1º Semestre de 2020

Questão 01

Como as instruções de declaração de tipo para variáveis simples afetam a legibilidade de uma linguagem, considerando que algumas linguagens não as exigem? Apresente exemplos de código para justificar sua resposta, que deverá conter no mínimo 300 palavras e no máximo 1.000 palavras.

Em muitas situações, o nome da variável pode não fornecer subsídios suficientes para auxiliar o programador na identificação do tipo de valor armazenado pela variável. Por exemplo, a variável responsável pelo armazenamento do Cadastro de Pessoas Físicas, nomeada CPF armazena qual tipo de valor?

Se o valor do CPF for obtido de uma interface gráfica, provavelmente o tipo da variável será um valor textual, como em 123.456.789-01, pois na maioria das linguagens de programação, entradas fornecidas pelos usuários são disponibilizadas ao programador no formato textual.

Se o valor do CPF for obtido de um banco de dados, provavelmente o tipo da variável será um valor numérico, como em 12345678901, pois é mais eficiente armazenar essa informação no formato numérico do que no formato textual.

Utilizando uma linguagem de programação com declaração de tipos para suas variáveis, como a linguagem de programação Java, o programador facilmente identifica o tipo de valor armazenado pela variável, como em

String cpf; // Valor textual

ou

long cpf; // Valor numérico

Utilizando uma linguagem de programação sem declaração de tipos para suas variáveis, como a linguagem de programação PHP, a identificação do tipo de valor armazenado pela variável se torna mais complexa para o programador, como em

$cpf = $_POST["cpf"];

O presente comando não fornece nenhuma informação sobre o tipo de valor armazenado pela variável $cpf, que pode ser tanto um valor textual como um valor numérico. Nesse caso, o tipo de valor da variável é descoberto analisando o código-fonte, o que exige um esforço mental maior do que simplesmente ler na própria definição da variável o seu tipo.

Para contornar esse problema, alguns programadores utilizam a notação húngara na nomeação de suas variáveis, adicionando um prefixo aos nomes das variáveis para indicar o tipo das mesmas, como em

$s_cpf; // Valor textual

ou

$n_cpf; // Valor numérico

Com o aparecimento dos Ambientes Integrados de Desenvolvimento (IDE) modernos, a notação húngara foi praticamente abolida da codificação de programas em linguagens de programação com declaração de tipos para suas variáveis, pois em qualquer parte do código-fonte é apresentado ao programador o tipo da variável, além de avisarem em tempo real possíveis erros de conversão entre as variáveis.

Codificar informações de tipos em nomes simplesmente adiciona uma tarefa extra de decodificação, acarretando numa sobrecarga mental desnecessária ao se tentar resolver um problema. Ademais, nomes codificados raramente são pronunciáveis e são fáceis de serem erroneamente escritos (Martin, 2011).

Questão 02

Escreva uma instrução de atribuição simples com um operador aritmético em alguma linguagem que você conheça. Para cada componente da instrução, liste as várias vinculações que são necessárias para determinar a semântica quando a instrução é executada. Para cada vinculação, indique o tempo de vinculação usada para a linguagem.

Considere o seguinte código, escrito na linguagem de programa Java.

int a = 0;
int b = a + 1;

Conjunto dos tipos possíveis para as variáveis a e b: vinculado no tempo de projeto da linguagem de programação. Em Java, o programador tem a sua disposição os tipos primitivos byte, short, int, long, float, double, char e boolean.

Os tipo das variáveis a e b: vinculado no tempo de compilação, quando o compilador Java associa o tipo int as variáveis a e b.

Conjunto de valores possíveis para as variáveis a e b: vinculado no tempo de implementação da linguagem. Em Java, o tipo int permite valores entre -2.147.483.648 e 2.147.483.647.

Os valor das variáveis a e b: vinculado no tempo de execução, com a execução da presente instrução é executada pela Java Virtual Machine (JVM).

Conjunto dos significados possíveis para o símbolo do operador +: vinculado no tempo de projeto da linguagem de programação. Em Java, o operador + pode possuir dois significados distintos: a) operador aritmético de adição e b) operador de concatenação de textos.

O significado do operador + nessa instrução: vinculado no tempo de compilação, quando o compilador identifica que os operandos do operador + são numéricos, associando ao operador + o significado de operador aritmético de adição.

Representação interna dos literais 0 e 1: vinculada no tempo de implementação da linguagem de programação Java.

Questão 03

Escreva uma breve discussão daquilo que foi ganho e daquilo que foi perdido na decisão dos projetistas do Java de não incluírem os ponteiros do C++. Apresente exemplos de código para justificar sua resposta, que deverá conter no mínimo 300 palavras e no máximo 1.000 palavras.

Ponteiros e referências são conceitualmente muito parecidos, pois ambos armazenam um endereço de memória, mas a forma como trabalham com o endereço de memória é completamente diferente em ambos os tipos de dados.

Ponteiros trabalham com o endereço de memória da mesma forma como tipos inteiros trabalham com os seus valores, ou seja, permitem que o programa realize operações sobre os mesmos e validam apenas se o valor resultante (endereço de memória) está dentro da faixa de valores permitido, mas não verificam se o endereço de memória realmente contem algum valor válido.

Por exemplo, na linguagem de programação C++ é completamente possível e válido realizar a seguinte operação sobre ponteiros.

int a = 10;
int *ptr = &a;
*(ptr + 5) = 7;

Nesse exemplo, o valor 7 não será atribuído a variável a, mas a cinco posições adiante, onde provavelmente alterará o valor de outra variável.

Referências basicamente são um ponteiro de constante que é sempre implicitamente valorado, ou seja, sempre possuirá um endereço de memória válido. No caso da linguagem de programação Java, as referências sempre referem-se a instâncias de classes, de modo que não faz sentido a realização de operações aritméticas sobre as mesmas, como apresentado a seguir.

Integer a = 10;
Integer b = a;
b = 7;

Nesse exemplo, as variáveis a e b são instâncias da classe Integer. Inicialmente, ambas as variáveis apontam para o endereço de memória que armazena o valor 10, e quando a variável b recebe o valor 7, a variável b deixa de referenciar o endereço de memória que armazena o valor 10 e passa a referenciar o endereço de memória que armazena o valor 7, não alterando o endereço de memória referenciado pela variável a.

Dessa forma, o principal ganho obtido pela linguagem de programação Java sobre a linguagem de programação C++ é a segurança proporcionada pela utilização das referências em detrimento da utilização de ponteiros. Em Java, o programador não consegue induzir o computador a acessar uma posição indevida de memória, como seria possível em C++.

Os projetistas da linguagem de programação Java conseguiram substituir integralmente os ponteiros da linguagem de programação C++ com a utilização das referências, garantindo a construção de sistemas mais seguros e confiáveis.

Uma desvantagem da ausência de ponteiros em Java seria na construção de drivers, onde é exigido o acesso a certas posições de memória para que a tarefa seja realizada, mas a linguagem de programação Java não foi desenvolvida para a construção de aplicações de baixo nível.

Questão 04

Escreva um programa de teste em sua linguagem favorita que determine e apresente como resultado a precedência e a associatividade de seus operadores aritméticos e booleanos.

O seguinte programa foi escrito na linguagem de programação Java.

public class Teste
{
public int a = 10;
public int b = 20;
public int c = 30;
public boolean x = true;
public boolean y = false;
public boolean z = false;

public int funA()
{
b = 10;
System.out.println("Valor de a: " + a);
return a;
}

public int funB()
{
c = 15;
System.out.println("Valor de b: " + b);
return b;
}

public int funC()
{
a = 15;
System.out.println("Valor de c: " + c);
return c;
}

public boolean funX()
{
y = true;
return x;
}

public boolean funY()
{
z = true;
return y;
}

public boolean funZ()
{
x = false;
return z;
}

public static void main(String[] args)
{
Teste t = new Teste();

System.out.println("Precedência dos operadores aritméticos:");
System.out.println("a + b * c - c / a = " + (t.a + t.b * t.c - t.c / t.a));

System.out.println("Associatividade dos operadores aritméticos:");
System.out.println("funA() + funB() + funC() = " + (t.funA() + t.funB() + t.funC()));

System.out.println("Precedência dos operadores lógicos:");
System.out.println("x | y & z ^ x = " + (t.x | t.y & t.z ^ t.x));

System.out.println("Associatividade dos operadores lógicos:");
System.out.println("funX() & funY() & funZ() = " + (t.funX() & t.funY() & t.funZ()));
}
}

Resultado obtido com a execução do programa.

Precedência dos operadores aritméticos:
a + b * c - c / a = 607
Associatividade dos operadores aritméticos:
Valor de a: 10
Valor de b: 10
Valor de c: 15
funA() + funB() + funC() = 35
Precedência dos operadores lógicos:
x | y & z ^ x = true
Associatividade dos operadores lógicos:
funX() & funY() & funZ() = true

Explicando os resultados obtidos.

Pela especificação da linguagem de programação Java, a precedência dos operadores aritméticos é multiplicação (*), divisão (/) ou módulo (%) para depois realizar os operadores de adição (+) ou subtração (-), como pode ser observado no resultado obtido.

a + b * c - c / a
10 + 20 * 30 - 30 / 10
10 + 600 - 30 / 10
10 + 600 - 3
610 - 3
607

Pela especificação da linguagem de programação Java, a associatividade dos operadores aritméticos é da esquerda para a direita, como pode ser observado no resultado obtido.

{a = 10, b = 20, c = 30} → funA() + funB() + funC()
{a = 10, b = 10, c = 30} → 10 + funB() + funC() // valor de b alterado por funA()
{a = 10, b = 10, c = 15} → 10 + 10 + funC() // valor de c alterado por funB()
{a = 5, b = 10, c = 15} → 10 + 10 + 15 // valor de a alterado por funC()
35

Pela especificação da linguagem de programação Java, a precedência dos operadores lógicos é o AND (&), seguido do XOR (^) e finalmente o OR (|), como pode ser observado no resultado obtido.

x | y & z ^ x
true | false & false ^ true
true | false ^ true
true | false
true

Pela especificação da linguagem de programação Java, a associatividade dos operadores lógicos é da esquerda para a direita, como pode ser observado no resultado obtido.

{x = true, y = false, z = false} → funX() & funY() & funZ()
{x = true, y = true, z = false} → true & funY() & funZ() // valor de y alterado por funX()
{x = true, y = true, z = true} → true & true & funZ() // valor de z alterado por funY()
{x = false, y = true, z = true} → true & true & true // valor de x alterado por funZ()
true