A Dirty Guide to OOP #1

Post

Posted
Rating:
#1 (In Topic #372)
Avatar
Regular
stevedee is in the usergroup ‘Regular’
If you want to get started with Object Orientated Programming (OOP) within your Gambas programs, here is a simple place to start.

OOP is all about identifying aspects of your project that can be implemented as objects. An object is usually a noun (e.g. fruit, animal, machine) with Properties (e.g. colour) Methods (e.g. delete) and sometimes Events (e.g. LostFocus).

Although "Class" in general programming can mean just a bunch of code in a module, in OOP a Class is the code you write as a kind of template from which you create Objects.

So here is a simple "fruit" example; Start a new project and then right-click in the Project window and select New > Class… and name it "clsFruit.class".

Another principle of OOP is encapsulation. We usually hide the internal class properties from the outside world and use "Getter" functions & "Setter" functions to read & write them. So even in our simple example, we need to Declare in the clsFruit.class any properties that we want to make available. Initially we need a Property called "Name" and another called "Colour" :-

Code (gambas)

  1. ' Gambas class fileclsFruit.class
  2. 'external refs
  3. Property Name As String        'the fruit Name
  4. Property Colour As String      'the fruit Colour

…then we create Private properties:-

Code (gambas)

  1. 'internal refs
  2. Private sFName As String        'the fruit Name
  3. Private sFColour As String      'the fruit Colour

…then we create Getter & Setter functions:-

Code (gambas)

  1. 'Getter functions
  2.   Return sFName
  3.  
  4. Private Function Colour_Read() As String
  5.   Return sFColour
  6.  
  7. 'Setter functions
  8. Private Sub Name_Write(Value As String)
  9.   sFName = Value
  10.  
  11. Private Sub Colour_Write(Value As String)
  12.   sFColour = Value

At this stage our class doesn't do much, but we can use it.

On the main project form add this code to create a new instance of our class:-

Code (gambas)

  1. Public myApple As New ClsFruit

Note: If autocomplete is working on your system, you should see the class name and properties listed as you type.

Now add a Button and add this as its click event:-

Code (gambas)

  1. Public Sub Button1_Click()
  2.  
  3.   myApple.Name = "apple"
  4.   myApple.Colour = "red"
  5.   Me.Text = "I have a " & myApple.Colour & " juicy " & myApple.Name
  6.   myApple.

So you should now have a working example. You can create as many objects as you like from this new class, for example:-

Code (gambas)

  1. Public myOrange As New ClsFruit
  2. Public myPlum As New ClsFruit
  3. Public myBanana As New ClsFruit

…and each instance can be given its own unique name & colour.


If this is of interest to anyone, I'm happy to write more.
Online now: No Back to the top

Post

Posted
Rating:
#2
Avatar
Administrator
sholzy is in the usergroup ‘unknown’

stevedee said

If this is of interest to anyone, I'm happy to write more.

Yes. I have no formal training in programming so I enjoy reading these short "lessons with examples" (the same with your personal website).

sholzy
Gambas One Site Director

To report bugs in the Gambas IDE:
Official Gambas Bug Tracker
Online now: No Back to the top

Post

Posted
Rating:
#3
Avatar
Enthusiast
GrayGhost is in the usergroup ‘Enthusiast’
Yes I will read everything you write
Online now: No Back to the top

Post

Posted
Rating:
#4
Avatar
Regular
stevedee is in the usergroup ‘Regular’
A Dirty Guide to OOP #2

Looking at the 'Fruit' example, you may wonder if its really worth the trouble. But one of the central principles of software development is "code re-use". If someone is paying you to write code, they don't want you to keep writing the same or similar stuff. Not only is this time consuming, but its also detrimental to code quality.

So whenever you find a use for some function more than just once or twice, the code should be written into a Module (I think Gambas calls this a static class). And if the task lends itself to becoming an Object, then write this code as a Class (I think Gambas calls this a creatable class).

Also, imagine that we expand our fruit class to have properties & methods for taste, size, position, visibility & so on, and we use it in a crazy fruit game where 100's of pieces of fruit are created and destroyed. If you didn't use objects, your code would probably be huge!

Anyway, I want to expand our fruit class by including a read-only property. All fruits have a skin, so lets add a boolean called HasSkin:-

Code (gambas)

  1. ' Gambas class fileclsFruit.class
  2. 'external refs
  3. Property Name As String        'the fruit Name
  4. Property Colour As String      'the fruit Colour
  5. Property Read HasSkin As Boolean     'does this fruit have a skin?
  6.  
  7. 'internal refs
  8. Private sFName As String        'the fruit Name
  9. Private sFColour As String      'the fruit Colour
  10.  
  11. 'Getter functions
  12.   Return sFName
  13.  
  14. Private Function Colour_Read() As String
  15.   Return sFColour
  16.  
  17. Private Function HasSkin_Read() As Boolean
  18.   Return bSkin

Notice that we use "Read" to declare the property and we don't included a setter. But we do need to set this property to True by default:-

Code (gambas)

  1. Public Sub _new()
  2.   'set defaults here
  3.   bSkin = True

And now in the main form, we add some code to check if our fruit has a skin:-

Code (gambas)

  1. Public Sub Button1_Click()
  2.  
  3.   myApple.Name = "apple"
  4.   myApple.Colour = "red"
  5.   Me.Text = "I have a " & myApple.Colour & " juicy " & myApple.Name
  6.   If myApple.HasSkin Then
  7.     Me.Text &= " & it has a skin"
  8.   Else
  9.     Me.Text = "My juicy " & myApple.Name & " has no skin"

Once you remove the skin from fruit, there is no going back. So here is a simple Method called Peel:-

Code (gambas)

  1. Public Sub Peel()
  2.   bSkin = False

…and updated main form code:-

Code (gambas)

  1. Public Sub Button2_Click()
  2.   myApple.Peel
Online now: No Back to the top

Post

Posted
Rating:
#5
Avatar
Regular
stevedee is in the usergroup ‘Regular’
A Dirty Guide to OOP #3

For most simple, non-graphical objects that you write, you may only need to implement Properties and Methods as described in the 2 earlier parts of this guide. (Take a look at my Wireless-range project which includes 2 class/objects: Gambas One - Gambas ONE)

But another aspect of the OOP paradigm which we should consider is "inheritance", which continues the "code re-use" idea by allowing one object to form the starting point for another. For Properties in particular, this means that the same names & meanings are maintained for many objects. Which makes it easier for us programmers, as we have less to remember.

For example, most of the Gambas visual components inherit from the Control class/object. So many properties (such as Name, Text, Enabled, Background, Width & so on) are the same for all descendants of Control, and quickly gain familiarity with those new to the language.

However, routine use of Inheritance in your written code can easily get out of hand. An object with too many ancestors will quickly accumulate a lot of Properties & Methods, and can make the code very difficult to read & understand (…I'm thinking of my time with C++).

Gambas allows you to use a maximum of (I think) 16 generations or levels of Inheritance, which in my opinion is about 15 too many! (…yes, this is the Dirty part of my simple guide).

Anyway, let's give simple inheritance a go!

Start a new project for vegetables, and copy the clsFruit.class file to the new project's .src folder. Add a new class called clsVeggie.class.

In clsVeggie write "Class clsVeggie Inherits clsFruit" and then create a boolean Property the OOP way, called RootVeg:-

Code (gambas)

  1. Class clsVeggie Inherits ClsFruit
  2.  
  3. Private bRootVeg As Boolean
  4.  
  5. Private Function RootVeg_Read() As Boolean
  6.  
  7.   Return bRootVeg
  8.  
  9. Private Sub RootVeg_Write(Value As Boolean)
  10.  
  11.   bRootVeg = value

In the Form class of this new project, create a new instance of clsVeggie and then add some trivial code to test it. Maybe some nonsense like this:-

Code (gambas)

  1. Public myVeg As New ClsVeggie
  2.  
  3. Public Sub Form_Open()
  4.  
  5.   myVeg.Name = "veg-edible"
  6.   myVeg.Colour = "Red"
  7.  
  8. Public Sub Button1_Click()
  9.  
  10.   myVeg.RootVeg = False
  11.   WhichVeg
  12.  
  13. Public Sub Button2_Click()
  14.  
  15.   myVeg.RootVeg = True
  16.   WhichVeg
  17.  
  18. Public Sub WhichVeg()
  19.  
  20.   If myVeg.RootVeg Then
  21.     Me.Text = "My " & myVeg.Colour & " " & myVeg.Name & " is a root vegetable"
  22.   Else
  23.     Me.Text = "My " & myVeg.colour & " " & myVeg.Name & " is NOT a root vegetable"



Note: Although this example demonstrates the principle that the new clsVeggie has inherited the basic Properties & Methods from clsFruit, there are a few points to note:-
1) autocomplete did not work for me when typing in lines like myVeg.Name (maybe that is a limitation of the IDE)
2)The format for Inherits is: Class <this-class>Inherits<ancestor-class>
I found that simply: Inherits<ancestor-class> also works at the time of writing, however its probably safer to use the full version, as the format could be tightened up in subsequent releases without notice.
3) my example may not show the correct way to implement inheritance…who knows? I haven't been able to find an example of how to do this…so if you have a better example, please post it here.
Online now: No Back to the top

Post

Posted
Rating:
#6
Avatar
Regular
stevedee is in the usergroup ‘Regular’
A Dirty Guide to OOP #4

There may be times when you want your Object to raise Events, especially if your program is for a computer with switches or sensors attached to its inputs.

Returning to our Fruit class example, I'm going to add a "rotten fruit" Event.

In clsFruit, add a line to declare the Event, a timestamp in the class constructor, and a new Method called "sniff". The complete class code should now look like this:-

Code (gambas)

  1. ' Gambas class fileclsFruit.class
  2. Event Rotten(sAlarm As String)
  3. 'external refs
  4. Property Name As String        'the fruit Name
  5. Property Colour As String      'the fruit Colour
  6. Property Read HasSkin As Boolean     'does this fruit have a skin?
  7.  
  8. 'internal refs
  9. Private sFName As String        'the fruit Name
  10. Private sFColour As String      'the fruit Colour
  11. Private dteBuy As Date
  12.  
  13. 'Getter functions
  14.   Return sFName
  15.  
  16. Private Function Colour_Read() As String
  17.   Return sFColour
  18.  
  19. Private Function HasSkin_Read() As Boolean
  20.   Return bSkin
  21.  
  22. 'Setter functions
  23. Private Sub Name_Write(Value As String)
  24.   sFName = Value
  25.  
  26. Private Sub Colour_Write(Value As String)
  27.   sFColour = Value
  28.  
  29.  
  30. 'constructor
  31. Public Sub _new()
  32.   'set defaults here
  33.   bSkin = True
  34.   dteBuy = Now()    'date we buy the fruit
  35.    
  36.  
  37. 'Methods
  38. Public Sub Peel()
  39.   bSkin = False
  40.  
  41.  
  42. Public Sub Sniff()
  43. 'is the fruit still OK to eat?
  44.  
  45.   If DateDiff(dteBuy, Now(), gb.Second) > 10 Then
  46.     Raise Rotten("is rotten!")
  47.  

In the Form class, add a third Button, change the object Declaration line to include a local name for the Event, and a routine to run when the event is triggered:-

Code (gambas)

  1. Public myApple As New ClsFruit As "FruitEvent"
  2.  
  3.  
  4. Public Sub Form_Open()
  5.   myApple.Name = "apple"
  6.   myApple.Colour = "red"
  7.  
  8.  
  9. Public Sub Button1_Click()
  10.   Me.Text = "I have a " & myApple.Colour & " juicy " & myApple.Name
  11.   If myApple.HasSkin Then
  12.     Me.Text &= " & it has a skin"
  13.   Else
  14.     Me.Text = "My juicy " & myApple.Name & " has no skin"
  15.  
  16. Public Sub Button2_Click()
  17.   myApple.Peel
  18.  
  19. Public Sub Button3_Click()
  20.   myApple.Sniff
  21.  
  22. Public Sub FruitEvent_Rotten(msg As String)
  23.   Me.Text = "Oh dear! my " & myApple.Name & " " & msg
  24.  

When you run this code, sniffing the fruit by clicking Button3 is not a problem until the life of the fruit is exceeded.

So what's happening here is that:-
1)The Event called "Rotten" is declared in our object/class
2)An Object is Declared and Instantiated in our form code which includes a local name for the Class Event (you can call it anything)
3)The Event routine in our form is referenced by our 'local event name'_'Class event name' (i.e. FruitEvent_Rotten)
4)When the "Raise" keyword is executed in our Object, the FruitEvent_Rotten routine is called and the string containing the message is passed as an argument.
Online now: No Back to the top

Post

Posted
Rating:
#7
Avatar
Regular
sjsepan is in the usergroup ‘Regular’
Hi SteveD,
Like the guide so far. BTW, the syntax you may need probably looks like…

Code (gambas)

  1. ' Gambas class file
  2.  
  3. Class clsVeggie Inherits clsFruit
  4.  

…because that's how I got my Dock and Anchor classes to inherit from DockAnchorBase in my DockAnchor library.
SteveS
https://github.com/ssepan2/DockAnchor
_______________

stevedee said

A Dirty Guide to OOP #3


Note: Although this example demonstrates the principle that the new clsVeggie has inherited the basic Properties & Methods from clsFruit, there are a few points to note:-
1) autocomplete did not work for me when typing in lines like myVeg.Name (maybe that is a limitation of the IDE)
2)The format for Inherits is supposed to be:-
MissingAs.png

…but I couldn't get this to compile.
3) my example may not show the correct way to implement inheritance…who knows? I haven't been able to find an example of how to do this…so if you have a better example, please post it here.
Online now: No Back to the top

Post

Posted
Rating:
#8
Avatar
Regular
stevedee is in the usergroup ‘Regular’
Cheers SteveS.

sjsepan said

Like the guide so far….
I'm not sure I have much more to add on the subject of OOP. I did a search yesterday for polymorphism & Gambas, but didn't find anything useful.

Maybe we can get the views of forum members on whether they use OOP in their programs, or whether they even like it (not everyone is a fan).
I like to create objects when I spot a suitable candidate in a project. I generally avoid using Inheritance between/within classes that I've written.

And I used to avoid putting code in a Form class that had nothing to do with the form (e.g. 'F to 'C conversion function would go in a Module, if it couldn't be part of an object) …sadly, most of my recent stuff is just a hack (…a hack is where you just sit at your keyboard and type code, with little or no pre-planning!)

 BTW, the syntax you may need probably looks like…
Thanks Steve, I have now updated the post with this syntax.

…because that's how I got my Dock and Anchor classes to inherit from DockAnchorBase in my DockAnchor library.
I tried to download your project but it is missing the library: GambasAppUtilityLib  …which I think you will find in your:
/usr/lib/Gambas3/stephensepan directory
Online now: No Back to the top

Post

Posted
Rating:
#9
Avatar
Guru
cogier is in the usergroup ‘Guru’
I will tell you a story. I was looking at the Spanish Gambas forum and it was asked if Gambas could do something like this video. (The tread is here.)

The challenge was set so I came up with:-
<IMG src="http://www.cogier.com/gambas/Forms.png"> </IMG>
Attachment

Now to the 'OOPS' part: -

I decided to try and make the 'Button' used into a class and with the help of my friend Matt came up with this. Once you get the hang of this it is extremely powerful as you are able to add Properties to the IDE. You can see 'EnterColor' and 'FlashColor', amongst others, in the image below. The Form below has been created entirely in the IDE and only 3 lines of code, outside ButtonPlus.class is used.
<IMG src="http://www.cogier.com/gambas/ButtonPlus.png"> </IMG>
Attachment

I have used 'ButtonPlus' in Remember in Project Showcase. if you want to try it just 'Import' the class into a new 'Graphical Application' and run the program. You will then find 'ButtonPlus' available in the Form toolbox, see image above. The 'ButtonPlus' is designed to work like RadioButtons. Click one and the others reset.
Online now: No Back to the top

Post

Posted
Rating:
#10
Avatar
Regular
sjsepan is in the usergroup ‘Regular’
 BTW, the syntax you may need probably looks like…
Thanks Steve, I have now updated the post with this syntax.

I tried to download your project but it is missing the library: GambasAppUtilityLib  …which I think you will find in your:
/usr/lib/Gambas3/stephensepan directory

That project is also out on github (https://github.com/ssepan2/GambasAppUtilityLib); I've not uploaded the latest versions to the GambasFarm because I was getting errors uploading library projects.

Steve S
Online now: No Back to the top

Post

Posted
Rating:
#11
Trainee
 I was wondering if it is at all possible to create objects at runtime.
Say, I have a resultset with two fields: id, oName
Can I create a class?

Public id as integer
public oName as string

public sub set_delete()  –go delete
public sub set_by_id($id as integer) – go populate obj
public sub set_insert() – go insert
etc..
Online now: No Back to the top

Post

Posted
Rating:
#12
Avatar
Guru
cogier is in the usergroup ‘Guru’
I was wondering if it is at all possible to create objects at runtime.

Run this in a new 'Graphical application'

Code (gambas)

  1. Label1 As Label
  2. Button1 As Button
  3.  
  4. Public Sub Form_Open()
  5.  
  6.   With Label1 = New Label(Me)
  7.     .Text = "Hello salihburhan"
  8.     .Font.Size = 25
  9.     .Font.Bold = True
  10.     .Width = 300
  11.     .Height = 56
  12.     .X = 50
  13.     .Y = 10
  14.  
  15.   With Button1 = New Button(Me) As "Button1"
  16.     .Text = "&Click me!"
  17.     .Height = 28
  18.     .Width = 98
  19.     .Picture = Picture["icon:/22/apply"]
  20.     .X = 50
  21.     .Y = 70
  22.  
  23.  
  24. Public Sub Button1_Click()
  25.  
  26.   If Label1.Text = "Hello salihburhan" Then
  27.     Label1.Text = "From cogier"
  28.   Else
  29.     Label1.Text = "Hello salihburhan"
  30.  

Grab the code from here and run it in the same way to see what can be done.

Does that help?
Online now: No Back to the top

Post

Posted
Rating:
#13
Avatar
Regular
stevedee is in the usergroup ‘Regular’

salihburhan said

…Can I create a class?…

Cogier's example shows creating objects from classes, but I don't believe that it is possible to create a class at runtime, if that is what you are asking.

Languages like VB.Net have a CreateClass command, but I don't think Gambas has an equivalent.
Online now: No Back to the top

Post

Posted
Rating:
#14
Avatar
Regular
Cedron is in the usergroup ‘Regular’
 Just for the sake of argument, I am going to disagree with you.

Just funning.

Writing code generators is fairly straightforward.  Given a list of fields and their types, there is certainly a formula for codifying that as a Gambas Class file.

Thus, one could write a program that reads the specs for class definition, writes the class definition as source code (along with a testing program), compiles the code, then shells out to run the compiled code.

Technically, it's the same thread executing the code it generated.

.... and carry a big stick!
Online now: No Back to the top

Post

Posted
Rating:
#15
Avatar
Regular
stevedee is in the usergroup ‘Regular’

Cedron said

…Writing code generators is fairly straightforward.  Given a list of fields and their types, there is certainly a formula for codifying that as a Gambas Class file….

Hey that sounds interesting. Can you give us a simple code example?
Online now: No Back to the top

Post

Posted
Rating:
#16
Trainee
 If there is a compiler engine of sorts like a class that can be imported and called at runtime for specific subroutines….
So maybe it might be possible to pass along a string to be compiled and a name for the class.
It can return a variable that has standard methods.
$var.insert()
$var.update_name()

Other than databases that host frameworks (like wordpress), would there be any other application?
Online now: No Back to the top

Post

Posted
Rating:
#17
Avatar
Guru
cogier is in the usergroup ‘Guru’
Hey that sounds interesting. Can you give us a simple code example?

This got me thinking and I came up with the attached program. This program will create a new folder and all the normal Gambas files and folders. It will add the code to FMain.class and then compile, make an executable and run it, all nearly instantly. You can add some text to the new program which will be displayed at the bottom of the Form.

I'm not sure this is exactly what people were looking for but here it is anyway.

<IMG src="http://www.cogier.com/gambas/CreateCode.png"> </IMG>
  
Attachment
Online now: No Back to the top

Post

Posted
Rating:
#18
Guru
BruceSteers is in the usergroup ‘Guru’
Just an additional note on setting up the Properties..

As of Gambas 3.14 the "Use" keyword was introduced to save on code.

So before you would write..

Code (gambas)

  1.  
  2. Property MyProperty As String  ' define property
  3.  
  4. Private $MyProperty As String  ' define private variable
  5.  
  6. ' define read and write methods
  7.  
  8. Private Function MyProperty_Read() As String
  9.  
  10.   Return $MyProperty
  11.  
  12.  
  13. Private Sub MyProperty_Write(Value As String)
  14.  
  15.   $MyProperty = Value
  16.  
  17.  
  18.  
  19.  

Now you can simply write…

Code (gambas)

  1.  
  2. Property MyProperty As String Use $MyProperty
  3.  
  4.  

This saves a lot of code but take note..
It will make your application fail if run on a gambas version less than 3.14 so if you want to share your app with debian users who might still be using Gambas 3.12 then do not use it.
Online now: No Back to the top

Post

Posted
Rating:
#19
Regular
01McAc is in the usergroup ‘Regular’
A very good idea and ideal for beginners like me, thank you very much. The guide is supposed to be renamed to A Fruity Guide to OOP :D
Online now: No Back to the top
1 guest and 0 members have just viewed this.