/**
 * Proof of concept for Object-Oriented Programming in Boppi.
 * Note that this is a very basic notion of OO that only includes private
 * members. It does not support type checking, inheritance or public members.
 * It requires a tremendous amount of boilerplate to work without proper
 * tuples, parametrization or OO class syntax.
 */

//Declaring dummy functions for type aliases because Boppi disallows
//the use of Void directly in a type.
function intToVoid(int a) 0;
function int voidToInt() 0;
function class() 0;



//Class declaration whose sole purpose is to make the code look better.
//`Rectangle` type checks with every other `()->Void` type.
var class Rectangle;



//Helpers for making methods available outside their closure (the function
//references should be passed via a return value if tuples were supported)
//Assigning them immediately to suppress warnings.
var voidToInt _getWidth;  _getWidth  := voidToInt;
var intToVoid _setWidth;  _setWidth  := intToVoid;
var voidToInt _getHeight; _getHeight := voidToInt;
var intToVoid _setHeight; _setHeight := intToVoid;
var voidToInt _getArea;   _getArea   := voidToInt;

//Wrappers to make a `getWidth()` call less of an eyesore and allow you
//to nest these calls without overriding the target closure in between
function int getWidth (Rectangle rect)             { rect();_getWidth() };
function     setWidth (Rectangle rect, int width)  { rect();_setWidth(width) };
function int getHeight(Rectangle rect)             { rect();_getHeight() };
function     setHeight(Rectangle rect, int height) { rect();_setHeight(height) };
function int getArea  (Rectangle rect)             { rect();_getArea() };



//A class definition looks decent apart from the bind function to expose
//the class methods. You can even add constructor arguments to your liking.
function Rectangle newRectangle() {
  var int width;
  var int height;

  function int getWidth()
    width;

  function setWidth(int newWidth) {
    width := newWidth;
  };

  function int getHeight()
    height;

  function setHeight(int newHeight) {
    height := newHeight;
  };

  function int getArea()
    width*height;


  function bind() {
    _getWidth  := getWidth;
    _setWidth  := setWidth;
    _getHeight := getHeight;
    _setHeight := setHeight;
    _getArea   := getArea;
  };
  bind
};



//Time to use the class
var Rectangle a; a := newRectangle();
var Rectangle b; b := newRectangle();

setWidth(a, 4);
setWidth(b, getWidth(a)+2);
setHeight(b, 3);
print(getArea(b));
