Let's look at a single practical example.
Let us say we're programming a menu navigation for a game. We want to store for each menu-item
- The entry's name
- The other menu we'll reach after pressing it.
- The action that would be performed when pressing the menu.
When a menu-item is pressed, we'll activate the menu-item action and then move to the next menu. So our menu would be a simple list of dictionaries, like so:
options,start_menu,about = [],[],[]
def do_nothing(): pass
about += [
{'name':"copyright by...",'action':None,'menu':about},
{'name':"back",'action':do_nothing,'menu':start_menu}
]
options += [
{'name':"volume up",'action':volumeUp,'menu':options},
{'name':"save",'action':save,'menu':start_menu},
{'name':"back without save",'action':do_nothing,'menu':start_menu}
]
start_menu += [
{'name':"Exit",'action':f,'menu':None}, # no next menu since we quite
{'name':"Options",'action':do_nothing,'menu':options},
{'name':"About",'action':do_nothing,'menu':about}
]
See how about
is cyclic:
>>> print about
[{'action': None, 'menu': [...], 'name': 'copyright by...'},#etc.
# see the ellipsis (...)
When a menu item is pressed we'll issue the following on-click function:
def menu_item_pressed(item):
log("menu item '%s' pressed" % item['name'])
item['action']()
set_next_menu(item['menu'])
Now, if we wouldn't have cyclic data structures, we wouldn't be able to have a menu item that points to itself, and, for instance, after pressing the volume-up function we would have to leave the options menu.
If cyclic data structures wouldn't be possible, we'll have to implement it ourselves, for example the menu item would be:
class SelfReferenceMarkerClass: pass
#singleton global marker for self reference
SelfReferenceMarker = SelfReferenceMarkerClass()
about += [
{'name':"copyright by...",'action':None,'menu':srm},
{'name':"back",'action':do_nothing,'menu':start_menu}
]
the menu_item_pressed
function would be:
def menu_item_pressed(item):
item['action']()
if (item['menu'] == SelfReferenceMarker):
set_next_menu(get_previous_menu())
else:
set_next_menu(item['menu'])
The first example is a little bit nicer, but yes, not supporting self references is not such a big deal IMHO, as it's easy to overcome this limitation.
The menus example is like a graph with self references, where we store the graph by lists of vertex pointers (every vertex is a list of pointers to other vertices). In this example we needed self edges (a vertex that points to itself), thus python's support for cyclic data structures is useful.