Today I encountered a situation whereby HASH_TABLE.current_keys caused the runtime to throw a couple a Catcall warnings onto my console. Within the bench, it was quickly discovered that these came from ARRAY.make, which uses ({G}).default to make_filled_area for itself. Below is a patch that will avoid the Catcall warnings (which are disguised attachment errors).


Now onto to discussion about `default’. This feature is defined in ANY as `frozen default: detachable like Current’. This feature has an empty body. Although syntactically correct, we have to then wonder what a frozen default would yield when void-safety becomes the standard. A `default’ value as such would seem useful in a way for non-object types (INTEGER and friends) and one could possibly think of default values for certain objects. For example a USER_AGENT_STRING could inherit from STRING and have a default value of say “Eiffel Request Client”. That is not possible, though, because of the frozen nature of `default’. Since there is only an empty body, a Void object is always created, which sort of defeats the purpose of void-safety (in general terms, that is).


I can see two solutions:

1)      Remove `default’ from ANY, as it is not useful in void-safety environments, except for INTEGER and friends. This can be done only in Eiffel versions after the standard adopts void-safety.

2)      Implement the `frozen default’ to `create Result’. This, however, does not work for INTEGER and friends, as they cannot be created (since they are not objects).


A third scenario comes to mind, which is my patch below. In this scenario, we would leave `default’ be, and “work around” its issues, by deeply checking Void-Safety. Although hidden within a couple of classes and feature calls, the compiler should still detect that ARRAY.make uses void-unsafe values in its call-chain.


We have the following types:

1)      HASH_TABLE [G, K -> detachable HASHABLE] (instantiated as HASH_TABLE [STRING, STRING], which will thus be a HASH_TABLE [attached STRING, detachable STRING])

2)      ARRAY [G] (instantiated as ARRAY [detachable STRING])

3)      SPECIAL [T] (instantiated as SPECIAL [detachable STRING])

We also have the following features:

1)      current_keys: ARRAY [K], instantiated as current_keys: ARRAY [detachable STRING]

2)      make (min_index, max_index: INTEGER), which calls make_filled_area (({G}).default, max_index – min_index + 1) (called as make_filled_area (({detachable STRING}).default, max_index – min_index + 1))

3)      frozen default: detachable like Current instantiated as frozen default: detachable STRING

4)      make_filled (v: T; n: INTEGER) (from SPECIAL [T], called by make_filled_area in TO_SPECIAL [T]) (instantiated as make_filled (v: detachable STRING; n: INTEGER)

5)      fill_with (v: T; start_index, end_index: INTEGER) instantiated as fill_with (v: detachable STRING; start_index, end_index: INTEGER)



So, the compiler is correct in saying nothing: all types involved are detachable. For the human mind, however SPECIAL [T] means that T is attached. This is thus not always the case:


Looking at this, the real culprit seems to be the generic declaration of HASH_TABLE: HASH_TABLE [G, K -> detachable HASHABLE]. Why does K need to be detachable? And if so, must then not all generic suppliers of HASH_TABLE be implemented as though their generic parameter *could* be detachable? This seems to not have taken place. So the only *real* solution to this problem would seem to implement the below or a similar patch for all classes where the generic parameter *could* be detachable, and thus yield a real-time value of Void.



Patch against ARRAY.e (Revision 454):

Index: array.e


--- array.e     (revision 454)

+++ array.e     (working copy)

@@ -78,7 +78,11 @@

                        lower := min_index

                        upper := max_index

                        if min_index <= max_index then

-                               make_filled_area (({G}).default, max_index - min_index + 1)

+                               if attached {G} ({G}).default as l_default_g then

+                                       make_filled_area (l_default_g, max_index - min_index + 1)

+                               else

+                                       make_empty_area (max_index - min_index + 1)

+                               end


                                make_empty_area (0)


***** END OF PATCH ******


Any thoughts on this subject?