"down-casting" in Eiffel

by Rouan van Dalen (modified: 2010 Oct 11)

Hi everyone.

I am new to Eiffel and have worked through the book: "Touch of Class". Great book. I am now looking forward to writing more substantial code in Eiffel.

While playing around with the language I came across the need to "cast" the type of a list from a more general type to a more specific type. The mechanism I came up with is a re-usable component:

-- NOTE: some code elements omitted for brevity. class CAST [G, H] create make feature {NONE} -- Initialization make -- Initialization for `Current'. do end feature -- Cast Operations to_linked_list (iter: LINKED_LIST [G]): LINKED_LIST [H] -- Convert the supplied LINKED_LIST elements of type G to a LINKED_LIST of elements of type H. local cast_list: LINKED_LIST [H] do create cast_list.make across iter as item loop if attached {H} item as elem then cast_list.extend (elem) end end Result := cast_list end end

Using this CAST class looks like this:

foo: LINKED_LIST [B] local list_a: LINKED_LIST [A] c: CAST [A, B] do create list_a.make create c.make Result := c.to_linked_list (list_a) end

As I am new to Eiffel, I would like more experienced developers to guide me in this pattern. Is there a better (more idiomatic) way of doing this type of down-casting in Eiffel? It is something I need to do a lot because of the type of code I am writing. Some of the down-casting can be replaced by the Visitor design pattern, but the Visitor pattern will not always work and I need to do narrowing-casts.

Any comments are appreciated.

Comments
  • Colin LeMahieu (14 years ago 12/10/2010)

    The object test is the only way to do a downcast. There used to be a conditional assignment but that was deprecated in favor of the object test. If any of the items in the list aren't an {H} the resultant list will be a different length. I probably wouldn't make a generic CAST class since this really isn't modeling any data, it's just holding functions. Maybe something like:

    expanded class SPECIFIC_LIST [G, H] create make, default_create feature make (source: LINKED_LIST [G]) do create list.make across source as source_l loop if attached {H} source_l.item as item_l then list.extend (item_l) else (create {DEVELOPER_EXCEPTION}).raise end end end list: LINKED_LIST [H]

    This way your class is modeling data, and the data is the list.