Easiest way to do type comparisons?

88 views
Skip to first unread message

Thomas Beale

unread,
Jan 1, 2016, 10:11:59 AM1/1/16
to Eiffel Users
Following the previous thread on INTERNAL attached/detachable type id checking being broken (for now at least), I'd like to rephrase the question in a simpler way. 

Let's say I want to obtain a type-id for any field of an object, and then I want to know if it matches any type-id on a specific list of types.

Since this is for the purpose of serialsiation / deserialisation, I want to do this comparison without caring about the static attached/detachable status of any of these types. So I want to be able to match a type id for a type like SEQUENCE[ INTERVAL [ DATE ] ], regardless of whether the object field was declared as

detachable SEQUENCE[ INTERVAL [ DATE ] ] or  SEQUENCE[ detachable INTERVAL [ DATE ] ] or SEQUENCE[ detachable INTERVAL [ DATE ] ] or SEQUENCE[ detachable INTERVAL [ detachable DATE ] ] or... you get the idea.


Q1: how do I generate my reference type ids? 

Currently I do it with code like this (source code):

Result.extend (({SEQUENCE [INTERVAL [DATE]]}).type_id)

Q2: how do I obtain the type ids of the fields, including generic parameters of generic types like SEQUENCE etc?

Currently I do things like this (source code):

if attached {SEQUENCE[ANY]} eif_container_obj as eif_seq then
att_static_cont_item_tid := attached_type (generic_dynamic_type (eif_container_obj, 1)) -- obtain type id of gen parm 1


and so on. The first line of code doesn't care whether the eif_container object was an attached or detachable field of its parent. The second line of code no longer works, becaure attached_type no longer works.


But perhaps there is a more efficient way to do this kind of type comparison?

- thomas

Emmanuel Stapf

unread,
Jan 4, 2016, 6:16:46 AM1/4/16
to eiffel...@googlegroups.com

Instead of trying to convert everything to attached type which are problematic since it is highly dependent on the version of the compiler you are using, you should instead rely on the detachable version of types. Granted this is not what you would like but it is the only solution that will work with the old versions of the compiler and the future ones.

 

Also look at the precondition of `{REFLECTED_OBJECT}.set_reference_field’, it will give you all you need to find out if a type matches the type of a field, the key here is to use `field_conforms_to’.

 

As for matching SEQUENCE [INTERVAL [DATE]] with the variations of the type, you actually only care about matching against the attached or detachable version of the type. The nature of the attachment of the actual generic parameter should not matter and it is fully working as of today.

 

Regards,

Mnau

 

--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Peter Gummer

unread,
Jan 4, 2016, 6:50:36 AM1/4/16
to eiffel...@googlegroups.com
Hi Manu,

Do these suggestions work with .NET too?

In the past, we have always relied on INTERNAL.type_conforms_to. (These days, this function is in DOTNET_REFLECTOR.) We have always had to override the class to deal with generics.

But if we can use field_conforms_to instead, will it work in .NET? I’m looking at the implementation of DOTNET_REFLECTOR.field_conforms_to …

do
-- Currently .NET does not support attachment, this is why we are simlpy
-- calling `type_conforms_to'.
fixme ("Take into account attachment marks")
Result := type_conforms_to (a_source_type, a_field_type)
end

So I think we will still need our override of DOTNET_REFLECTOR.type_conforms_to. What do you think?

Regards,
Peter

Thomas Beale

unread,
Jan 4, 2016, 9:57:54 AM1/4/16
to Eiffel Users, ma...@eiffel.com
thanks Manu.... but a full solution is not yet clear. One thing I need to be able to do is determine what kind of type 'G' is in HASH_TABLE [G, K]. 

Currently I do this:

 dynamic_hash_item_type := generic_dynamic_type (a_hash_table, 1)
 
if is_dt_primitive_atomic_type (dynamic_hash_item_type) then
     
...

 elseif is_dt_primitive_sequence_conforming_type
(dynamic_hash_item_type) then
   
... etc
 

How do I implement is_dt_primitive_atomic_type()? Currently I test the passed type against a list of types, i.e.

 Result := dt_primitive_atomic_types.has (attached_type (a_type_id))


But this now doesn't work; but you say there is also no way to determine from a type id whether it is an expanded type, so I can't even figure out if it's expanded. In fact, expandedness isn't actually the criterion of interest - the criterion is whether the type is in a list of lexically atomic types in my type system, which is currently all the Eiffel expanded types + DATE, TIME, ... STRING, URI, ... and a few others that are typically atomic in a serialisation scheme. The test list currently looks as follows:

 dt_primitive_atomic_types: ARRAYED_LIST [INTEGER]
 
-- all primitive atomic types used in DT structures
 once
 create
Result.make (0)

 
Result.extend (({NATURAL_8}).type_id)
 
Result.extend (({NATURAL_16}).type_id)
 
Result.extend (({NATURAL_32}).type_id)
 
Result.extend (({NATURAL_64}).type_id)

 
Result.extend (({INTEGER_8}).type_id)
 
Result.extend (({INTEGER_16}).type_id)
 
Result.extend (({INTEGER_32}).type_id)
 
Result.extend (({INTEGER_64}).type_id)

 
Result.extend (({REAL_32}).type_id)
 
Result.extend (({REAL_64}).type_id)

 
Result.extend (({BOOLEAN}).type_id)

 
Result.extend (({CHARACTER_8}).type_id)
 
Result.extend (({CHARACTER_32}).type_id)

 
Result.extend (({STRING_8}).type_id)
 
Result.extend (({STRING_32}).type_id)

 
Result.extend (({DATE}).type_id)
 
Result.extend (({DATE_TIME}).type_id)
 
Result.extend (({TIME}).type_id)
 
Result.extend (({DATE_TIME_DURATION}).type_id)

 
Result.extend (({ISO8601_DATE}).type_id)
 
Result.extend (({ISO8601_DATE_TIME}).type_id)
 
Result.extend (({ISO8601_TIME}).type_id)
 
Result.extend (({ISO8601_DURATION}).type_id)


 
Result.extend (({TERMINOLOGY_CODE}).type_id)
 
Result.extend (({URI}).type_id)
 
end

I just want to know if dynamic_hash_item_type is in that list, by the simplest means possible (e.g. I don't care if I have to put 'detachable' on every item in the list).

thanks

- thomas

Emmanuel Stapf

unread,
Jan 4, 2016, 7:05:56 PM1/4/16
to eiffel...@googlegroups.com

Indeed nothing changes for .NET, so previous workarounds still have to be applied.

 

Manu

--

Emmanuel Stapf

unread,
Jan 4, 2016, 7:12:59 PM1/4/16
to Eiffel Users

I would drop the `attached_type’ in the implementation of is_dt_primitive_atomic_type because the ID you will get from querying directly the actual generic parameter type from the HASH_TABLE will carry the proper attachment mark. Now if you can have detachable type for items, then make sure to add the detachable version of the reference types in your `dt_primitive_atomic_types’ table, i.e.

 

Result.extend (({STRING_8}).type_id)

Result.extend (({detachable STRING_8}).type_id)

 

Regards,

Manu

Thomas Beale

unread,
Jan 5, 2016, 6:46:23 AM1/5/16
to Eiffel Users, ma...@eiffel.com


On Tuesday, January 5, 2016 at 12:12:59 AM UTC, Emmanuel STAPF [ES] wrote:

I would drop the `attached_type’ in the implementation of is_dt_primitive_atomic_type because the ID you will get from querying directly the actual generic parameter type from the HASH_TABLE will carry the proper attachment mark.


in that case, that's true, but checking the type of the generic parameter of containers is just one use of is_dt_primitive_atomic_type, there are others which just obtain the dynamic type from an object.
 

Now if you can have detachable type for items, then make sure to add the detachable version of the reference types in your `dt_primitive_atomic_types’ table, i.e.

 

Result.extend (({STRING_8}).type_id)

Result.extend (({detachable STRING_8}).type_id)



this will of course double the size of my tables... it really seems that simple type testing is much harder than it should be. 

Is your real suggestion to rewrite the type testing code using field_conforms_to()? But that still entails looping through my type tables and making that call... also not efficient.

There must be a better strategy here...

- thomas

Emmanuel Stapf

unread,
Jan 5, 2016, 9:50:01 AM1/5/16
to Eiffel Users
> in that case, that's true, but checking the type of the generic
> parameter of containers is just one use of
> is_dt_primitive_atomic_type, there are others which just obtain the
> dynamic type from an object.

In the old way, you will get the detachable type ID. In the new way (only available in experimental mode), you will always get an attached type ID. This is why, even if you are increasing the size of your table which should have a minimal impact on performance, it will work now and then.

> Result.extend (({STRING_8}).type_id)
> Result.extend (({detachable STRING_8}).type_id)

Actually the code above is not full-proof so use a HASH_TABLE instead of an ARRAYED_LIST and make sure to use `put' or `force' but not `extend' as in some situation (e.g. compiling in non-void-safe mode) the ID will be duplicated.

> Is your real suggestion to rewrite the type testing code using
> field_conforms_to()? But that still entails looping through my type
> tables and making that call... also not efficient.

If you are manipulating fields, this is the best thing to do. The less you do with types but the more you do with objects, the better and safer your code will be. This is the approach we have taken in our serialization code and we have barely changed it the past few years.

Regards,
Manu

Thomas Beale

unread,
Jan 6, 2016, 6:01:58 PM1/6/16
to Eiffel Users, ma...@eiffel.com
I've been  looking at the code. There are around 1,500 lines of code affected, and in fact, a pretty high dependence on using type ids rather than testing types of objects. 

Fixing this is going to be major surgery, but I have to do something because it's broken every project we have in Eiffel, they all rely on the ODIN serialiser.

Is it the case that attached_type () is going to be fixed in the future?

If not, I think going back to 14.x is probably the rational thing to do.

- thomas

Emmanuel Stapf

unread,
Jan 18, 2016, 9:01:21 AM1/18/16
to Eiffel Users

Here is the code I suggested you to write to replace `attached_type’ in REFLECTOR while waiting for a fix:

 

                is_attached_type (a_type_id: INTEGER): BOOLEAN

                                                -- Is `a_type_id' an attached type?

                                require

                                                a_type_non_negative: a_type_id >= 0

                                do

                                                if type_of_type (a_type_id).is_expanded then

                                                                Result := True

                                                else

                                                                Result := {ISE_RUNTIME}.is_attached_type (a_type_id)

                                                end

                                end

 

 

                attached_type (type_id: INTEGER): INTEGER

                                                -- Attached version of `type_id'.

                                require

                                                type_id_nonnegative: type_id >= 0

                                do

                                                if type_of_type (type_id).is_expanded then

                                                                Result := type_id

                                                else

                                                                Result := {ISE_RUNTIME}.attached_type (type_id)

                                                end

                                ensure

                                                unchanged_if_attached: is_attached_type (type_id) implies type_id = Result

                                end

 

Did you try that? If so and it doesn’t work, the error is somewhere else.

 

Regards,

Manu

 

From: Thomas Beale [mailto:wolan...@gmail.com]
Sent: Thursday, January 07, 2016 08:02
To: Eiffel Users <eiffel...@googlegroups.com>
Cc: ma...@eiffel.com
Subject: Re: [eiffel-users] Easiest way to do type comparisons?

 

I've been  looking at the code. There are around 1,500 lines of code affected, and in fact, a pretty high dependence on using type ids rather than testing types of objects. 

Thomas Beale

unread,
Jan 19, 2016, 9:39:10 AM1/19/16
to Eiffel Users, ma...@eiffel.com

I will try this in the next few days.

Thomas Beale

unread,
Jan 25, 2016, 10:35:44 AM1/25/16
to Eiffel Users, ma...@eiffel.com
I've tried this now, it appears to work. 

Thanks
Reply all
Reply to author
Forward
0 new messages