In §, we discussed some of the
advantages structured types offer over lists and sets for
storing data. Because instances of a structured type are created by
calling a Darwin function which returns an unevaluated function as
the structure, we are able to do extensive error checking,
simplification and normalization. However, both simple types and
the structured type ProEntry defined in
§
still have the
undesirable property that we must remember which index of the
structure corresponds to which field of the data type. In our basic example
ProEntry, the first index is the name of the entry, the
second is database where the entry was found, the third is the
accession number into this database, and so forth.
> protent := ProEntry('ABL1_CAEEL', 'SwissProt', 'P03949', 'C. ELEGANS', > 'NNEWCEARLYSTRKNDASNQRRLGEIGWVPSNFIAPYNSLDK', 42); > protent[1]; # retrieve the name of the sequence ABL1_CAEEL > protent[4]; # retrieve the organism name C. ELEGANS > protent[6]; # retrieve the length of the sequence 42Darwin offers an alternative method called selection for accessing the contents of a structure. Essentially, selection allows us to assign a name to a field of a type in much the same way we assign names to variables and routines. To accomplish this, we create a function named ProEntry_select (in general, the naming convention is the name of the structure type, followed by an underscore symbol (
_
), followed by the
Darwin keyword select). The keyword select is a built-in
name with special polymorphic status (for more details on polymorphism
see Chapter > ProEntry_select := proc(u, sel, val) > upper_sel := uppercase(sel); > if ( upper_sel = 'NAME' ) then > if ( nargs = 3 ) then u[1] := val else u[1] fi; > elif ( upper_sel = 'DB' ) then > if ( nargs = 3 ) then u[2] := val else u[2] fi; > elif ( upper_sel = 'AC' ) then > if ( nargs = 3 ) then u[3] := val else u[3] fi; > elif ( upper_sel = 'ORGANISM' ) then > if ( nargs = 3 ) then u[4] := val else u[4] fi; > elif ( upper_sel = 'SEQUENCE' ) then > if ( nargs = 3 ) then u[5] := val else u[5] fi; > elif ( upper_sel = 'LENGTH' ) then > if ( nargs = 3 ) then u[6] := val else u[6] fi; > fi; > end:Here u is a structure of type ProEntry, sel is the name of the field we wish to access, and val is the value we would like to assign to field u[sel]. A function call such as
> protent['DB'] := 'GenBank';is equivalent to the call
> ProEntry_select( protent, 'DB', 'GenBank' );This statement modifies the contents of field 'DB' (the second index) of protent. To examine the contents of a field from protent we omit the third argument val. In this case val is empty and the system name nargs is assigned the value two. ProEntry_select only returns the contents of the field labeled 'DB'.
> protent['Names']; > protent['DB']; > protent['DB']:= 'GenBank'; > protent['DB']; > protent['organism']; > protent['organism'] := 'H. influenzae'; > protent['organism'];
> protent[6] := 42; > protent['Length'] := 42;although they both assign values to the sixth element of the structure protent. The latter statement invokes the ProEntry_select function while the former statement does not. This means that whatever functions ProEntry_select performs above and beyond the assignment of 42 to the field Length (the sixth index) to protent will not be carried out by the assignment protent[6] := 42.