Pitfalls with self-replicating objects

When designing a class, it's a good thing to consider reusability. The subject of this entry is to examine objects of a class that are able to replicate, and the consequences this has on making the class reusable.

Object replication means creating a new object from within the code. It doesn't have to be a copy, it just means here that a new object of the same class is created. There is no special consideration regarding the state of the new object.

The effect of calling mitosis is to create a new cell identical to the original.

Inheritance

All is good so far, however things become messy if we want to write a new class inheriting from BASIC_CELL. You noticed the create intruction, it calls make and therefore make must be available for creation for all descendants.

This can be a problem, for instance if the descendant has no obvious default state. It's also a problem if we don't want the outside world to create objects of the descendant class with make. Fortunately, a work around this is to restrict the export state of make, as the code below demonstrates.

This code fails to compile if void safety is turned on, and types are attached by default. In that case, there is no way for make to find the correct value of cell_organ.

Deferred descendants

Theoretically, a deferred class can inherit from a parent without trouble. But no deferred class can inherit from BASIC_CELL, because it would have to list make as a creation procedure, and deferred classes cannot have them.

Fixing the code

A good workaround to this problem is to have a feature dedicated to the creation of the new object. The idea is that it can be undefined and redefined based on the descendants needs. Undefined in deferred classes, redefined to use the appropriate creation procedure otherwise.

class
RED_BLOOD_CELL
inherit
BLOOD_CELL
undefine
make
end
create
make
feature -- Creation
make
local
body_blood: BLOOD
do
create body_blood
make_with_organ(body_blood)
end
feature -- Marker
add_marker
do
end
feature -- New object
create_new: like current
do
create result.make
end
end

Conclusion

As we have seen, using create to duplicate an object makes a class harder to reuse, unless the use of create is restricted to be in a dedicated feature. Descendants can then undefine or redefine that feature in a way that suits their needs.

The compiler could detect this situation and issue a warning if the feature where create is found to contain other instructions.

Last but not least, perhaps someone could take a look at classes from the standard libraries, since at least TWO_WAY_LIST can replicate. I have myself written code that inherits from TWO_WAY_LIST, and working around this issue has annoyed me quite a bit, prompting this post.

Comments

Manu(8 years ago 2/4/2010)

The issue with deferred classes has been discussed at ECMA. At the time, we postponed any resolution on the solution because it was not felt as a major issue and it is easy to work around using the `create_new' mechanism you have described and the pitfall you mentioned.

I believe that if something is adopted it will be the following. When checking the code of a deferred class the creation of a like Current' instance will always be valid if the call is valid. Clearly the non-deferred descendants of the deferred class will ensure that make' is indeed properly exported for creation.