Author Topic: Starting Oop with OxygenBasic  (Read 6491 times)

0 Members and 1 Guest are viewing this topic.

Charles Pegge

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #15 on: August 14, 2016, 02:48:24 AM »
Hi Roland,

The static members and the constructor/deconstructor methods of the base class are currently inaccessible. But I have a new release of o2 which supports calls to base constructors and destructors.

It will also do the same for multiple inheritance:to call all the member constructors.

I'm still testing, but I hope to release it within the next 2 weeks or so.

Arnold

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #16 on: August 14, 2016, 11:38:11 PM »
Hi Charles,

it began to dawn on me that I can see the constructor method as a means to construct a 'new' instance of a class with some initialized attributes, similar like a procedure with arguments. This was not obvious to me in the past and so I failed afterwards. (Sorry for my ignorance). If it will be possible in the future to derive constructor methods from base classes this will be fine. The example I refer to was coded in several languages which all seem to be able to create and use constructors.

But if I have understood this basic principle correctly then at the same time it should be possible to get the results without constructors at all - like using procedures without arguments. So I modified the code and this is what came out. If I did everything properly then I reached a real milestone in OOP.

Roland

Code: [Select]
  $filename "Banking.exe"

'include "$/inc/RTL32.inc"
'include "$/inc/RTL64.inc"

% TryAttachConsole
include "$/inc/console.inc"

SetConsoleTitle "Bank Transactions"

class account

  static int count    'class variable

  'data encapsulation - information hiding
  protected ' or private
  ' Attributes
  int account_num     'instance variables
  double balance

  public

  method init()
    count += 1
    balance = 0.00 
  end method

  ' methods for secure access
  method set_account_num(int number)
    account_num = number
  end method

  method get_account_num() as int
    return account_num
  end method

  method get_balance() as double
    return balance
  end method

  method pay_in(double amount)
    balance += amount
    printl "Payed in: " str(amount) & " Euro"
  end method

  method pay_out(double amount)
    balance -= amount
    printl "Payed out: " str(amount) & " Euro"
  end method
   
  method statement_of_account()
    printl "Account Number: " & account_num & " Balance: " & str(balance,2) & " Euro"
  end method
 
  method same_account_num(account *a,*b) as int
    sys aa=a.get_account_num
    sys bb=b.get_account_num
    if aa=bb then return -1
  end method

  method transfer(double amount, account *account_A, *account_Z)
    account_A.statement_of_account()
    account_Z.statement_of_account()
    account_A.pay_out(amount)
    account_Z.pay_in(amount)
    printl "From Account Number: " & account_A.get_account_num()
    print " transferred " & amount & " Euro"
    print " to Account Number: " & account_Z.get_account_num() & cr
    account_A.statement_of_account()
    account_Z.statement_of_account()
  end method

end class

' --> Inheritance
class savings_account

  has account
 
  private
  double rate_percent' ' additional attribute

  public
 
  ' new methods for accessing attribute rate_percent
  method get_rate_percent() as double
    return rate_percent'
  end method

  method set_rate_percent(double interest)
    rate_percent = interest'
  end method
 
  ' new method
  method pay_interest()
    double interest_payable = (rate_percent * balance)/100)
    printl "Interest payable: " & str(interest_payable,2)
    balance += interest_payable ' uses inherited attributes
  end method

end class



' Access class variable via class name
printl "Number of Accounts: " & account.count
account my_account   ' new instance of type account
my_account.init()
my_account.set_account_num(1234567)
printl "Account Number: " & my_account.get_account_num() ' read access
print " Balance: " & my_account.get_balance() & " Euro"
printl "Number of Accounts: " & account.count
account your_account ' new instance of type account
your_account.init()
your_account.set_account_num(2357666)
your_account.statement_of_account()
printl "Number of Accounts: " & account.count

' Assigning (coupling by reference)
account our_account at @your_account
'equiv: account *our_account : @our_account = @your_account
printl "Account Number: " & our_account.get_account_num() ' read access
print " Balance: " & our_account.get_balance() & " Euro"
our_account.statement_of_account()
printl "Number of Accounts: " & account.count
printl


if account.same_account_num(my_account, your_account) then
  printl "My account and your account are identical."
else
  printl "My account and your account are different."
end if

if account.same_account_num(our_account, your_account) then
  printl "Our account and your account are identical."
else
  printl "Our account and your account are different."
end if


my_account.pay_in(2000.00)
my_account.statement_of_account()
printl

your_account.pay_in(100.00)
your_account.statement_of_account()
printl

our_account.pay_in(200.00)
our_account.statement_of_account()
printl

'transfer some money
account.transfer(30.00, my_account, your_account)
printl

' Inheritance

savings_account my_savings_account'(4444990, 5.2)
my_savings_account.init()
my_savings_account.set_account_num(4444990)
my_savings_account.set_rate_percent(5.2)

'each instance of class savings_account has 3 attributes
printl "Account Number: " & my_savings_account.get_account_num() 'inherited attribute
print " Balance: " & my_savings_account.get_balance() &" Euro"'  'inherited attribute
printl "Rate Percent: " & str(my_savings_account.get_rate_percent(),2)' ' new declared attribute
printl "Number of Accounts: " & account.count

'method pay_in(amount), pay_out(amount) and statement_of_account() can be used
my_savings_account.pay_in(250.00)  'inherited methods
my_savings_account.statement_of_account()'
my_savings_account.pay_out(10.00)'
my_savings_account.statement_of_account()

'instances of class savings_account can use the method pay_interest()
my_savings_account.pay_interest()' ' new method
my_savings_account.statement_of_account()'

printl cr & "Hit Enter ... " : waitkey

Output:
Number of Accounts: 0
Account Number: 1234567 Balance: 0 Euro
Number of Accounts: 1
Account Number: 2357666 Balance: 0 Euro
Number of Accounts: 2
Account Number: 2357666 Balance: 0 Euro
Account Number: 2357666 Balance: 0 Euro
Number of Accounts: 2

My account and your account are different.
Our account and your account are identical.
Payed in: 2000 Euro
Account Number: 1234567 Balance: 2000 Euro

Payed in: 100 Euro
Account Number: 2357666 Balance: 100 Euro

Payed in: 200 Euro
Account Number: 2357666 Balance: 300 Euro

Account Number: 1234567 Balance: 2000 Euro
Account Number: 2357666 Balance: 300 Euro
Payed out: 30 Euro
Payed in: 30 Euro
From Account Number: 1234567 transferred 30 Euro to Account Number: 2357666

Account Number: 1234567 Balance: 1970 Euro
Account Number: 2357666 Balance: 330 Euro

Account Number: 4444990 Balance: 0 Euro
Rate Percent: 5.2
Number of Accounts: 3
Payed in: 250 Euro
Account Number: 4444990 Balance: 250 Euro
Payed out: 10 Euro
Account Number: 4444990 Balance: 240 Euro
Interest payable: 12.48
Account Number: 4444990 Balance: 252.48 Euro

Aurel

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #17 on: August 15, 2016, 12:06:39 AM »
Hi..
I am back..  :D
Yes OOP in Oxgen is one of the best and simpliest OOP way

Charles Pegge

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #18 on: August 15, 2016, 01:06:28 AM »
Hi Aurel,

Yes I try to keep the OOP as simple as possible. Constructor and Destructor methods are only necessary when using new and del.

Hi Roland,

Referring back to accessing the base constructor.

If you name the base class member, you will be able to access its constructor and destructor methods:

class cc
has bb bbase
...
bbase.constructor()


Code: [Select]
'ACCESSING THE BASE CLASS BY SPECIFIED NAME
class bb
  private static sys counter

  method constructor()
  counter++
  end method

  method destructor()
  end method

  method CounterVal() as int
  return counter
  end method
end class

class cc
  has bb bbase 'give a name to the base class bb

  method constructor()
  bbase.constructor()
  end method

  method destructor()
  bbase.destructor()
  end method
end class

new cc c
print c.bbase.counterVal()
del c
« Last Edit: August 15, 2016, 01:13:53 AM by Charles Pegge »

Arnold

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #19 on: August 16, 2016, 12:19:34 AM »
Hi Charles,

by using OxygenBasic I learned so many things which I as an autodidact did not understand before. I incorporated your counter method and used constructor again.

This last example deals with overriding methods. It will complete my exploring the basic principles of OOP and I will then try some own simple apps. For the notation I changed the naming a little bit and used camel case most of the time

There are the classes account which is initialized with number and the class savingsAccount which has account and is initialized with number and interest rate.
I created a class giroAccount which has account and is initialized with number and credit limit. It uses a method pay_out which overrides the method of account. I used this method:

  ' --> reimplementation
  method pay_out(double amount)
    if amount <= (balance + limit) then
'      account.pay_out(amount) ' does not work for statement_of_account
      balance -= amount
      printl "Payed out: " str(amount) & " Euro"
    else
      printl "Exceeded Limit!"
    end if
  end method


Would it be possible to use the method pay_out() of class account in some way? When I try account.pay_out then myGiroAccount.statement_of_account() does not show the correct result. Therefore I used the equivalent statements.

Hopefully it is ok that I append the full code. (many statements were done before). It contains everything I learned about OOP so far and how it can be done with OxygenBasic. So it could be interesting for other people too who would like to start with OOP.

Roland

Code: [Select]
' Account7.o2bas

  $filename "Banking.exe"

'include "$/inc/RTL32.inc"
'include "$/inc/RTL64.inc"

% TryAttachConsole
include "$/inc/console.inc"

SetConsoleTitle "Bank Transactions"

'accessing the base class by specified name
class counter
  private static sys counterVal

  method constructor()
  counterVal++
  end method

  method destructor()
  end method

  method count() as int
  return counterVal
  end method
end class

class account

  has counter num 'give a name to the base class counter

  'data encapsulation - information hiding
  protected ' or private
  ' Attributes
  int accountNumber     'instance variables
  double balance

  public

  ' initialize
  method constructor(int number)
    num.constructor
   
    accountNumber = number
    balance = 0.00
  end method
 
  method destructor()
    num.destructor
  end method

  ' methods for secure access
  method getAccountNumber() as int
    return accountNumber
  end method

  method getBalance() as double
    return balance
  end method

  method pay_in(double amount)
    balance += amount
    printl "Payed in: " str(amount) & " Euro"
  end method

  method pay_out(double amount)
    balance -= amount
    printl "Payed out: " str(amount) & " Euro"
  end method
   
  method statement_of_account()
    printl "Account Number: " & accountNumber & " Balance: " & str(balance,2) & " Euro"
  end method
 
  method sameAccountNumber(account *a,*b) as int
    sys aa=a.getAccountNumber
    sys bb=b.getAccountNumber
    if aa=bb then return -1
  end method

  method transfer(double amount, account *account_A, *account_Z)
    account_A.statement_of_account()
    account_Z.statement_of_account()
    account_A.pay_out(amount)
    account_Z.pay_in(amount)
    printl "From Account Number: " & account_A.getAccountNumber()
    print " transferred " & amount & " Euro"
    print " to Account Number: " & account_Z.getAccountNumber() & cr
    account_A.statement_of_account()
    account_Z.statement_of_account()
  end method

end class

' --> Inheritance
class savingsAccount

  has account
 
  private
  double ratePercent ' additional attribute

  public
 
  ' constructor of class savingsAccount
  method constructor(int number, double interest)
    num.constructor()

    accountNumber = number
    balance = 0.00
 
    ratePercent = interest
  end method

  method destructor()
    num.destructor()
  end method

  ' new methods for accessing attribute ratePercent
  method getRatePercent() as double
    return ratePercent'
  end method

  method setRatePercent(double interest)
    ratePercent = interest'
  end method
 
  ' new method
  method pay_interest()
    double interest_payable = (ratePercent * balance)/100)
    printl "Interest payable: " & str(interest_payable,2)
    balance += interest_payable ' uses inherited attributes
  end method

end class


' --> overriding, reimplementation
class giroAccount

  has account

  private 
  double limit
 
  public
 
  method constructor(int number, double bankLine)
    num.constructor()

    accountNumber = number
    limit = abs(bankLine)
  end method

  method destructor()
    num.destructor()
  end method

  method getLimit() as double
    return limit
  end method
 
  ' method for access, check if arg is positiv
  method setLimit(double limit)
    limit = abs(limit)
  end method

  ' --> reimplementation
  method pay_out(double amount)
    if amount <= (balance + limit) then
'      account.pay_out(amount) ' does not work for statement_of_account
      balance -= amount
      printl "Payed out: " str(amount) & " Euro"
    else
      printl "Exceeded Limit!"
    end if
  end method

end class


' Access class variable via class name
printl "Number of Accounts: " & account.num.count
new account myAccount(1234567)   ' new instance of type account
printl "Account Number: " & myAccount.getAccountNumber() ' read access
print " Balance: " & myAccount.getBalance() & " Euro"
printl "Number of Accounts: " & account.num.count
new account yourAccount(2357666) ' new instance of type account
yourAccount.statement_of_account()
printl "Number of Accounts: " & account.num.count

' Assigning (coupling by reference)
account ourAccount at @yourAccount
'equiv: account *ourAccount : @ourAccount = @yourAccount
ourAccount.statement_of_account()
printl "Number of Accounts: " & account.num.count
printl


if account.sameAccountNumber(myAccount, yourAccount) then
  printl "My account and your account are identical."
else
  printl "My account and your account are different."
end if

if account.sameAccountNumber(ourAccount, yourAccount) then
  printl "Our account and your account are identical."
else
  printl "Our account and your account are different."
end if
printl

myAccount.pay_in(2000.00)
myAccount.statement_of_account()
printl

yourAccount.pay_in(100.00)
yourAccount.statement_of_account()
printl

ourAccount.pay_in(200.00)
ourAccount.statement_of_account()
printl

'transfer some money
account.transfer(30.00, myAccount, yourAccount)
printl

' Inheritance

new savingsAccount mySavingsAccount(4444990, 5.2)

'each instance of class savingsAccount has 3 attributes
printl "Account Number: " & mySavingsAccount.getAccountNumber() 'inherited attribute
print " Balance: " & mySavingsAccount.getBalance() &" Euro"'  'inherited attribute
printl "Rate Percent: " & str(mySavingsAccount.getRatePercent(),2)' ' new declared attribute
printl "Number of Accounts: " & account.num.count

'method pay_in(amount), pay_out(amount) and statement_of_account() can be used
mySavingsAccount.pay_in(250.00)  'inherited methods
mySavingsAccount.statement_of_account()'
mySavingsAccount.pay_out(10.00)'
mySavingsAccount.statement_of_account()

'instances of class savingsAccount can use the method pay_interest()
mySavingsAccount.pay_interest()' ' new method
mySavingsAccount.statement_of_account()'
printl

' Reimplementation
myAccount.pay_out(1700.00) ' method pay_out(amout) of class account
myAccount.statement_of_account()
printl
printl "Trying to draw 5000 Euro."
myAccount.pay_out(5000.00) ' method pay_out(amout) of class account
myAccount.statement_of_account()
printl

new giroAccount myGiroAccount(1733065,100)
myGiroAccount.statement_of_account()
printl "Bank Line = " & myGiroAccount.getLimit()
printl "Number of Accounts: " & account.num.count
myGiroAccount.pay_in(400.00)
myGiroAccount.statement_of_account()
printl "Trying to draw 450 Euro."
myGiroAccount.pay_out(450.00) ' method pay_out(amout) of class giroAccount
myGiroAccount.statement_of_account()
printl "Trying to draw 350 Euro."
myGiroAccount.pay_out(350.00) ' method pay_out(amout) of class giroAccount
myGiroAccount.statement_of_account()

printl cr & "Hit Enter ... " : waitkey

del myAccount
del yourAccount 'alias ourAccount
del mySavingsAccount
del myGiroAccount

Output:
...
...
Payed out: 1700 Euro
Account Number: 1234567 Balance: 270 Euro

Trying to draw 5000 Euro.
Payed out: 5000 Euro
Account Number: 1234567 Balance: -4730 Euro

Account Number: 1733065 Balance: 0 Euro
Bank Line = 100
Number of Accounts: 4
Payed in: 400 Euro
Account Number: 1733065 Balance: 400 Euro
Trying to draw 450 Euro.
Payed out: 450 Euro
Account Number: 1733065 Balance: -50 Euro
Trying to draw 350 Euro.
Exceeded Limit!
Account Number: 1733065 Balance: -50 Euro

Hit Enter ...

Arnold

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #20 on: August 16, 2016, 12:41:59 AM »
I would like to ask a last question about the constructor method: Would it be possible to overload the constructors in a class so that I could use:

new account myAccount(number)
new account yourAccount(number, amount)

I saw that Java can use a second constructor overloading the first, some other languages cannot do this.

But I consider this question a little bit academic as I learned that I can initialize an instance of a class by using simple methods. I am not sure if I will need constructors for my projects at all.

Roland

Charles Pegge

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #21 on: August 16, 2016, 03:26:45 AM »

in haste:

Yes, you can have several constructors with different prototypes. o2 will select the best match when a constructor is called.

Another approach is to use optional params. if the optional param is not used then the function will see it as null.

Charles Pegge

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #22 on: August 16, 2016, 08:12:05 AM »
Hi Roland,

To answer your question on accessing a method which has been overridden:

      this technique can be used safely with single line inheritance (as in java)

      account a at @this
      a.pay_out(amount)


      for single line inheritance, use the term of or from instead of has.
      In the next release of o2, the term extends will also be understood.

Code: [Select]
' --> overriding, reimplementation
class giroAccount

  from account 'single line inheritance

  private 
  double limit
 
  public
 
  method constructor(int number, double bankLine)
    num.constructor()

    accountNumber = number
    limit = abs(bankLine)
  end method

  method destructor()
    num.destructor()
  end method

  method getLimit() as double
    return limit
  end method
 
  ' method for access, check if arg is positiv
  method setLimit(double limit)
    limit = abs(limit)
  end method

  ' --> reimplementation
  method pay_out(double amount)
    if amount <= (balance + limit) then
'      account.pay_out(amount) ' does not work for statement_of_account
'      invoking the class directly will only work for static elements
'      but this technique can be used safely with single line inheritance (as in java)
      account a at @this
      a.pay_out(amount)

'      balance -= amount
'      printl "Payed out: " str(amount) & " Euro"
    else
      printl "Exceeded Limit!"
    end if
  end method

end class
« Last Edit: August 16, 2016, 08:19:54 AM by Charles Pegge »

Arnold

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #23 on: August 19, 2016, 07:27:34 AM »
Hi Charles,

using 'from account' in class giroAccount and the two replacements in method pay_out worked quite nice. One of my future projects will be to investigate the possible uses of pointers in OxygenBasic. I have not yet found the correct clue for applying them although I know there must be a common logic for using them. And to handle them in other programming languages is not a bit easier.

The help file of Oxygen states:
'of', 'has' and 'from' currently means 'inherits. They indicate derivation from a single parental class.
I did not notice a difference between 'has' or 'from' when building the class giroAccount, but there is a distinction?

I also tried out polymorphism and added some more statements invoking different types for myAccount. This worked also quite nice. Will it be sufficient if I use 'del myAccount' once at the end of the program?

Roland

Code: OxygenBasic
  1. ...
  2. ...
  3. ' --> Polymorphism - single interface to entities of different types
  4. printl cr & "Polymorphism" & cr
  5.  
  6. account myAccount     ' Test: object of type account
  7.  
  8. new account myAccount(4531088) ' myAccount points to object of type account
  9. myAccount.pay_in(300.00)
  10. myAccount.pay_out(500.00) ' method pay_out(amount) of class account is called
  11. myAccount.statement_of_account()
  12. printl
  13.  
  14. new giroAccount myAccount(5613990,100) ' myAccount now points to object of type giroAccount
  15. myAccount.pay_in(300.00)
  16. myAccount.statement_of_account()
  17. printl "Trying to draw 500 Euro"
  18. myAccount.pay_out(500.00) ' method pay_out(amount) of class giroAccount is called
  19. ' --> polymorphism & dynamic binding
  20. myAccount.statement_of_account()
  21. printl
  22.  
  23. new savingsAccount myAccount(1733065,1.25) ' myAccount now points to object of type Typ savingsAccount
  24. myAccount.pay_in(400.00)
  25. myAccount.statement_of_account()
  26. myAccount.pay_out(500.00) ' method pay_out(amount) of class savingsAccount is called
  27. myAccount.statement_of_account()
  28.  
  29. myAccount.pay_interest()
  30. myAccount.statement_of_account()
  31.  
  32.  
  33. printl cr & "Hit Enter ... " : waitkey
  34.  
  35. del myAccount
  36. del yourAccount 'alias ourAccount
  37. del mySavingsAccount
  38. del myGiroAccount
  39.  

Output:
...
...
Polymorphism

Payed in: 300 Euro
Payed out: 500 Euro
Account Number: 4531088 Balance: -200 Euro

Payed in: 300 Euro
Account Number: 5613990 Balance: 300 Euro
Trying to draw 500 Euro
Exceeded Limit!
Account Number: 5613990 Balance: 300 Euro

Payed in: 400 Euro
Account Number: 1733065 Balance: 400 Euro
Payed out: 500 Euro
Account Number: 1733065 Balance: -100 Euro
Interest payable: -1.25
Account Number: 1733065 Balance: -101.25 Euro

Hit Enter ...

Charles Pegge

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #24 on: August 20, 2016, 01:34:33 AM »
Hi Roland,

The default form of inheritance is 'has'. This term can be omitted. It supports inheritance from multiple classes and types.

Single-line inheritance, using 'of' and 'from' ('extends') uses a different arrangement of virtual table pointers and offsets. COM uses this mode of inheritance, and in Java this is the only form of inheritance supported. Not so good when you want to combine say, Banking and Graphics in one object.

The difference becomes apparent when classes are exported.



'del' is all you need to remove a 'new' object. Constructor and Destructor methods are mainly used for Building/Dismantling associated structures and linkages, as well as setting initial values.
« Last Edit: August 20, 2016, 01:46:00 AM by Charles Pegge »

Arnold

  • Guest
Re: Starting Oop with OxygenBasic
« Reply #25 on: August 20, 2016, 07:43:14 AM »
Hi Charles,

thanks for the explanatory notes.

This was the basis for my experiments with accounts (I omitted overloading the constructor method):
Grundkonzepte objektorientierter Programmierung
(Erratum page 66: Overloading of methods in Python is not possible - seems not to be valid any more)
The corresponding course was (is still?) offered to the students of the University of Jena

Unfortunately I found the project thesis only in the german language but it was very helpful for me as it discusses the basics of OOP in a compact way and how to apply them in several programming languages. Probably I will never be able to create any program with these languages but it was very interesting to compare with Oxygen.

Two more examples are provided which will be worthwhile to elaborate, in particular 'Geometric shapes' because I noticed that OxygenBasic already provides classes and methods to handle them. But first of all I must find out which results are expected.

Roland