![]() |
|
||||
![]() ![]() ![]() ![]() ![]() ![]() ![]() |
|||||
|
|
|||||
| Prerequisite Concepts | Related Syntax | ||||
Records, extended |
|||||
You can create records that are extensions of other records. This is useful if you have records of different types that share common characteristics. For example, you can declare a record type "publication" with the base characteristics common to all publications:
declare record publication field stream name field stream publisher
You can then create record types for specific types of publications by extending the publication type:
declare record book extends publication field stream author variable field stream year-of-publication field stream ISBN declare record periodical extends publication field integer issues-per-year field stream editor-in-chief field stream ISPN
You can use an extended record type as the base type for creating a more extended (and therefore more specialized type):
declare record novel extends book field stream genre field stream locale variable
A shelf of an extended type can be used in place of a shelf of its base type (or any of its ancestral base types) in most circumstances in which the base type can be used. For instance, if you write a function to print the details of a publication, you can also pass a book, or novel to that function. In the following example, the string source function pub-info takes a publication, but the program passes a book and a periodical to it. Since a book and a periodical have all the fields of a publication, they can be used as a publication:
declare record publication
field stream name
field stream publisher
declare record book
extends publication
field stream author variable
field stream year-of-publication
field stream ISBN
declare record periodical
extends publication
field integer issues-per-year
field stream editor-in-chief
field stream ISPN
define string source function pub-info
value publication p
as
output p:name || "%n"
process
local publication pubs variable
local book war-and-peace
local periodical field-and-stream
set war-and-peace:name to "War and Peace"
set new war-and-peace:author to "Leo Tolstoy"
set field-and-stream:name to "Field and Stream"
set field-and-stream:issues-per-year to "12"
output pub-info war-and-peace
output pub-info field-and-stream
Since a record of an extended type can be used as a record of a base type, you can assign a record of an extended type to a shelf of its base type or to a shelf of any of its ancestor types. Thus you can assign a "novel" record to a shelf of type "book" or a shelf of type "publication":
process
local novel bedtime-reading
local book work-reading
local periodical bathroom-reading
local publication reading-material variable
set bedtime-reading:name to "The Sinister Pig"
set bedtime-reading:publisher to "HarperCollins"
set new bedtime-reading:author to "Tony Hillerman"
set bedtime-reading:year-of-publication to "2003"
set bedtime-reading:ISBN to "006019443X"
set bedtime-reading:genre to "mystery"
set new bedtime-reading:locale to "Four Corners"
set new bedtime-reading:locale to "Mexican border"
set work-reading:name to "Internet Programming with OmniMark"
;initialize rest of work-reading
set bathroom-reading:name to "Reader's Digest"
;initialize rest of bathroom-reading
set new reading-material to bedtime-reading
set new reading-material to work-reading
set new reading-material to bathroom-reading
output "Stuff I'm currently reading:%n"
repeat over reading-material
output reading-material:name || "%n"
again
If you have a shelf of a base type that contains records of extended types, you can safely address the fields that belong to the base type and are therefore common to all extended types. If you want to address fields that are specific to any of the extended types, you first need to determine the precise type of each record on the shelf. You can do this using do select-type:
repeat over reading-material
output reading-material:name
do select-type reading-material as r
case novel
output ", a " || r:genre || " novel%n"
case book
output "by "
repeat over r:author as a
output a
output "," unless #last
again
output "%n"
case periodical
output ", a periodical edited by " || r:editor-in-chief
else
output "%n"
done
again
Rather than using do select-type every time you need to determine the exact type of a record, you can create a collection of overloaded type-specific functions using the dynamic and overriding keywords. To do this you define a dynamic function for the base type and an overriding function for each of the extensions of the base type. The following code defines several extensions of publication, and a display function for each one. The repeat loop at the end of the code calls the display function for each items on a shelf of publications. The appropriate overriding function is called dynamically based on the type of each individual item on the shelf:
declare record publication
field stream name
field stream publisher
declare record book
extends publication
field stream author variable
field stream year-of-publication
field stream ISBN
declare record periodical
extends publication
field integer issues-per-year
field stream editor-in-chief
field stream ISPN
declare record novel
extends book
field stream genre
field stream locale variable
define dynamic string source function display
value publication p
as
output p:name || "%n"
define overriding string source function display
value novel n
as
output n:name
|| " a "
|| n:genre
|| " novel%n"
define overriding string source function display
value book b
as
output b:name
|| " by "
repeat over b:author as a
output a
output "," unless #last
again
output "%n"
define overriding string source function display
value periodical p
as
output p:name
|| ", a periodical%n"
process
local novel bedtime-reading
local book work-reading
local periodical bathroom-reading
local publication reading-material variable
set bedtime-reading:name to "The Sinister Pig"
set bedtime-reading:publisher to "HarperCollins"
set new bedtime-reading:author to "Tony Hillerman"
set bedtime-reading:year-of-publication to "2003"
set bedtime-reading:ISBN to "006019443X"
set bedtime-reading:genre to "mystery"
set new bedtime-reading:locale to "Four Corners"
set new bedtime-reading:locale to "Mexican border"
set work-reading:name to "Internet Programming with OmniMark"
set new work-reading:author to "Mark Baker"
;initialize rest of work-reading
set bathroom-reading:name to "Reader's Digest"
;initialize rest of bathroom-reading
set new reading-material to bedtime-reading
set new reading-material to work-reading
set new reading-material to bathroom-reading
repeat over reading-material
output display reading-material
again
Suppose you want to write a function that will add novels to a shelf. You could write the function like this:
define function add-novels
into modifiable novel n
as
local novel x
repeat
;populate fields of x
set new n to x
again
This works so long as you only pass shelves of type novel to the function. However, you may want to be able to pass shelves of type publication or type book to the function. The type novel is an extension of book and publication, so you can place a novel record on a book or publication shelf. However, you cannot pass a book or a publication shelf as a modifiable argument to a function that expects a shelf of type novel. For instance, if you passed it a shelf of type "publication", that shelf might contain a record of type "periodical". The function, however, thinks that the shelf is of type "novel", and a periodical cannot be used as a novel.
To write a function that add novels to a shelf, but that will accept a book or publication shelf as an argument, you must use a write only argument:
define function add-novels
into write-only novel n
as
local novel x
repeat
;populate fields of x
set new n to x
again
With a write-only argument the function is forbidden to perform any operation on the shelf which is specific to the type of the individual items on the shelf. It cannot read or write the fields of individual records or even inquire about their type using do select-type. All it can do is add items to the shelf, replace an existing item with a new item, or delete an item.
The only way to add a new novel to a write-only argument shelf, therefore, is to create a local variable of type novel, update its properties, and then add it to the write-only argument shelf.
|
Prerequisite Concepts Functions Records Shelves |
Related Syntax cast define overloaded function, dynamic, overriding do select-type function, define function record, declare record |
Copyright © Stilo International plc, 1988-2008.