class A
default_create do Precursor -- ANY create turtle end
end -- class A
class B
inherit A
default_create do Precursor {A} create rabbit end
end -- class B
class C
inherit A B
default_create do Precursor {A} Precursor {B} create cat end
end -- class B
class C
inherit A B
default_create do create turtle create rabbit create cat end
end -- class B
but on more complex cases, I don't want (and don't tell me I have to please...) each time I have 1 common ancestor go to see what is common on the creation procedure and then do it only once....
One strategy is to use one of the reference attributes as a test for initialization. As for example
class A default_create do if not attached turtle then Precursor -- ANY create turtle end end end
But this will only work if you are using the non-void safe compiler and you know the attribute is always supposed to be attached (after initialization)
Eiffel-Loop has a general solution to the problem which works if
you just want to assign some default values. It uses the class EL_REFLECTIVELY_SETTABLE
to reflectively set each attribute. `make_default' sets default
values for many common types as for example: STRING, STRING_32,
ZSTRING, EL_FILE_PATH, DATE, TUPLE [X, Y, Z..] (where X, Y, Z are
basic or common types) or objects conforming to EL_MAKEABLE. Using
your example with EL_REFLECTIVELY_SETTABLE
would look like the following. (Note that `new_instance_functions'
is only redefined for attributes that are initialize-able using
default methods)
class A inherit EL_REFLECTIVELY_SETTABLE rename make_default as make redefine new_instance_functions end create make feature {NONE} -- Implementation new_instance_functions: like Default_initial_values do create Result.make_from_array (<< agent: like turtle do create Result end >>) end end class B inherit A EL_REFLECTIVELY_SETTABLE redefine new_instance_functions end create make feature {NONE} -- Implementation new_instance_functions: like Default_initial_values do Precursor + agent: like rabbit do create Result end end end class C inherit A B EL_REFLECTIVELY_SETTABLE redefine new_instance_functions end create make feature {NONE} -- Implementation new_instance_functions: like Default_initial_values do Precursor + agent: like cat do create Result end end end
-- SmartDevelopersUseUnderScoresInTheirIdentifiersBecause_it_is_much_easier_to_read
thx in advance
Thx a lot Finnan, so it seems that you also had the same problems with that so much that you developed a library for managing that. I'll take a look deeper on that.
I had one further idea today that I quickly implemented without
testing but, it looks like it might work. The class EL_INITIALIZEABLE
has no dependencies except ISE base so you are welcome to try it.
Here is how it is intended to be be applied. It is easy to imagine
how this might be built into the compiler. The `Initialization_mask_table'
must be implemented as a once function for each class heirarchy.
class A inherit EL_INITIALIZEABLE create make feature {NONE} -- Initialization make do if not_initialized ({A}) then create turtle set_initialized end end feature {NONE} -- Constants Initialization_mask_table: HASH_TABLE [NATURAL, INTEGER] once create Result.make (7) end end class B inherit A redefine make end create make feature {NONE} -- Initialization make do if not_initialized ({B}) then Precursor {A} create rabbit set_initialized end end end class C inherit A redefine make end B redefine make end create make feature {NONE} -- Initialization make do if not_initialized ({C}) then Precursor {A} Precursor {B} create cat set_initialized end end end
-- SmartDevelopersUseUnderScoresInTheirIdentifiersBecause_it_is_much_easier_to_read
Thx a lot Finnan, so it seems that you also had the same problems with that so much that you developed a library for managing that. I'll take a look deeper on that.
That reflection library has a lot more benefits besides. The
initialization aspect is only the tip of the iceberg.
-- SmartDevelopersUseUnderScoresInTheirIdentifiersBecause_it_is_much_easier_to_read
Class EL_PRECURSOR_MAP
The class EL_INITIALIZEABLE has some performance issues as you need to create a new TYPE object (requiring additional GC) unless you want to go to the trouble of caching the {TYPE}.type_id as a once function.
But I have come up with a better solution that is much more
efficient. See class EL_PRECURSOR_MAP
(source
on github) Basically it uses the address of the make routine to
look up a bitmap mask for a bitmap indicating whether the routine
has been called already or not.
The class is used like this:
class A inherit EL_PRECURSOR_MAP create make feature {NONE} -- Initialization make do create turtle end feature {NONE} -- Constants Done_mask_table: HASH_TABLE [NATURAL, POINTER] once create Result.make (7) end end class B inherit A redefine make end create make feature {NONE} -- Initialization make do if not done ($make) then Precursor {A} create rabbit set_done ($make) end end end class C inherit A redefine make end B redefine make end create make feature {NONE} -- Initialization make do if not done ($make) then Precursor {A} Precursor {B} create cat set_done ($make) end end end
Class EL_PRECURSOR_MAP
I have introduced 2 variations of this class