Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Double dispatch
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==== Classic Spaceship example ==== A variation of the classic Spaceship example has one or more spaceship objects roaming about a universe filled with other items like rogue asteroids and space stations. What we want is a double-dispatch method for handling encounters (e.g. possible collisions) between two co-variant objects in our make-believe universe. In our example below, the output excursion of our USS Enterprise and USS Excelsior will be: <syntaxhighlight lang="text"> Starship Enterprise changes position from A-001 to A-002. Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 1'! Starship Enterprise changes position from A-002 to A-003. Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 2'! Starship Enterprise beams a science team to Starship Excelsior as they pass! Starship Enterprise changes position from A-003 to A-004. Starship Excelsior changes position from A-003 to A-005. Starship Enterprise takes evasive action, avoiding Asteroid `Rogue 3'! Starship Excelsior is near Space Station Deep Space 9 and is dockable. Starship Enterprise changes position from A-004 to A-005. Starship Enterprise beams a science team to Starship Excelsior as they pass! Starship Enterprise is near Space Station Deep Space 9 and is dockable. </syntaxhighlight> ===== Visitor ===== The visitor for the classic Spaceship example also has a double-dispatch mechanism. <syntaxhighlight lang="eiffel" line highlight="35"> make -- Allow SPACESHIP objects to visit and move about in a universe. local l_universe: ARRAYED_LIST [SPACE_OBJECT] l_enterprise, l_excelsior: SPACESHIP do create l_enterprise.make_with_name ("Enterprise", "A-001") create l_excelsior.make_with_name ("Excelsior", "A-003") create l_universe.make (0) l_universe.force (l_enterprise) l_universe.force (create {ASTEROID}.make_with_name ("Rogue 1", "A-002")) l_universe.force (create {ASTEROID}.make_with_name ("Rogue 2", "A-003")) l_universe.force (l_excelsior) l_universe.force (create {ASTEROID}.make_with_name ("Rogue 3", "A-004")) l_universe.force (create {SPACESTATION}.make_with_name ("Deep Space 9", "A-005")) visit (l_enterprise, l_universe) l_enterprise.set_position ("A-002") visit (l_enterprise, l_universe) l_enterprise.set_position ("A-003") visit (l_enterprise, l_universe) l_enterprise.set_position ("A-004") l_excelsior.set_position ("A-005") visit (l_enterprise, l_universe) visit (l_excelsior, l_universe) l_enterprise.set_position ("A-005") visit (l_enterprise, l_universe) end feature {NONE} -- Implementation visit (a_object: SPACE_OBJECT; a_universe: ARRAYED_LIST [SPACE_OBJECT]) -- `a_object' visits `a_universe'. do across a_universe as ic_universe loop check attached {SPACE_OBJECT} ic_universe.item as al_universe_object then a_object.encounter_agent.call ([al_universe_object.sensor_data_agent]) end end end </syntaxhighlight> The double-dispatch can be seen in line #35, where two indirect agents are working together to provide two co-variant calls working in perfect polymorphic concert with each other. The `a_object' of the `visit' feature has an `encounter_agent' which is called with the sensor data of the `sensor_data_agent' coming from the `al_universe_object'. The other interesting part of this particular example is the SPACE_OBJECT class and its `encounter' feature: ===== Visitor action ===== The only exported features of a SPACE_OBJECT are the agents for encounter and sensor data, as well as the capacity to set a new position. As one object (the spaceship) visits each object in the universe, the sensor data is collected and passed to the visiting object in its encounter agent. There, the sensor data from the sensor_data_agent (that isβthe data element items of the sensor_data TUPLE as returned by the sensor_data_agent query) are evaluated against the current object and a course of action is taken based on that evaluation (see `encounter' in SPACE_OBJECT below). All other data is exported to {NONE}. This is similar to C, C++ and Java scopes of Private. As non-exported features, the data and routines are used only internally by each SPACE_OBJECT. Finally, note that encounter calls to `print' do not include specific information about possible descendant classes of SPACE_OBJECT! The only thing found at this level in the inheritance are general relational aspects based completely on what can be known from the attributes and routines of a general SPACE_OBJECT. The fact that the output of the `print' makes sense to us, as human beings, based on what we know or imagine about Star ships, space stations and asteroids is merely logical planning or coincidence. The SPACE_OBJECT is not programmed with any specific knowledge of its descendants. <syntaxhighlight lang="eiffel" line> deferred class SPACE_OBJECT feature {NONE} -- Initialization make_with_name (a_name: like name; a_position: like position) -- Initialize Current with `a_name' and `a_position'. do name := a_name position := a_position sensor_data_agent := agent sensor_data encounter_agent := agent encounter ensure name_set: name.same_string (a_name) position_set: position.same_string (a_position) end feature -- Access encounter_agent: PROCEDURE [ANY, TUPLE] -- Agent for managing encounters with Current. sensor_data_agent: FUNCTION [ANY, TUPLE, attached like sensor_data_anchor] -- Agent for returning sensor data of Current. feature -- Settings set_position (a_position: like position) -- Set `position' with `a_position'. do print (type + " " + name + " changes position from " + position + " to " + a_position + ".%N") position := a_position ensure position_set: position.same_string (a_position) end feature {NONE} -- Implementation encounter (a_sensor_agent: FUNCTION [ANY, TUPLE, attached like sensor_data_anchor]) -- Detect and report on collision status of Current with `a_radar_agent'. do a_sensor_agent.call ([Void]) check attached {like sensor_data_anchor} a_sensor_agent.last_result as al_sensor_data then if not name.same_string (al_sensor_data.name) then if (position.same_string (al_sensor_data.position)) then if ((al_sensor_data.is_dockable and is_dockable) and (is_manned and al_sensor_data.is_manned) and (is_maneuverable and al_sensor_data.is_not_maneuverable)) then print (type + " " + name + " is near " + al_sensor_data.type + " " + al_sensor_data.name + " and is dockable.%N") elseif ((is_dockable and al_sensor_data.is_dockable) and (is_manned and al_sensor_data.is_manned) and (is_maneuverable and al_sensor_data.is_maneuverable)) then print (type + " " + name + " beams a science team to " + al_sensor_data.type + " " + al_sensor_data.name + " as they pass!%N") elseif (is_manned and al_sensor_data.is_not_manned) then print (type + " " + name + " takes evasive action, avoiding " + al_sensor_data.type + " `" + al_sensor_data.name + "'!%N") end end end end end name: STRING -- Name of Current. type: STRING -- Type of Current. deferred end position: STRING -- Position of Current. is_dockable: BOOLEAN -- Is Current dockable with another manned object? deferred end is_manned: BOOLEAN -- Is Current a manned object? deferred end is_maneuverable: BOOLEAN -- Is Current capable of being moved? deferred end sensor_data: attached like sensor_data_anchor -- Sensor data of Current. do Result := [name, type, position, is_dockable, not is_dockable, is_manned, not is_manned, is_maneuverable, not is_maneuverable] end sensor_data_anchor: detachable TUPLE [name, type, position: STRING; is_dockable, is_not_dockable, is_manned, is_not_manned, is_maneuverable, is_not_maneuverable: BOOLEAN] -- Sensor data type anchor of Current. end </syntaxhighlight> There are three descendant classes of SPACE_OBJECT: <syntaxhighlight lang="eiffel"> SPACE_OBJECT ASTEROID SPACESHIP SPACESTATION </syntaxhighlight> In our example, the ASTEROID class is used for the `Rogue' items, SPACESHIP for the two star ships and SPACESTATION for Deep Space Nine. In each class, the only specialization is the setting of the `type' feature and of certain properties of the object. The `name' is supplied in the creation routine as well as the `position'. For example: Below is the SPACESHIP example. <syntaxhighlight lang="eiffel" line> class SPACESHIP inherit SPACE_OBJECT create make_with_name feature {NONE} -- Implementation type: STRING = "Starship" -- <Precursor> is_dockable: BOOLEAN = True -- <Precursor> is_manned: BOOLEAN = True -- <Precursor> is_maneuverable: BOOLEAN = True -- <Precursor> end </syntaxhighlight> So, any SPACESHIP in our universe is dock-able, manned and maneuverable. Other objects, like Asteroids are none of these things. A SPACESTATION, on the other hand, is both dock-able and manned, but is not maneuverable. Thus, when one object has an encounter with another, it first checks to see if the positions put them in the vicinity of each other and if they are, then the objects interact based upon their basic properties. Note that objects with the same type and name are considered to the same object, so an interaction is logically disallowed.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)