A mix of void safety and object creation issue, not sure how to fix it

4 messages Options
Embed this post
Permalink
dlebansais

A mix of void safety and object creation issue, not sure how to fix it

Reply Threaded More More options
Print post
Permalink
Hello,

I encountered an issue in one of my class inheriting from SORTED_TWO_WAY_LIST. Since my code is a bit complicated I made the sample classes below to explain the problem.

class
        ANCESTOR

create
        make

feature

        make
        do
                must_be_one := 1
        end

        proceed_to_test
        do
                internal_test
        end

feature {NONE}

        must_be_one: INTEGER
        temp_object: detachable like current

        internal_test
        do
                create temp_object.make
        end

end

In ANCESTOR I have 'must_be_one' just to simulate to attribute that must be set by the creation procedure. Basically, any descendant of ANCESTOR must call 'make' to initialize properly.

Here is the sample code for such a descendant:

class
        DESCENDANT

inherit
        ANCESTOR
                redefine
                        make
                end

create
        make

feature

        make
        do
                -- How to call ANCESTOR.make here?
                create my_array.make(1, 0)
        end

        my_array: ARRAY[INTEGER]
end

The DESCENDANT class has its own 'my_array' attribute which must be attached at creation.

I've created a project with this code, and turned on Full Class Checking, Cat call detection, Attached by default. Void safety is set to complete, and syntax is left to the default.

Also, while not related, I use the base-safe library and the base-mt-safe precompile. This is with EiffelStudio 6 (6.4.7.9263 GPL Edition - windows).

With these settings, the code compiles fine. However, you probably have noticed that 'make' in DESCENDANT doesn't call 'make' in ANCESTOR and therefore the object isn't correctly initialized.

That's my issue: I can't have a creation procedure called 'make' and be able to call a creation procedure with that name in the ancestor.

Unless, of course, I rename 'make' from ANCESTOR, like this:

class
        DESCENDANT

inherit
        ANCESTOR
                rename
                        make as ancestor_make
                end

create
        make

feature

        make
        do
                ancestor_make -- Nice try but it won't compile
                create my_array.make(1, 0)
        end

        my_array: ARRAY[INTEGER]
end

This code doesn't compile, because in the test feature of ANCESTOR we create an object by calling 'create temp_object.ancestor_make' (remember, 'make' was renamed as 'ancestor_name'). And, since 'like current' means DESCENDANT, 'ancestor_make' isn't listed as a creation procedure. Thus compilation fails.

Now, if I add 'ancestor_make' in the list of creation procedure, it doesn't work either because 'my_array' is left detached...

I can see a few ways to fix this issues.

1. I had a newbie moment and there is an obvious fix. Please be kind with me!

2. Make 'my_array' detachable. It works but what's the point of void safety if ANCESTOR forces all its descendants to have detachable attributes? And it creates all sort of problems with invariants anyway.

3. In ANCESTOR, use an intermediate creation feature that a descendant can redefine, like this:

class
        ANCESTOR

create
        make

feature

        make
        do
                must_be_one := 1
        end

        proceed_to_test
        do
                internal_test
        end

        new_object: like current
        do
                create result.make
        end

feature {NONE}

        must_be_one: INTEGER
        temp_object: detachable like current

        internal_test
        do
                temp_object := new_object
        end

end

class
        DESCENDANT

inherit
        ANCESTOR
                rename
                        make as ancestor_make
                redefine
                        new_object
                end

create
        make

feature

        make
        do
                ancestor_make -- Now it works
                create my_array.make(1, 0)
        end

        new_object: like current
        do
                create result.make
        end

        my_array: detachable ARRAY[INTEGER]
end

The problem is that it requires a change in ANCESTOR and that might not work out if ANCESTOR comes from a library.

Actually, SORTED_TWO_WAY_LIST does have this intermediate creation feature, called 'new_chain'. Unfortunately it doesn't use it everywhere!

Beside, this is a generic issue potentially affecting all code. Instead of just fixing SORTED_TWO_WAY_LIST (if I'm right) there should be some additional check in Eiffelstudio to warn coders about this pitfall.

Any thoughts? Should I submit a bug report?

Thank you for your patience.
David Le Bansais.


Jimmy Johnson

Re: A mix of void safety and object creation issue, not sure how to fix it

Reply Threaded More More options
Print post
Permalink
Why not use Precursor in make?

make
  do
      -- How to call ANCESTOR.make here?
    Precursor {ANCESTOR}
    create my_array.make(1, 0)
  end




Emmanuel Stapf

RE: A mix of void safety and object creation issue, not sure how to fix it

Reply Threaded More More options
Print post
Permalink
In reply to this post by dlebansais
> class
> DESCENDANT
>
> inherit
> ANCESTOR
> redefine
> make
> end
>
> create
> make
>
> feature
>
> make
> do
> -- How to call ANCESTOR.make here?
> create my_array.make(1, 0)
> end
>
> my_array: ARRAY[INTEGER]
> end

To call the ancestor `make' simply do

        make
                do
                        Precursor
                        create my_array.make (1, 0)
                end

> 1. I had a newbie moment and there is an obvious fix. Please be kind with
> me!

See above.
 
> 2. Make 'my_array' detachable. It works but what's the point of void
> safety if ANCESTOR forces all its descendants to have detachable
> attributes? And it creates all sort of problems with invariants anyway.

Not needed if you use `Precursor' as specified above.
 
> Actually, SORTED_TWO_WAY_LIST does have this intermediate creation
> feature, called 'new_chain'. Unfortunately it doesn't use it everywhere!

It is used from the DYNAMIC_CHAIN ancestor in `duplicate'.

Hope this helps,
Manu

------------------------------------------------------------------------  
Eiffel Software
805-685-1006
http://www.eiffel.com       
Customer support: http://support.eiffel.com       
User group: http://groups.eiffel.com/join       
------------------------------------------------------------------------  
dlebansais

Re: A mix of void safety and object creation issue, not sure how to fix it

Reply Threaded More More options
Print post
Permalink
> > feature
> >
> > make
> > do
> > -- How to call ANCESTOR.make here?
> > create my_array.make(1, 0)
> > end
> >
> > my_array: ARRAY[INTEGER]
> > end
>
> To call the ancestor `make' simply do
>
> make
> do
> Precursor
> create my_array.make (1, 0)
> end
>
>
> Hope this helps,
> Manu
>

Thank you for helping us on these issues. Someone already had pointed it out, but I'm grateful that you and others are taking the time to investigate all such posts. Very appreciated.


Regards,
David Le Bansais.