Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Access control

A type that keeps rules about its data, such as "a balance never goes negative", can only keep them if nothing else can write that data. Access sections let a type decide which of its members the rest of the program may touch.

type Account
  public:                           '' anyone may use these
    declare constructor( byval opening as int64 )
    declare sub Deposit( byval amount as int64 )
    declare function Withdraw( byval amount as int64 ) as boolean
    declare function Balance( ) as int64
  private:                          '' only Account's own methods
    declare sub Record( byref what as ustring )
    balance_ as int64
    entries_ as int32
end type

constructor Account( byval opening as int64 )
    balance_ = iif( opening < 0, 0, opening )
    Record( "opened" )
end constructor

sub Account.Deposit( byval amount as int64 )
    if amount <= 0 then exit sub    '' the type keeps its own rules
    balance_ += amount
    Record( "deposit" )
end sub

function Account.Withdraw( byval amount as int64 ) as boolean
    if amount <= 0 orelse amount > balance_ then return false
    balance_ -= amount
    Record( "withdrawal" )
    return true
end function

function Account.Balance( ) as int64
    return balance_
end function

'' A private method is a helper the outside world never sees.
sub Account.Record( byref what as ustring )
    entries_ += 1
    print "  entry"; entries_; ": "; what
end sub

dim as Account acct = Account( 100 )
acct.Deposit( 50 )
acct.Deposit( -1000 )               '' ignored
var tooMuch = acct.Withdraw( 500 )
var enough = acct.Withdraw( 30 )
print "withdraw 500: "; tooMuch; ", withdraw 30: "; enough
print "balance:"; acct.Balance( )

Output

  entry 1: opened
  entry 2: deposit
  entry 3: withdrawal
withdraw 500: false, withdraw 30: true
balance: 120

Inside a type, a label starts a section that runs to the next label:

LabelMembers reachable from
public:anywhere; this is the default before any label
private:the type's own methods, constructors and operators only
protected:the type's own methods and those of types derived from it

The private section of Account holds the balance, an entry counter and Record, a helper method. Every change to the balance goes through Deposit or Withdraw, which refuse what the account does not allow, so the balance cannot go wrong from outside. Reaching for the field directly is a compile error:

type Account
    declare function Balance( ) as int64
  private:
    balance_ as int64
end type

function Account.Balance( ) as int64
    return balance_
end function

dim as Account acct
acct.balance_ = 1000000             '' refused: balance_ is private
accesserror.tiko(12,5): error TKO0625: 'balance_' is not accessible here
     |
  12 | acct.balance_ = 1000000             '' refused: balance_ is private
     |     ^

A global operator, such as an operator = written for the type, is not a method, so it sees only the public members too; build it from the type's public methods. protected: matters once types extend one another, in Inheritance.

The trailing underscore on balance_ is a naming habit, not syntax. It marks the data the methods look after and leaves the plain name free for a method or property that exposes it.

Status in this version

A type with a private constructor and a public static function that creates it is the usual way to insist that objects are made only through that function. In this version var acct = Account.Open( 100 ) is refused with TKO0633 as soon as the type has any private constructor, so that pattern cannot be used yet.

Activities

  1. Add a public Entries( ) function that returns how many entries Record has made.
  2. Move Deposit into the private section and read the error for acct.Deposit( 50 ).