eiffelcreation-pattern

Eiffel: best practices for creation procedures


Animal

deferred class ANIMAL
inherit
    ANY
        redefine
            default_create
        end
feature

    creator: like Current

    guts: GUTS

    default_create
        do
            create guts
        end

    make_malformed
        do
            default_create
        end

end --class

PIG

class PIG

inherit
    ANIMAL
        redefine
            make_malformed
        end

create
    default_create,
    make_malformed,
    make_from_insemination

feature
    guts: GUTS

    make_malformed
        do
            Precursor
            set_left_eye (create {MALFORMED_EYE})
        end

    make_from_insemination (some_humain: HUMAIN)
        do
            default_create
            creator := some_humain
        end

end --class

Into my vision of best practices, I'll say that

Correct me if I'm wrong. Thanks in advance!


Solution

  • Many Eiffel libraries were developed before default_create was added to ANY with the corresponding semantics. This explains why many classes of the base library do not use it.

    Also, creation procedures can carry some specific sense. For example, make can create a container that compares internal objects using reference equality whereas make_equal can create a container that uses object equality instead (this is the case for HASH_TABLE, though there is an additional argument to indicate an expected number of elements, this argument could be omitted with some other design choice). In such cases, default_create and default_create_equal would be non-symmetric, whereas make and make_equal are symmetric, so that the design is more consistent.

    As you point out, default_create should not carry any specific behavior, just some basic things, expected from all descendants.

    Whether default_create should be called by all other creation procedures heavily depends on the design. One example, where this is almost a rule, is the library "vision" that encodes in default_create a correct order of initialization, crucial for void safety. It's still possibly to write a class (based on this library) that performs the initialization correctly without calling default_create in its creation procedure, but having a ready-to-follow patters simplifies development.