2010-05-23 9 views
9

primera vez en el desbordamiento de la pila.En Ruby o Python, ¿se puede reescribir el concepto de Clase?

Estoy buscando utilizar algunas de las funciones de metaprogramación proporcionadas por Ruby o Python, pero primero necesito saber en qué medida me permitirán ampliar el idioma. Lo principal que debo poder hacer es volver a escribir el concepto de Clase. Esto no significa que quiera reescribir una clase específica durante el tiempo de ejecución, sino que quiero hacer mi propia conceptualización de lo que es una clase . Para ser un smidge más específico aquí, quiero hacer algo que es como lo que la gente normalmente llama una clase, pero quiero seguir el supuesto "open world". En el "mundo cerrado" de las Clases normales, si declaro que Poodle es una subclase de Perro para ser una subclase de Animal, entonces sé que Poodle tampoco será un tipo de FurCoat. Sin embargo, en una Clase mundial abierta, entonces el objeto Poodle que he definido puede o no ser objeto de tipo FurCoat y no lo sabremos con certeza hasta que explique que puedo usar el poodle. (Poodle Poodle.) Todo esto tiene que ver con un estudio que estoy haciendo sobre ontologías OWL.

Para que lo sepas, traté de encontrar información en línea, pero debido a la sobrecarga de términos aquí no encontré nada útil.

gracias Super, John

Actualización: Me acaba de ocurrir un buen caso de uso para mi concepto de mundo abierto de clase. Tal vez esto proporcionará una mejor comprensión de lo que realmente deseo hacer. Quiero poder "describir" una clase en lugar de definirla. Por ejemplo, quiero poder decir que un perro es cualquier cosa que a) tiene cuatro patas b) ladra. Entonces, quiero poder crear un objeto de Clase no especificada y describir que este objeto tiene cuatro patas. En este punto, el objeto sigue siendo de tipo no especificado. Entonces quiero decir que el objeto ladra. En este punto, se conocerá que el objeto (posiblemente entre otras cosas) es un perro.

+2

¿Podría ser la herencia múltiple que está buscando? Eso permitiría que 'Poodle' sea una subclase de' Dog' y 'FurCoat', y como consecuencia, encontrar que' Poodle' es una subclase de 'Dog' no excluye la posibilidad de que sea una subclase de' FurCoat'. –

+1

Parece que estás demasiado obsesionado con esta idea de modificar la clase. Es posible cambiar cómo 'is_a?' Funciona en Ruby para comparar campos en lugar de los tipos de clase y debe hacer lo que desee. –

Respuesta

7

Estoy de acuerdo con Samir en que suena a mecanografiar pato. No es necesario que le importe lo que "escriba" realmente un objeto "es", solo necesita preocuparse por lo que un objeto puede "hacer". Esto es cierto tanto en Ruby como en Python.

Sin embargo, si realmente mirando los tipos de clases y que realmente no necesita tener un objeto Poodle opcionalmente también ser un FurCoat en tiempo de ejecución, entonces la manera de hacer esto en Ruby es mixin un módulo FurCoat en el objeto Poodle , de la siguiente manera:

class Poodle; end 
module FurCoat; def wear; end; end 

my_poodle = Poodle.new 
my_poodle.is_a?(Poodle) #=> true 
my_poodle.is_a?(FurCoat) #=> false 
my_poodle.wear #=> NoMethodError 

# now we mix in the FurCoat module 
my_poodle.extend(FurCoat) 

# my_poodle is now also a FurCoat 
my_poodle.is_a?(Poodle) #=> true (still) 
my_poodle.is_a?(FurCoat) #=> true 
my_poodle.wear #=> the wear method now works 

EDITAR (debido a su pregunta actualizada):

todavía no es necesario volver a escribir Class para conseguir lo que quiere, sólo ne ed parche de monos los métodos kind_of? y is_a? (y potencialmente instance_of?) en el módulo Kernel de Ruby. Dado que Ruby tiene clases abiertas Esto se hace fácilmente:

class Module 
    def obj_implements_interface?(obj) 
     false 
    end 
end 

module Kernel 
    alias_method :orig_is_a?, :is_a? 

    def is_a?(klass) 
     orig_is_a?(klass) || klass.obj_implements_interface?(self) 
    end 
end 

y luego definir para cada clase (o módulo) lo que significa para un objeto de implementar su interfaz:

class Dog 
    def self.obj_implements_interface?(obj) 
     obj.respond_to?(:bark) && obj.respond_to?(:num_legs) && obj.num_legs == 4 
    end 
end 

module FurCoat 
    def self.obj_implements_interface?(obj) 
     obj.respond_to?(:wear) 
    end 
end 

Ahora probarlo:

my_poodle = Poodle.new 
my_poodle.is_a?(FurCoat) #=> false 

# now define a wear method on my_poodle 
def my_poodle.wear; end 
my_poodle.is_a?(FurCoat) #=> true 
+0

Lo primero es lo primero, estoy MUY impresionado con stackOverflow y con ustedes muchachos. Salgo a tomar un bocado y vuelvo y tengo 63 vistas y algunas respuestas bastante inteligibles para arrancar! Así que Samir y barandilla, ustedes se están acercando * a la funcionalidad que necesito, pero no creo que puedan llegar hasta allí. No puedo escribir patos porque si puede volar, no necesariamente es un avión. El tipo real es importante, solo se conoce de manera incompleta.No puedo mezclar porque a veces tendré que * inferir * que también es un FurCoat sin especificarlo. Realmente necesito poder reescribir la Clase – JnBrymn

+0

Muy genial. Eso sí me acerca al resultado que requiero. Aunque realmente me gustaría tener libertad para crear mi propia entidad que imita a la entidad de la Clase. Parece, sin embargo, que crece un consenso en contra de esa posibilidad. – JnBrymn

8

Me parece duck typing. Sólo declarar los métodos que desee y recuerde que es más fácil pedir perdón que pedir permiso:

try: 
    poodle.wear() 
except (AttributeError, TypeError): 
    pass 
+0

+1 para pato escribir probablemente siendo lo que el OP puede usar –

2

En Python puede cambiar el inheritence de una clase en tiempo de ejecución, pero en cada momento dado una clase no es una subclase de otra uno a menos que se declare lo contrario. No hay "puede o no puede" - eso necesitaría una lógica ternaria que Python no admite. Pero, por supuesto, puede escribir sus propias funciones "Is-a" y "Has-a" para mapear ontologías OWL a las clases de Python.

1

creo que depender de una estructura de clases, no importa qué tan dinámico, es un paso hacia atrás cuando representación de la información con un supuesto palabra abierta.

Las clases que sirven como plantillas y objetos que sirven como instancias no ofrecen ninguna ventaja cuando se usan con un OWA. Considere una clase de Persona en la que codificamos el conocimiento de que una persona tiene 2 piernas. Sin embargo, no podemos deducir que una instancia de Person tendrá dos piernas, ya que la persona puede tener una discapacidad.

Si las propiedades de la clase no significan nada como en el ejemplo anterior, parece que tiene poco sentido usarlas o cualquier otra estructura jerárquica para codificar información.

+0

Debo aclarar aquí que, por ahora, no me preocupa si mis intenciones son razonables o no. Más bien, solo quiero saber si puedo usar Ruby para crear una entidad * de tipo * para reemplazar la entidad de clase actual. Dicho esto, tiene algunos puntos buenos, e incluso cuando creé el ejemplo de "perro tiene 4 patas", me di cuenta de que era demasiado simplista. Sin embargo, tengo otras cosas en mente que todavía me interesan mucho en la creación de una clase de mundo abierto. – JnBrymn

6

No, no puedes hacer eso en Ruby. En Ruby, el modelo de objetos se hornea en el language specification y no es accesible (y ciertamente no modificable) desde dentro del programa. Incluso en Rubinius, que es una implementación de Ruby escrita principalmente en Ruby, y con increíbles capacidades de metaprogramación que se extienden mucho más allá de lo que ofrece la especificación Ruby, algunas de the fundamental primitives are hardwired in C++.

No estoy tan íntimamente familiarizado con Python, pero estoy bastante seguro de que es de la misma manera, incluso en PyPy.

Usted puede ser capaz de hacer eso en Smalltalk, mediante la modificación (o subclases) the Behavior class, que es la superclase de Class y define el comportamiento de ambas clases y metaclases.

Puede sin duda hacer que en CLOS, o más precisamente utilizando CLOS's MOP (Meta-Object Protocol). Después de todo, para eso sirve un MOP: definir el modelo de objetos.

El concepto de OO más cercano a lo que está describiendo parece ser el de Predicate Classes.Una clase de predicado es una clase cuyas instancias no están definidas estáticamente, sino por un conjunto de predicados: todos los objetos que satisfacen el conjunto de predicados son instancias de la clase, tan pronto como el predicado se mantiene. En un lenguaje con estado mutable, esto obviamente significa que los objetos pueden "moverse" dentro y fuera de las clases de predicados a medida que cambia su estado. También significa que en cualquier momento dado un objeto puede ser una instancia de muchas o ninguna clase de predicado.

El único lenguaje principal (para una definición bastante amplia de "mainstream") que sé que tiene clases de predicados es Factor.

Sin embargo, tenga en cuenta que incluso aquí, los predicados se definen y un objeto los cumple o no. No existe el concepto de descubrir si un objeto cumple o no un predicado en tiempo de ejecución.

La idea de Clojure de ad-hoc taxonomy de los clientes también le puede interesar.

Por último, pero ciertamente no menos importante, puede echarle un vistazo al sistema de objetos de Mikel Evins llamado Categories. La mejor descripción de las categorías, es simplemente seguir las entradas de blog en orden cronológico:

  1. Protocols
  2. Categories
  3. A peek at Categories
  4. No Kings in Rome
  5. Up pops a reasonable facsimile thereof
  6. Different Categories of Categories
  7. Categories Bugs
  8. Flat Cat in a C3 Vat
  9. Categories 0.2
  10. Bard
  11. Bard intricacies

En el futuro, la mayor parte del desarrollo de Categorías va a ser hecho en nuevo lenguaje de Mikel Bard y usted puede seguir su progreso siguiendo the Categories tag y the Bard tag en Mikel's new blog.

Sin embargo, en general, diría que el hecho de que Knowledge Management y Object-Orientation usen la palabra clase es principalmente un accidente histórico. No creo que modelar uno con el otro sea una buena opción.

+0

Muy buena información Jörg. Gracias por llamar la atención sobre el concepto de clase Predicate. Es muy parecido a lo que quiero, aunque con una gran excepción que ya ha señalado: en una clase de predicado si el objeto no satisface el predicado, entonces se sabe que no está en esa clase. Quiero conservar la tercera opción, que es "No sé si está en esa clase". Entonces, si decido seguir adelante, tendré que volver a crear una clase como objeto. Todavía estoy esperando alguna forma de hacer esto en ruby. En lugar de reprogramar Class, ¿puedo heredar de Module y hacer un OpenClass? – JnBrymn

Cuestiones relacionadas