Sistema de Objeto Lisp Comum - Common Lisp Object System

Combinação de método padrão em ANSI lisp comum

O Common Lisp Object System (CLOS) é o recurso de programação orientada a objetos que faz parte do ANSI Common Lisp . CLOS é um sistema de objeto dinâmico poderoso que difere radicalmente dos recursos OOP encontrados em linguagens mais estáticas , como C ++ ou Java . CLOS foi inspirado por sistemas de objetos Lisp anteriores, como MIT Flavors e CommonLoops , embora seja mais geral do que qualquer um deles. Originalmente proposto como um add-on, CLOS foi adotado como parte do padrão ANSI para Common Lisp e foi adaptado para outros dialetos Lisp, como EuLisp ou Emacs Lisp .

Características

Os blocos de construção básicos do CLOS são métodos , classes , instâncias dessas classes e funções genéricas . CLOS fornece macros para definir os: defclass, defmethod, e defgeneric. As instâncias são criadas com o método make-instance.

As classes podem ter várias superclasses , uma lista de slots (variáveis ​​de membro na linguagem C ++ / Java) e uma metaclasse especial . Os slots podem ser alocados por classe (todas as instâncias de uma classe compartilham o slot) ou por instância. Cada slot tem um nome e o valor de um slot pode ser acessado por esse nome usando a função slot-value. Além disso, funções genéricas especiais podem ser definidas para escrever ou ler valores de slots. Cada slot em uma classe CLOS deve ter um nome exclusivo.

CLOS é um sistema de despacho múltiplo . Isso significa que os métodos podem ser especializados em qualquer um ou todos os seus argumentos necessários. A maioria das linguagens OO são de despacho único, o que significa que os métodos são especializados apenas no primeiro argumento. Outro recurso incomum é que os métodos não "pertencem" às classes; classes não fornecem um namespace para funções ou métodos genéricos. Os métodos são definidos separadamente das classes e não têm acesso especial (por exemplo, "this", "self" ou "protected") aos slots de classe.

Os métodos no CLOS são agrupados em funções genéricas . Uma função genérica é um objeto que pode ser chamado como uma função e que associa uma coleção de métodos a um nome e estrutura de argumento compartilhados, cada um especializado em diferentes argumentos. Como o Common Lisp fornece classes não CLOS para estruturas e tipos de dados embutidos (números, strings, caracteres, símbolos, ...), o despacho CLOS também funciona com essas classes não CLOS. CLOS também oferece suporte a despacho sobre objetos individuais (especializadores eql). O CLOS não suporta, por padrão, o dispatch sobre todos os tipos de dados Common Lisp (por exemplo, o dispatch não funciona para tipos de array totalmente especializados ou para tipos introduzidos por deftype). No entanto, a maioria das implementações do Common Lisp fornece um protocolo de metaobjeto que permite que funções genéricas forneçam especialização específica do aplicativo e regras de despacho.

O despacho no CLOS também é diferente da maioria das linguagens OO:

  1. Dada uma lista de argumentos, uma lista de métodos aplicáveis ​​é determinada.
  2. Esta lista é classificada de acordo com a especificidade de seus especializadores de parâmetro.
  3. Os métodos selecionados desta lista são então combinados em um método eficaz usando a combinação de métodos usada pela função genérica.
  4. O método eficaz é então chamado com os argumentos originais.

Este mecanismo de despacho funciona em tempo de execução. Adicionar ou remover métodos, portanto, pode levar a métodos eficazes alterados (mesmo quando a função genérica é chamada com os mesmos argumentos) em tempo de execução. Alterar a combinação de métodos também pode levar a diferentes métodos eficazes.

Por exemplo,

; declare the common argument structure prototype
(defgeneric f (x y))

; define an implementation for (f integer t), where t matches all types
(defmethod f ((x integer) y) 1)

(f 1 2.0) => 1

; define an implementation for (f integer real)
(defmethod f ((x integer) (y real)) 2)

(f 1 2.0) => 2 ; dispatch changed at runtime

Como os sistemas OO na maioria das linguagens dinâmicas , o CLOS não impõe o encapsulamento . Qualquer slot pode ser acessado usando a slot-valuefunção ou por meio de métodos de acesso (opcionalmente gerados automaticamente) . Para acessá-lo por meio slot-valueé necessário saber o nome do slot. Os programadores de CL usam o recurso de pacote da linguagem para declarar quais funções ou estruturas de dados devem ser exportadas.

Para além do ácido ( "primários"), os métodos normais, também existem :before, :aftere :aroundmétodos de "auxiliares". Os dois primeiros são chamados antes ou depois do método principal, em uma ordem específica com base na hierarquia de classes. Um :aroundmétodo pode controlar se o método principal é executado. Além disso, o programador pode especificar se todos os métodos primários possíveis ao longo da hierarquia de classes devem ser chamados ou apenas aquele que fornece a correspondência mais próxima.

A combinação de métodos padrão fornece os métodos primários, antes, depois e ao redor explicados acima. Existem outras combinações de métodos com outros tipos de métodos. Novas combinações de métodos (simples e complexas) e tipos de métodos podem ser definidos.

CLOS permite herança múltipla . Quando a ordem padrão na qual os métodos são executados em herança múltipla não está correta, o programador pode resolver os problemas de herança de diamante especificando a ordem das combinações de métodos.

CLOS é dinâmico, o que significa que não só o conteúdo, mas também a estrutura de seus objetos podem ser modificados em tempo de execução. O CLOS oferece suporte à alteração das definições de classe em tempo real (mesmo quando já existem instâncias da classe em questão), bem como à alteração da associação de classe de uma determinada instância por meio do change-classoperador. CLOS também permite adicionar, redefinir e remover métodos em tempo de execução. O problema do círculo-elipse é prontamente resolvido no CLOS, e a maioria dos padrões de projeto OOP desaparecem ou são qualitativamente mais simples.

CLOS não é uma linguagem de protótipo : as classes devem ser definidas antes que os objetos possam ser instanciados como membros dessa classe.

Protocolo de Metaobjeto

Fora do padrão ANSI Common Lisp, há uma extensão amplamente implementada para CLOS, chamada Metaobject Protocol (MOP). O MOP define uma interface padrão para os fundamentos da implementação CLOS, tratando classes, descrições de slots, funções genéricas e métodos próprios como instâncias de metaclasses e permite a definição de novas metaclasses e a modificação de todo o comportamento CLOS. A flexibilidade do CLOS MOP prefigura a programação orientada a aspectos , que mais tarde foi desenvolvida por alguns dos mesmos engenheiros, como Gregor Kiczales . O MOP define o comportamento de todo o sistema de objetos por um conjunto de protocolos. Eles são definidos em termos de CLOS. Assim, é possível criar novos sistemas de objetos estendendo ou alterando a funcionalidade CLOS fornecida. O livro The Art of the Metaobject Protocol descreve o uso e a implementação do CLOS MOP.

As várias implementações do Common Lisp têm suporte ligeiramente diferente para o protocolo Meta-Object. O projeto Closer visa fornecer os recursos que faltam.

Influências de sistemas de objetos baseados em Lisp mais antigos

Flavors (e seu sucessor, New Flavors) era o sistema de objetos na Máquina Lisp do MIT . Grandes partes dos sistemas operacionais da Máquina Lisp e muitas aplicações para ela usam Sabores ou Novos Sabores. Flavors introduziu herança múltipla e mixins , entre outros recursos. Flavors é principalmente obsoleto, embora existam implementações para Common Lisp. A Flavors estava usando o paradigma de transmissão de mensagens. New Flavors introduziu funções genéricas.

CommonLoops foi o sucessor do LOOPS (da Xerox Interlisp -D). CommonLoops foi implementado para Common Lisp. Uma implementação portátil chamada Portable CommonLoops (PCL) foi a primeira implementação do CLOS. O PCL é amplamente portado e ainda fornece a base para a implementação CLOS de várias implementações Common Lisp . PCL é implementado principalmente em Common Lisp portátil com apenas algumas partes dependentes do sistema.

CLOS em outras linguagens de programação

Por causa do poder e expressividade do CLOS, bem como a disponibilidade histórica do TinyCLOS (uma implementação CLOS portátil simplificada escrita por Gregor Kiczales para uso com Scheme), sistemas de objetos baseados em MOP semelhantes a CLOS se tornaram a norma de fato na maioria dos Lisp implementações de dialeto, bem como encontrar seu caminho para as facilidades OOP de algumas outras linguagens :

Referências

  • " CommonLoops: mesclando Lisp e programação orientada a objetos ", por Daniel G. Bobrow, Kenneth Kahn, Gregor Kiczales, Larry Masinter, Mark Stefik, Frank Zdybel. 1986, Portland, Oregon, Estados Unidos. Páginas 17–29 da Conferência sobre Linguagens e Aplicações de Sistemas de Programação Orientada a Objetos , ISSN 0362-1340.
  • "A History and Description of CLOS", de Jim Veitch. Páginas 107–158 do Manual de Linguagens de Programação, Volume IV: Linguagens de Programação Funcional e Lógica , ed. Peter H. Salus . 1998 (1ª edição), Macmillan Technical Publishing; ISBN  1-57870-011-6

Literatura