A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

7-1 8 Sistemas de Tipos Polimorfismo de inclusão. Polimorfismo paramétrico. Sobrecarga. Conversões de tipos. Notas de implementação.

Apresentações semelhantes


Apresentação em tema: "7-1 8 Sistemas de Tipos Polimorfismo de inclusão. Polimorfismo paramétrico. Sobrecarga. Conversões de tipos. Notas de implementação."— Transcrição da apresentação:

1 7-1 8 Sistemas de Tipos Polimorfismo de inclusão. Polimorfismo paramétrico. Sobrecarga. Conversões de tipos. Notas de implementação.

2 7-2 Polimorfismo de inclusão (1) Polimorfismo de inclusão é um sistema de tipo no qual um tipo pode ter subtipos, que herdam as operações daquele tipo Conceito-chave das linguagem orientadas a objetos Tipos e subtipos Um tipo T é um conjunto de valores equipado com operações Um subtipo de T é um subconjunto dos valores de T equipado com as mesmas operações de T –Todo valor do subtipo também é valor do tipo T, podendo ser usado no contexto onde um valor do tipo T é esperado –O conceito de subtipos é uma idéia útil e comum em programação

3 7-3 Exemplo: tipos primitivos e subtipos em Ada Declarações em Ada definindo subtipos de Integer subtype Natural is Integer range 0.. Integer'last; subtype Small is Integer range ; Conjuntos de valores correspondentes – Natural = {0, 1, 2, 3, 4, 5, 6,...} Small = {-3, -2, -1, 0, +1, +2, +3} Variáveis – i: Integer; n: Natural; s: Small; i := n; i := s; n := i; n := s; s := i; s := n: Requer verificação em tempo de execução

4 7-4 Exemplo: tipos e subtipo de registros discriminados em Ada (1) Declaração de registro discriminado em Ada type Form is (pointy, circular, rectangular); type Figure (f: Form := pointy) is record x, y: Float; case f is when pointy => null; when circular => r: Float; when rectangular => h, w: Float; end case; end record; subtype Point is Figure(pointy); subtype Circle is Figure(circular); subtype Rectangle is Figure(rectangular); Conjuntos de valores – Form = {pointy, circular, rectangular} Figure = pointy(Float Float) + circular(Float Float Float) + rectangular(Float Float Float Float)

5 7-5 Exemplo: tipos e subtipo de registros discriminados em Ada (2) Conjunto de valores dos subtipos – Point = pointy(Float Float) Circle = circular(Float Float Float) Rectangle = rectangular(Float Float Float Float) Exemplos de variáveis diagram: array (...) of Figure; frame: Rectangle; cursor: Point;

6 7-6 Polimorfismo de inclusão (2) Em linguagens de programação que suportam subtipos, não é possível estabelecer univocamente o subtipo de um valor Propriedades gerais dos subtipos Condição necessária para S ser um subtipo de T: S T O tipo T é equipado com operações que são aplicáveis a todos os valores do tipo T Todas essas operações também serão aplicáveis aos valores do subtipo S – S herda as perações de T

7 7-7 Polimorfismo de inclusão (3) Compatibilidade de tipos na presença de subtipos V := E T 1 é compatível com T 2 se e somente se T 1 e T 2 têm valores em comum –Ou T 1 é um subtipo de T 2 ou T 2 é um subtipo de T 1 ou T 1 e T 2 são subtipos de outro tipo qualquer Casos de interesse quando T 1 e T 2 são compatíveis –T 1 é um subtipo de T 2 : T 1 pode ser usado com segurança num contexto onde um valor de T 2 é esperado – não precisa de verificação em tempo de execução –T 1 não é um subtipo de T 2 : valores do tipo T 1 somente podem ser usados após verificação em tempo de execução para determinar se ele também é um valor do tipo T 2 tipo = T 1 tipo = T 2

8 7-8 Classes e subclasses Uma classe C é um conjunto de objetos equipados com operações Cada objeto da classe C tem uma ou mais variáveis componentes e está equipada com métodos que acessam essas variáveis Cada objeto de uma subclasse S de C herda todas as variáveis componentes dos objetos da classe C, podendo ter variáveis componentes adicionais Cada objeto da classe S potencialmente herda todos os métodos dos objetos da classe C e pode ser equipada com métodos adicionais para acessar tais variáveis Qualquer objeto de uma subclasse pode ser usado no contexto onde um objeto da classe C é esperado Subclasses não são o mesmo que subtipos em geral

9 7-9 Exemplo: subclasses de Java como subtipos (1) Considere as classes class Point { protected double x, y; public void draw () {...} } class Circle extends Point { private double r; public void draw () {...} } class Rectangle extends Point { private double w, h; public void draw () {...} }

10 7-10 Exemplo: subclasses de Java como subtipos (2) Conjuntos de valores das classes – Point = Point(Double Double) Circle = Circle(Double Double Double) Rectangle = Rectangle(Double Double Double Double) Nota-se que Circle e Rectangle não são subtipos de Point Mas são subtipos do tipo Point$ abaixo – Point$ = Point(Double Double) + Circle(Double Double Double) + Rectangle(Double Double Double Double) Point$

11 7-11 Exemplo: subclasses de Java como subtipos (3) Java permite que objetos de qualquer subclasse sejam tratados como objetos da superclasse Point p;... p= new Point(3.0, 4.0);... p= new Circle(3.0, 4.0, 5.0); –Variáveis do classe Point podem referenciar quaisquer valores do tipo Point$ Em geral, se C é uma classe, então C$ inclui não apenas os objetos da classe C, mas também os objetos de todas as subclasses de C –C$ é denominada de tipo de classe estendido (class-wide type)

12 7-12 Exemplo: extensibilidade em Java (1) Sejam as declarações considerando o exemplo anterior class Line extends Point { private double length, orientation; public void draw () {... } } class Textbox extends Rectangle { private String text; public void draw () {... } } As definições acima não apenas definem os conjuntos de objetos das novas classes – Line = Line(Double Double Double) Textbox = Textbox(Double Double String)

13 7-13 Exemplo: extensibilidade em Java (2) como também definem os tipos de classe estendidos abaixo – Point$ = Point(Double Double) + Circle(Double Double Double) + Rectangle(Double Double Double Double) + Line(Double Double Double) + Textbox(Double Double String) – Rectangle$ = Rectangle(Double Double Double Double) + Textbox(Double Double String)

14 7-14 Polimorfismo paramétrico (1) Polimorfismo paramétrico é um sistema de tipos que permite que se escrevam procedimentos polimórficos Um procedimento polimórfico é aquele que pode operar uniformemente sobre argumentos de toda uma família de tipos Um procedimento monomórfico é aquele que somente pode operar sobre argumentos de um tipo fixo –Uma função que computar o tamanho de uma lista de caracteres não pode ser aplicada a listas de inteiros, por exemplo

15 7-15 Polimorfismo paramétrico (2) Procedimentos polimórficos Suportado naturalmente em Haskell –Basta que se declare o tipo da função utilizando variáveis de tipo, em vez de tipos específicos Uma variável de tipo é um identificador que denota um tipo de uma família de tipos »Letras romanas minúsculas em Haskell »Letras gregas nos exemplos do livro-texto (,,,...)

16 7-16 Exemplo: função polimórfica em Haskell (1) Função monomórfica em Haskell second (x: Int, y: Int) = y Tipo da função – Integer Integer Integer – second(13, 21) resulta no valor 21, mas a chamada second(13, true) é ilegal, pois os tipos não casam A versão polimórfica desta função resolve este problema second (x:, y: ) = y Tipo da função – – e são variáveis de tipo, cada uma representação de um tipo arbitrário

17 7-17 Exemplo: função polimórfica em Haskell (2) Agora, a chamada da função abaixo é legal – second(13, true) resulta no valor true –O tipo da função determinado pelo casamento de tipos é o seguinte Integer e Boolean Substituíndo ambos no tipo, tem-se o tipo resultante da aplicação da função Integer Boolean Boolean Esta função polimórfica aceitas argumentos de muitos tipos, mas não quaisquer argumentos Apenas pares da forma As chamadas abaixo são ilegais – second(13) – second(1978, 5, 5)

18 7-18 Polimorfismo paramétrico (3) Um politipo deriva uma família de tipos e sempre possui uma ou mais variáveis de tipo e são exemplos de politipos Politipos derivam uma família de tipos pela substituição sistemática das variáveis de tipo por tipos –A família de tipos derivada por, incluem Integer Boolean Boolean String String String –mas não incluem Integer Boolean Integer Integer Integer String String String String

19 7-19 Exemplo: função polimórfica em Haskell Considere a seguinte função monomórfica em Haskell either (b: Bool) (x1: Char) (x2: Char) = if b then x1 else x2 O tipo dessa função é Boolean Character Character Character translate (x: Char) = either (isspace x) x '*' Nota-se que o tipo do primeiro argumento deve ser Boolean, mas os tipos do segundo e terceiro argumentos não precisão ser! either (b: Bool) (x1: ) (x2: ) = if b then x1 else x2 O tipo da função para Boolean translate (x: Char) = either (isspace x) x '*' max (m: Int, n: Int) = either (m > n) m n' Aplicação legal da função either

20 7-20 Tipos parametrizados Um tipo parametrizado é um tipo que toma outros tipos como parâmetros Pode-se imaginar o [] como um tipo parametrizado de C, que pode ser especializado num tipo ordinário, como char[], ou float[], ou float[][], pela substituição da variável por um tipo real Todas as linguagens de programação têm tipos parametrizados pré- definidos –C, C++ e Java têm [] –Ada tem array ( ) of e access Poucas linguagens de programação, como ML e Haskell permitem que o programador defina seus próprios tipos parametrizados

21 7-21 Exemplo: tipo parametrizado em Haskell Definição de um tipo de pares homogêneos type Pair τ =(τ, τ) τ é um parâmetro do tipo e denota um tipo arbitrário Uma especialização deste tipo poderia ser – Pair Int –com o tipo resultante Integer Integer, ou seja valores pares de números inteiros –ou – Pair Float –com o tipo resultante Real Real, ou seja valores pares de números reais

22 7-22 Exemplo: tipo parametrizado recursivo em Haskell Definição de listas homogêneas data List = Nil | Cons (, List ) Agora, List Int é um tipo cujos valores são listas de inteiros head (l: List )= case l of Nil -> error Cons(x,xs) -> x tail (l: List )= case l of Nil -> error Cons(x,xs) -> xs length (l: List )= case l of Nil -> 0 Cons(x,xs) -> 1 + length(xs) List = Unit + ( List ) head : List tail : List List length: List Integer

23 7-23 Inferência de tipos A maioria das linguagens estaticamente tipadas requerem que o programador declare explicitamente os tipos usados em toda entidade declarada num programa I: constant T := E; I: T; function I (I': T') return T; Em Haskell, os tipos não precisam ser explicitados – são inferidos do contexto Inferência de tipos é um processo pelo qual o tipo de uma entidade declarada é inferido, quando não foi explicitamente estabelecido

24 7-24 Exemplo: inferência de tipos monomórficos em Haskell Considere a seguinte definição de função even n = (n 'mod' 2 = 0) Sabe-se que o operador mod tem tipo Integer Integer Integer A partir da subexpressão n 'mod' 2 pode-se inferir que o tipo de n é Integer De forma similar, pode-se inferir que o corpo da função tem o tipo Boolean Logo, a função even tem o monotipo Integer Boolean Nem sempre pode inferir um monotipo!

25 7-25 Exemplo: inferência de tipos polimórficos em Haskell Considere a seguinte função f. g = \x -> f(g(x)) Nota-se que f e g são funções, que o tipo resultante de g deve ser o mesmo tipo do parâmetro de f, mas nada se pode inferir que tipo é este, ele é um politipo qualquer Nada se pode afirmar dos tipos do parâmetro de g e do valor resultante de f, que podem ser diferentes, eles podem ter os politipos e, respectivamente Neste caso, o tipo de x obrigatoriamente é Logo, o tipo da função acima é – ( ) ( ) ( )

26 7-26 Sobrecarga (1) Um identificador está sobrecarregado se ele denota dois ou mais procedimentos num mesmo escopo Aceitável apenas quando a chamada do procedimento pode ser feita sem ambigüidade Pode ser definida pelo programador em Java, C++, Ada, dentre outras linguagens

27 7-27 Exemplo: funções sobrecarregadas em C O operador "–" em C denota simultaneamente quatro funções pré-definidas Negação de inteiros (função com tipo Integer Integer ) Negação de ponto-flutuante (função com tipo Float Float ) Subtração de inteiro (função com tipo Integer Integer Integer ) Subtração de ponto-flutuante (função com tipo Float Float Float ) Nota-se que não há ambigüidade, pois o número e os tipos dos operandos determinam a função a chamar

28 7-28 Exemplo: funções sobrecarregadas em Ada O operador " / " denota duas funções pré-definidas em Ada Divisão de inteiros (função com tipo Integer Integer Integer ) Divisão de ponto-flutuante (função com tipo Float Float Float ) Pode-se declarar a função sobrecarregada abaixo function "/" (m, n: Integer) return Float; -- Return the quotient of m and n as a real number. cujo tipo é (função com tipo Integer Integer Float ) Neste caso, a função a chamar vai depender do contexto onde é aplicada e não apenas dos parâmetros reais n: Integer; x: Float;... x := 7.0/2.0;- computes 7.0/2.0 = 3.5 x := 7/2; - computes 7/2 = 3.5 n := 7/2;- computes 7/2 = 3 n := (7/2)/(5/2); - computes (7/2)/(5/2) = 3/2 = 1 Algumas chamadas são ambíguas e ilegais – x := (7/2)/(5/2); - computes (7/2)/(5/2) = 3/2 = 1.5 ou (7/2)/(5/2) = 3.5/2.5 = 1.5

29 7-29 Sobrecarga (2) Suponha um identificador F denotando simultaneamente duas funções f 1 : S 1 T 1 e f 2 : S 2 T 2 Sobrecarga independente de contexto: requer que S 1 e S 2 sejam não equivalentes –A função a ser chamada sempre pode ser univocamente identificada pelo tipo do parâmetro real Sobrecarga dependente de contexto: requer apenas que S 1 e S 2 sejam não equivalentes ou que T 1 e T 2 sejam não equivalentes –Quando S 1 e S 2 são equivalentes, o contexto onde o F é utilizado deve ser levado em conta para identificar a função a ser chamada –Possibilita a formulação de expressões nas quais a função a ser chamada não pode ser determinada univocamente – tais construções ambíguas devem ser proibidas

30 7-30 Sobrecarga (3) Advertência! Não confundir sobrecarga – também conhecido como polimorfismo ad hoc – com polimorfismo paramétrico –A sobrecarga não aumenta o poder de expressividade da linguagem de programação, visto que a quantidade de funções sobrecarregadas sempre é limitada –Por outro lado, o polimorfismo paramétrico permite que um procedimento opere sobre um número potencialmente ilimitado de variedade de tipos

31 7-31 Conversão de tipos (1) Uma conversão de tipos é um mapeamento de valores de um tipo para valores correspondentes de outro tipo Exemplos: – Mapeamento natural de números inteiros para reais {..., 2 2.0, 1 1.0, 0 0.0, , ,...} –Truncamento e o arredondamento são opções de conversão de tipos de real para inteiros –Mapeamento de caracteres para strings de tamanho 1

32 7-32 Conversão de tipos (2) Conversões de tipos podem ser mapeamentos totais Caracteres para códigos de caracteres, inteiros para reais,... Conversões de tipos podem ser mapeamentos parciais Códigos de caracteres para caracteres, reais para inteiros,... Mapeamentos parciais podem provocar falhas em programas

33 7-33 Conversão de tipos (3) Conversões de tipos podem ser explícitas ou implícitas Um cast é uma conversão de tipos explícita –Em C, C++ e Java, um cast tem a forma (T)E –Em Ada e em Object Pascal, um cast tem a forma T(E) Caso a subexpressão E é do tipo S – não equivalente a T – e se a linguagem de programação define uma conversão de tipo de S para T, então o cast mapeia o valor de E para o valor correspondente de T Uma coerção é uma conversão de tipos implícita, realizada automaticamente sempre que o contexto sintático exigir –Considere a expressão E no contexto do tipo T Se o tipo de E é S – não equivalente a T – e se a linguagem permite a coerção de S para T nesse contexto, então a coerção mapeia o valor de E para o valor correspondente de T

34 7-34 Exemplo: coerções e Pascal e casts em Ada Pascal var n: Integer; x : Real;... x := n;-- converte o valor de n para um número real n := x;-- ilegal! n := round(x)-- converte o valor de x para um inteiro por arredondamento Ada Ada não prover nenhum tipo de coerção n: Integer; x : Float;... x := n;-- ilegal! n := x;-- ilegal! x := Float(n)-- converte o valor de n para um número real n := Integer(x)-- converte o valor de x para um inteiro por arredondamento Algumas linguagens de programação são muitos permissivas em relação às coerções, e. g. C, Java A tendência é reduzir ou mesmo eliminar coerções nas linguagens de programação mais modernas

35 7-35 Notas de Implementação (1) Implementação do polimorfismo paramétrico Procedimento polimórficos operam uniformemente sobre argumento de uma família de tipos Opções de implementação –Gera uma instância separada de procedimento para cada tipo distinto de argumento Inviável na prática! –Representar os valores de todos os tipos de tal modo que eles pareçam similar para o procedimento polimórfico Representar cada valor através de um apontador para o objeto na memória heap

36 7-36 Notas de Implementação (2) Considere as funções polimórficas Estas funções somente copia valores do tipo e isto é implementado copiando-se os ponteiros para estes valores – either: Boolean – second: – head : List Esta implementação de funções paramétricas é simples e uniforme, porém de alto custo –Todos os valores – incluindo valores primitivos – devem ser armazenados na memória heap e acessados através de apontadores –Espaço na memória deve ser alocado quando eles são usados da primeira vez e desalocado pelo gerenciador de memória quando não são mais necessários


Carregar ppt "7-1 8 Sistemas de Tipos Polimorfismo de inclusão. Polimorfismo paramétrico. Sobrecarga. Conversões de tipos. Notas de implementação."

Apresentações semelhantes


Anúncios Google