Perfect Developer basic tutorial 5 This page last modified 2011-10-30 (JAC)
Schemas

In Perfect, a method that can change something is called a schema. A schema might be declared as changing the current instance of the class of which it is a member, or one or more of its parameters, or both.

Let's illustrate schemas by extending our Book class to include some information that is liable to change after a Book has been created. We'll assume that a book might be available in any combination of paperback, hardback and Braille versions.

Here is a suitable enumeration class to represent these versions:

class PublishedVersion ^= enum paperback, hardback, Braille end;

If you are trying this example out, place this declaration in the Book.pd file, but outside the declaration of class Book. Alternatively, you could place it in its own file, and then import that file into Book.pd.

Now let's include a variable in class Book to represent the versions in which the book is available. Each book might be available in any combination of versions, or none at all (i.e. the book is out-of-print), so we need to store a set of versions.

Add the following variable declaration to the abstract data:

var versions: set of PublishedVersion;

(alternatively, just include the new declaration in the existing var declaration list). Now you will need to extend the constructor postconditions to initialize the new variable - let's initialize to the empty set.

Now you need to add two new methods: a method to be called when a book is published in a particular version, and a method to be called when a particular version goes out-of-print.

Here are the two method declarations:

schema !publish(v: PublishedVersion)
  post versions! = versions.append(v);

schema !outOfPrint(v: PublishedVersion)
  pre v in versions
  post versions! = versions.remove(v);

This is what it means:

The exclamation-mark before each schema name indicates that the schemas may change the current object. If the schema name is not preceded by an exclamation mark, this means that the schema does not change the current object (those of you familiar with C++ may liken this to a const method).

The absence of exclamation marks in the parameter lists indicates that the schemas do not change their parameters (by now, you may be getting the idea that in Perfect, an exclamation mark always means that the value of an associated entity changes).

Schemas may have preconditions, just like functions and constructors.

The schema postcondition describes the final state of objects modified by the schema, just as a constructor postcondition describes the state of the constructed object. However, a schema postcondition may depend on the initial value of the current object (whereas a constructor postcondition can't depend on the initial value, because the object doesn't have a value until the constructor completes).

You also need to initialize the new attribute versions in each of the constructors. This leaves the complete Book file looking like this:

class PublishedVersion ^= enum paperback, hardback, Braille end;

class Book ^=
abstract
  var title: string,
      authors: set of string,
      versions: set of PublishedVersion;
  invariant #authors ~= 0;

interface
  function
title;

  function hasAuthor(author: string): bool
    ^= author in authors;

  opaque function anyAuthor: string
    ^= any authors;

  function toString(byWord, andWord: string): string
    ^= ( let quotedTitle ^= "'" ++ title ++ "'";
         let byWithSpaces ^= " " ++ byWord ++ " ";
         let andWithSpaces ^= " " ++ andWord ++ " ";
         quotedTitle ++ byWithSpaces ++ interleave(authors.permndec, andWithSpaces)
       );

  redefine function toString: string
    ^= toString("by", "and");

  schema !publish(v: PublishedVersion)
    post versions! = versions.append(v);

  schema !outOfPrint(v: PublishedVersion)
    pre v in versions
    post versions! = versions.remove(v);

  build{!title: string, !authors: set of string}
    pre #authors ~= 0
    post versions! = set of PublishedVersion {};

  build{!title: string, author: string}
    post authors! = set of string{author},
         versions! = set of PublishedVersion {};
end;

Knowledge round-up quiz

Exercise

Modify the 'toString' method to include the set of available versions in the returned string, e.g.:

Hint: the toString method is automatically defined for enumeration classes. Use the permndec function to turn the set of versions into a sequence, i.e. versions.permndec yields the available versions as a sequence.

Next:  Calling a schema

 

Save My Place Glossary Language Reference Manual
Tutorials Overview Main site   
Copyright © 1997-2012 Escher Technologies Limited. All rights reserved. Information is subject to change without notice.