Marc : Conversion process and questions about it

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Sat Jan 02, 2021 7:42 pm

James,

One of your favorites is also a question....

I used in early days rather small object programming, and at this point i'm not going to changes a lot of it, more if new stuff wil be added it will become a option.

I used

DATABASE oKlant // my early way
and then stuff for oKlant

I see many times :

oCustomers:= TDatabase():New(,"temp",,.f.)
oCustomers:use()

Is the second way the way it should be done in order to use ALL options in FWH or is it the same ?

If I reachs the process of TDATABASE i will come back on this options...
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby James Bott » Sat Jan 02, 2021 7:51 pm

Marc,

You really need to avoid filters. Filters require reading the entire database each time you call them. So for an incremental search of 10 characters you are going to read the entire database 10 times.

Even if you don't do an incremental search, you still have to read the entire database using a filter. Using a scope you only read the database records you need. Way faster!

Another possibility is to use a scope, then filter only the records in the scope.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Sat Jan 02, 2021 7:59 pm

James Bott wrote:Marc,

You really need to avoid filters. Filters require reading the entire database each time you call them. So for an incremental search of 10 characters you are going to read the entire database 10 times.

Even if you don't do an incremental search, you still have to read the entire database using a filter. Using a scope you only read the database records you need. Way faster!

Another possibility is to use a scope, then filter only the records in the scope.


I use scoped filter... They are fast.

BTW : Speed is not the problem. All by all... it is fast enough, but optimising code can speed things up, unless the functions I posted are not correct ??
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby James Bott » Sat Jan 02, 2021 8:37 pm

DATABASE oKlant // my early way
and then stuff for oKlant

I see many times :

oCustomers:= TDatabase():New(,"temp",,.f.)
oCustomers:use()

Is the second way the way it should be done in order to use ALL options in FWH or is it the same ?


You can use all options of the database when it is an object. One of the great things when you use an object is that you don't have to deal with workareas at all. You can even have multiple copies of the same database open at the same time, even in the function. This allows you to open a database in a function, use it, then close it, even while it is open in another function. Without this capability you had to save and restore the database state (including workarea, indexes, filters, scopes, recno, etc.).

Also you should not open a database object like in your second example. You should always try to write code only once. This reduces code and thus the chance of errors.

Also you want to emulate the real world, so you create a customers class and open the database and index(s) in the class.

Code: Select all  Expand view
Class TCustomers from TDatabase
   Method New()
Endclass

Method New Class TCustomers
   ::use(,"Customers","customers")
Return self


Note that I use the class name "Customers" (plural). This is because the database is full of single customer records and we also need a "TCustomer" class for a single customer object. So now we can do:

Code: Select all  Expand view
oCustomers := TCustomers():new()  // create the table object

oCustomers:seek("12345")


Now the code to open a database exists only in the object's new method. Thus if you want to change or add an index, you only have one place to modify. Also if you want to change the location of the database, you do it in the new method only. Actually better would be to create a parent object for all databases, that specifies the location, then all database class inherit from that parent class. Now the location only exists in one place.

Now we can create a single customer object.

Code: Select all  Expand view
oCustomer:= TCustomer():New(oCustomers:custno)  // create a customer object


So now we can use the customer object to query for name, address, balance, past due, last invoice, etc. You can also pass it to another object or function and within that object or function you can get access all the object's data and methods. Note that you add methods to the object instead of using functions. This follows the rule of "encapsulation." You encapsulate "functions" for customers into methods of that object.

Code: Select all  Expand view
oCustomer:AcceptPayment( nAmount, dDate)


Since the customer object is a smart object it knows how to update any appropriate databases with the payment information.

Using this technology I have taken existing programs and reduced the code by 50-70 percent. This is because you can eliminate a lot of repetitive code, and less code means less chance of errors, and it is much easier to read and understand.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Sat Jan 02, 2021 9:36 pm

For my customer update, i'm going for objects ....

I found this template sample from Mr. Rao

http://forums.fivetechsupport.com/viewtopic.php?f=3&t=37080#p221386

This has several of the basic commands to start with OOP.

Which are the most used methods that I have to look into ? File is classes/database
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby James Bott » Sat Jan 02, 2021 10:28 pm

Marc,

Well this seems to be an example of how to edit the properties of a database. I would not get sidetracked with that right now in your learning curve.

Most object programming texts advocate separating the interface code from real-world objects. Thus a customer object should emulate a real-world customer and not include data entry screens, browses, etc. There is nothing wrong with creating classes for those types of things too, but I suggest you trying emulating real-world objects first. They are simpler and easier to grasp, IMHO.

Have you read my introductory articles about OOP https://gointellitech.com/program.html? If not, I think they will help. Note that they are very dated so some of the things I wrote then I would not advocate today.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Tue Jan 05, 2021 9:52 am

I wonder if we can use this technique also for the mem variables ?
During programming we define a lot of local variables

local cNum:="", nTel:=0 .....

Maybe you also make a object out of it, so that ALL vars or at least those that are used othen on several places can be set into the object so that they can be easily passed..

I'm thinking more of system variables that are used public at my software.

Sys_date, Sys_Path, Sys_Periode (public variables set at startup)

can become :

oSystem:Date
oSystem:Path

The ease would be that they are all located into the object.
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Tue Jan 05, 2021 9:55 am

I see that there is a advice to use a prg for each object.

So the intension would be a

prg file for Customers
prg file for Xbrowsers
....

I see the goal of that of having all customers stuff in a customer file

This is still correct anno 2020 FWH ?
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby Antonio Linares » Tue Jan 05, 2021 10:17 am

Marc,

To use oSystem:Date and oSystem:Path, you need to use an object of a class like this:

#include "hbclass.ch"

CLASS System
DATA date
DATA path
ENDCLASS

oSystem = System()
oSystem:date = Date()
oSystem:path = hb_CurDrive() + ":\" + CurDir()

another alternative is to use a "hash" where you don't need a class:

local hSystem := {=>}

hSystem[ "date" ] = Date()
hSystem[ "path" ] = hb_CurDrive() + ":\" + CurDir()
hSystem[ "another" ] = 123

as you see you can have more info inside it without having to keep a Class updated

Yes, use different PRGs to keep properly organized the different parts of your app.
"Divide and conquer", the key of structured programming :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Marc : Conversion process and questions about it

Postby anserkk » Tue Jan 05, 2021 12:32 pm

Another option is to use a CLASS already developed by Andrade A. Daniel. The CLASS's name is TPublic

Code: Select all  Expand view
// Usage
oBill:=TPublic():New(.T.)

// Vaiables Declaration
oBill:nBillNo:=100
oBill:dBillDate:=Date()
oBill:cCustCode:=Space(10)
oBill:cCustName:=Space(35)


Instead of passing many variables to other functions as parameters, you can simply pass one single object
For eg
Instead of using YourFuncName(nBillNo,dBillDate,cCustCode,cCustName,......)
You can easily pass this one single object ie
YourFuncName(oBill)

This will help you to maintain your code neatly. On a later date if you need to pass one more additional variable to the function, then you don't have to modify the function "YourFuncName(oBill)" to receive more parameters.

The Hash is also a good alternative as shown by Mr.Antonio
User avatar
anserkk
 
Posts: 1329
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Tue Jan 05, 2021 1:05 pm

Exactly what I was thinking about. Thanks eveyone.

I found the class in the forum : http://forums.fivetechsupport.com/viewtopic.php?f=6&t=38871&hilit=tpublic

Antonio asked about it. Maybe it is inside FWH already ?? I have to test/see in the source files

Otherwise, If I want to use it, I copy it to tpublic.prg and just link it in? And this is so for every class I would make.
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby James Bott » Tue Jan 05, 2021 5:18 pm

Marc,

From a previous post near the top of this message topic you said:

I used

DATABASE oKlant // my early way
and then stuff for oKlant

I see many times :

oCustomers:= TDatabase():New(,"temp",,.f.)
oCustomers:use()

Is the second way the way it should be done in order to use ALL options in FWH or is it the same ?


Not exactly. Remember you need to write each piece of code only once. Thus, define a class for each database like the sample below. I put all the database classes into one PRG. Now your database filenames are all in one place, and thye only exist in that one place. So if you need to change them, it requires only one simple name change.

Code: Select all  Expand view
Class TCustomers from TDatabase
   Method New()
Endclass

Method New( lShared ) Class TCustomers
   Default lShared:= .T.
   super:new(,"Customers",,lShared)  // database filename only exists here.
   ::use()
Return Self


So now everywhere you need to use the customers database, you just do:

oCustomers:= TCustomers:New()

Simple!

That alone will probably eliminate hundreds of lines of code in your program.

The variable oCustomers should be declared as LOCAL. Note that you can still pass oCustomers to a function if you wish.

One last thing, I am using CDXs that auto-open when the database is opened thus you don't need to deal with them. I also always have the primary key index as the first index so you don't need to set it as the current index when opening the file. More lines of code are eliminated this way.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Marc : Conversion process and questions about it

Postby Marc Venken » Wed Jan 06, 2021 12:59 pm

The variable oCustomers should be declared as LOCAL. Note that you can still pass oCustomers to a function if you wish.


Why not public ? Then the oCustomers is visible everywhere and we don't have to paste them by a function.
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1343
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Marc : Conversion process and questions about it

Postby Antonio Linares » Wed Jan 06, 2021 1:32 pm

Think about the app as an entire object. The app has its own datas and methods (behaviors) of its class.

CLASS TApp

DATA aPublics INIT {}

METHOD New( ... )
....

ENDCLASS

The entire app is just an object
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Marc : Conversion process and questions about it

Postby James Bott » Mon Mar 15, 2021 6:41 pm

Marc,

I just saw this old message:

The variable oCustomers should be declared as LOCAL. Note that you can still pass oCustomers to a function if you wish.


Why not public? Then the oCustomers is visible everywhere and we don't have to paste them by a function.


One reason is that using a public violates the object rule of encapsulation. You can open a new copy of the customers object anywhere you want, then close it when you are done. This way you don't have to save and restore the state of a passed database object. You could have many copies of the same database open at any time and none would conflict with any of the others. For instance you could have a oCustomer object (single customer not a table) as a variable of the invoice class. Note also that the database objects handle finding and using a unique workarea so you never have to deal with workareas again.

oInvoice:= TInvoice():new(cInvoice:ID)
MsgInfo( oInvoice:oCustomer:name )

To do this the invoice object opens a copy of the oCustomers object in the oInvoice:New() method and it looks up the customer record and creates a oCustomer (singular) object inside the TInvoice class.

I never use publics.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

PreviousNext

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 101 guests