Mis amigos y yo estamos trabajando en algunos ejercicios básicos de Ruby para familiarizarnos con el idioma, y hemos encontrado un comportamiento interesante que todavía no hemos podido comprender. Básicamente, estamos creando un tipo de datos tree
donde solo hay una clase, node
, que contiene exactamente un valor y una matriz de cero o más nodes
. Estamos usando el corredor de prueba autospec de rspec. En un momento comenzamos a escribir pruebas para rechazar la recursión infinita (una estructura de árbol circular).¿Por qué esta recursión NO es infinita?
Aquí está nuestra prueba:
it "breaks on a circular reference, which we will fix later" do
tree1 = Node.new 1
tree2 = Node.new 1
tree2.add_child tree1
tree1.add_child tree2
(tree1 == tree2).should be_false
end
Aquí está la clase Node:
class Node
attr_accessor :value
attr_reader :nodes
def initialize initial_value = nil
@value = initial_value
@nodes = []
end
def add_child child
@nodes.push child
@nodes.sort! { |node1, node2| node1.value <=> node2.value }
end
def == node
return (@value == node.value) && (@nodes == node.nodes)
end
end
Esperamos que la última línea de la prueba para dar lugar a un bucle infinito hasta que los desbordamientos de pila, ya que debe continuamente compare los nodos secundarios entre sí y nunca encuentre un nodo hoja. (Estamos bajo la impresión de que el operador ==
en una matriz iterará sobre la matriz y llamará al ==
en cada niño, según the array page of RubyDoc). Pero si lanzamos un puts
en el método ==
para ver la frecuencia con que se llama, descubrimos que se llama exactamente tres veces y luego pasa la prueba.
¿Qué nos falta?
Editar: Tenga en cuenta que si reemplazamos be_false
en la prueba con be_true
, la prueba falla. Por lo tanto, definitivamente cree que las matrices no son iguales, simplemente no está recurriendo a ellas (aparte de las tres llamadas distintas al ==
).
@beavis: "==" debe ser recursivo en esta implementación, porque trata de comparar los elementos secundarios de dos nodos que se referencian entre sí cuando son niños comparando a sus hijos, y así sucesivamente. Es un "árbol" porque es un nodo con nodos secundarios, que a su vez puede tener nodos secundarios, etc. Ver http://en.wikipedia.org/wiki/Tree_(computer_science) – David
Es un árbol bastante desordenado. Un nodo no debería saber cómo organizarse dentro de la estructura de datos en la que vive. – user370731
@beavis: ¿Te refieres al género? Eso fue algo que quisimos agregar para probar la ordenación de arreglos y probablemente se eliminará a medida que el código madure. Es un prototipo temprano, que en realidad no se usará para nada. Como dije, solo estamos sintiendo el idioma en este momento. – David