Skip to content

Resources design exercise

jennalwise edited this page Nov 1, 2017 · 15 revisions

Typestate

Most real world problems or scenarios can be solved or modeled with an emphasis on state, sometimes for the better. For example, consider the state chart diagram below used to model the state of a wallet with money and a license.

Wallet State Chart

Resources

For each task the money and license must follow certain properties/restrictions:

  • The money and license cannot be duplicated.

    For example,

    @Resource class Money {...}
    
    class Person {
      Wallet wallet;
    
      // If I find money on the street, I put it in my wallet.
      transaction foundMoney(Money newMoney) {
        Money money = newMoney;
        wallet.addMoney(newMoney); // COMPILE ERROR: Money cannot be duplicated because it is a @Resource
        wallet.addMoney(money); // no compiler error
      }
    }
  • The money and license can only be used once.

    For example,

    @Resource class Money {...}
    
    class Person {
      Wallet wallet;
    
      // If I find money on the street, I put it in my wallet.
      transaction foundMoney(Money money) {
        wallet.addMoney(money);
        wallet.addMoney(money); // COMPILE ERROR: can't consume Money twice because it is a @Resource.
      }
    }
  • The money and license cannot be dropped on the floor.

    • They must be either passed, returned, or released.

The money and license are special and will be referred to and marked as resources.

Task 1

The Wallet state chart diagram is implemented as a class with state member variables and transaction methods. The state member variables contain their own member variables (resources) appropriate to each state and the transaction methods contain one or more transitions (-><state name>) from the current state to another.

However, the code below is incomplete as resources are not being handled properly. Your task is to add to and/or modify the code below (where indicated with // TODO:) to ensure the license and money resources are handled properly by following the rules listed in the Resources section above.

Do not limit yourself to known language constructs; ie. make up any language features you may want. We want to see the kind of code you would want to be able to write.

@Resource class License {...}
@Resource class Money {...}

class Wallet {
  state HasLicenseOnly;
  state HasMoneyOnly;
  state HasLicenseAndMoney;
  state Empty;

  License license available in HasLicenseOnly, HasLicenseAndMoney;
  Money money available in HasMoneyOnly, HasLicenseAndMoney;

  transaction putInMoney(Money newMoney) available in Empty {...}

  transaction putInMoney(Money newMoney) available in HasLicenseOnly {
    // TODO: add money to the wallet, there is not a wallet capacity for money
    // you may modify the method declaration (like with a return statement/type) or the state transition to your liking

    ->HasLicenseAndMoney
  }

  transaction putInLicense(License newLicense) available in HasMoneyOnly {...}
  transaction putInLicense(License newLicense) available in Empty {...}

  transaction putInLicenseAndMoney(License newLicense, StudentId newMoney) available in Empty {
    // TODO: add a license and money to the wallet, there is not a wallet capacity for money
    // you may modify the method declaration (like with a return statement/type) or the state transition to your liking

    ->HasLicenseAndMoney
  }

  transaction takeOutMoney() available in HasLicenseAndMoney {
    // TODO: remove all the money from the wallet
    // you may modify the method declaration (like with a return statement/type) or the state transition to your liking

    ->HasLicenseOnly
  }

  transaction takeOutMoney() available in HasMoneyOnly {...}
  transaction takeOutLicense() available in HasLicenseOnly {...}
  transaction takeOutLicense() available in HasLicenseAndMoney {...}

  transaction takeOutLicenseAndMoney() available in HasLicenseAndMoney {
    // TODO: remove all the money and the license from the wallet
    // you may modify the method declaration (like with a return statement/type) or the state transition to your liking

    ->Empty
  }
}

Task 2

For this task you will be given various code design options for resource handling based on the Wallet code example from Task 1. Your task is to read and understand each design option.

Passing resources

Option 1

Resources are assigned to the state member variables available in the state being transitioned to with the state transition. All the transition state member variables must be assigned at once.

Ex.

// Option 1
transaction putInLicenseAndMoney(License newLicense, Money newMoney) available in Empty {
  ->HasLicenseAndMoney(license = newLicense, money = newMoney)
}

Option 2

Resources are assigned to the state member variables available in the state being transitioned to before the state transition. The transition state member variables are assigned individually and are annotated with the transition state they are currently in the scope of.

Ex.

// Option 2
transaction putInLicenseAndMoney(License newLicense, Money newMoney) available in Empty {
  HasLicenseAndMoney::license = newLicense;
  HasLicenseAndMoney::money = newMoney;
  ->HasLicenseAndMoney
}

Option 3

Resources are assigned to the state member variables available in the state being transitioned to before the state transition. The transition state member variables are assigned individually.

Ex.

// Option 3
transaction putInLicenseAndMoney(License newLicense, Money newMoney) available in Empty {
  license = newLicense;
  money = newMoney;
  ->HasLicenseAndMoney
}

Option 4

Resources are assigned to the state member variables available in the state being transitioned to after the state transition. The transition state member variables are assigned individually.

Ex.

// Option 4
transaction putInLicenseAndMoney(License newLicense, Money newMoney) available in Empty {
  ->HasLicenseAndMoney
  license = newLicense;
  money = newMoney;
}

Returning Resources

Option 1

When resources in the current state do not exist in the state being transitioned to from the current state, they are returned to an unordered collection. The resources can then be referenced by name. Resources can be added to, removed from, and released through the collection.

Ex.

// Option 1
transaction takeOutLicenseAndMoney() available in HasLicenseAndMoney returns x {
  x = ->Empty //doesn't have to be x (can be named like a variable)

  print(
    "License with license number " +
    x.license.licenseNumber() +
    " is being removed."
  );
  print(
    x.money.value() +
    " dollars are being removed."
  );

  return x;
}

// add to
x += money;
// remove from (x.license can be read only after this)
License newLicense = x.license;
// release single resource
release(x.money);
// release entire collection
release(x);

Option 2

When resources in the current state do not exist in the state being transitioned to from the current state, they are returned to an ordered tuple collection. The resources can then be referenced by an assigned name. The name assignment syntax when performing the transition (see example below) is required. However, after returning from the transaction the tuple can be named as a whole or the elements named individually. Resources may be removed from or released through the tuple collection.

// Option 2
transaction takeOutLicenseAndMoney() available in HasLicenseAndMoney returns (returnLicense, returnMoney) {
  (returnLicense = license, returnMoney = money) = ->Empty

  print("License with license number " +
    returnLicense.licenseNumber +
    " is being removed."
  );
  print(
    returnMoney.value() +
    " is being removed."
  );

  return (returnLicense, returnMoney);
}

// returned tuple
tuple = wallet.takeOutLicenseAndMoney();
// remove from (tuple[0] can be read only after this)
License license = tuple[0];
// release single resource
release(tuple[0]);
// release tuple collection
release(tuple);

// returned tuple
(walletLicense, walletMoney) = wallet.takeOutLicenseAndMoney();

Releasing resources

Option 1

Resources from the current state are released before transitioning from that state to another state where the resources no longer exists.

Ex.

// Option 1
transaction licenseExpires() available in HasLicenseAndMoney {
  console.out("License with license number " +
    license.licenseNumber + " has expired.";

  release(license);

  ->HasMoneyOnly
}

Option 2

Resources from the current state must be returned to a modifying reference (local to the transaction method) if they do not exist in the state being transitioned to and have not been released beforehand. This modifying reference must be released before it goes out of scope.

Ex.

// Option 2
transaction licenseExpires() available in HasLicenseAndMoney {
  returnedLicense = ->HasMoneyOnly

  console.out("License with license number " +
    returnedLicense.licenseNumber + " has expired.";

  release(returnedLicense);
}

Task 3

Implement each of the Passing Resources design options in the following code sample.

class Wallet {

  ...

  License license available in HasLicenseOnly, HasLicenseAndMoney;
  Money money available in HasMoneyOnly, HasLicenseAndMoney;

  transaction putInLicenseAndMoney(License newLicense, Money newMoney) available in Empty returns Money {

		Money overcapacity = new Money(0);

		if (newMoney.value() <= 100) {

		} else {

      double value = newMoney.value();
			double leftover = value - 100;

			overcapacity.add(leftover);
			newMoney.subtract(leftover);

    }

    return overcapacity;
  }

  ...
}

Task 4

Task 5