Hello xProgrammer,
On Mar 16, 2010, at 4:56 PM, [email protected] wrote: > Hi all > > Its nice to see that a discussion that started out with some highly > questionable > assertions about OOP has turned right around to a discussion of ORMs > which > essentially extend the OOP concept. > > Harbour doesn't force OOP on anyone, but I suspect most savvy xBase > coders head > that way. Even those that write procedural code are using some objects, > hidden from them by the preprocessor. Beginners soon realise that they > are > writing code that pretty much does something similar to what they have > done > before. At first they may use the "cut and paste" approach. Most then > come to > realise that this approach is not ideal because > > 1. Its easy to miss bits of code that need to be altered > > 2. To change "standard behaviour" you have to change code in many places > > So most of us ended up with a whole series of "utility functions" which > identified (as parameters) those things that changed from invocation to > invocation and meant that standard behaviour could be changed by altering > a > single piece of code. > > OOP basically extends this in a more powerful and consistent way. > > But if you don't like writing "standard" Harbour OOP code that might look > like > > obj_MyWindow := TWindow():New( 500, 300, "Sample Window" ) > > you can use the preprocessor and write something like > > CREATE WINDOW myWindow TITLE "Sample Window" SIZE 500, 300 > > all it takes is a preprocessor directive like > > #xcommand CREATE WINDOW TITLE SIZE , => ; > := TWindow():New( , , ) > > That is one of the fundamental beauties of xBase. > > I would also note that the popularity of VB is due to Microsoft's > marketing power and the fact > that many of us are effectively forced to use it (or its sibling VBA) to > automate office type tasks. > If you judged languages by their popularity you wouldn't be using Harbour > despite the fact > that its so wonderful a language. > > Now onto the interesting part - ORMs. > > These should fit very neatly into Harbour. Take an "example" from a > previous post: > > emp=Employee.new > emp.name = "Emp1" > emp.basic = 4500 > emp.designation = "Programmer" > emp.save > > Harbour equivalents are easy: > > obj_Employee := TEmployee():New() > WITH OBJECT obj_Employee > :Name := "Emp1" > :Basic := 4500 > :Designation := "Programmer" > :Save() > END > > Of course there are many alternatives (depending in part on the TEmployee > class) such as > > obj_Employee := TEmployeeNew( "Emp1", 4500, "Programmer" ) > obj_Employee:Save() > > Or with suitable preprocessor directive for those that like the object > orientation hidden > > CREATE EMPLOYEE ThisEmployee > ThisEmployee:Name := "Emp1" > ThisEmployee:Basic := 4500 > ThisEmployee:Designation := Programmer > SAVE EMPLOYEE ThisEmployee > > Obviously we have to define the TEmployee Class which would inherit from > a class that > "understands" how to read / write etc but not the particular details of > an employee record, > something like: > > CLASS TEmployee FROM TSingleRecord > > DATA Name > DATA Basic > DATA Designation > // etc > > ENDCLASS > > Methods like Save() would be inherited from TSingleRecord as might its > oid (object > identifier / primary key ) Exactly. > > CLASS TSingleRecord > > DATA oid > // etc > > METHOD Save() > // etc > > ENDCLASS > > This is very much along the lines of the approach I use combined with a > client-server data > base back end I wrote for my own use. A record is returned as a > two-dimensional array that > can be used to directly update the front end object. The array is > serialsed and transmitted > using IP sockets. Properties are directly updated using > __ObjSetValueList(). This type of > approach would seem ideal for an ORM in my opinion. I'll add that to fulfill this approach, we need to have at least: * Abstraction * Inheritance * Polymorphism e.g., The following sample creates three new databases: TEmployer TPerson TEmployee fills the databases with some values and then prints it out: <prg> /* Contains the Employer's database */ CLASS TEmployer FROM TTable DATA tableName INIT "employer" // the physical file data base DEFINE FIELDS // Load the Field's information ENDCLASS BEGIN FIELDS CLASS TEmployer /* the primary key database */ ADD PRIMARYKEY FIELD "Employer" AUTOINCREMENTAL ADD STRING FIELD "FirstName" SIZE 100 ADD STRING FIELD "LastName" SIZE 100 ADD STRING "Phone" SIZE 40 /* creates a TEmployees table whos MasterSource is this database (TEmployer) */ ADD OBJECT FIELD "Employees" CLASS "TEmployee" END FIELDS /* Contains the Person's database */ CLASS TPerson FROM TTable DATA tableName INIT "persemp" // the physical file data base DEFINE FIELDS // Load the Field's information /* calculated fields */ CALCFIELD Age INLINE Years( ::Field_Birth ) CALCFIELD FullName INLINE RTrim( ::Field_LastName ) + ", " + RTrim( ::Field_FirstName ) ENDCLASS BEGIN FIELDS CLASS TPerson /* the primary key database */ ADD PRIMARYKEY FIELD "Person" AUTOINCREMENTAL ADD STRING FIELD "FirstName" SIZE 40 ADD DATE FIELD "Birth" ; VALID {|d| Year( d ) > 1850 } /* validation for field */ ADD STRING FIELD "Genre" ; VALID {|g| g $ "FM" } /* validation for field */ END FIELDS /* Contains the Employee's database */ CLASS TEmployee FROM TPerson DEFINE FIELDS // Load the Field's information CALCFIELD Age INLINE Years( ::Field_HiredOn ) ENDCLASS BEGIN FIELDS CLASS TEmployee /* the master key database */ ADD OBJECT FIELD "Employer" CLASS "TEmployer" MASTERKEY ADD FLOAT FIELD "Salary" ; VALID {|s| s >= 0 } /* validation for field */ ADD DATE FIELD "HiredOn" ; VALID {|d| Year( d ) > 1850 } /* validation for field */ /* the primary key database */ ADD PRIMARYKEY FIELD "Person" END FIELDS FUNCTION Main() emp := TEmployer():New() /* adds a new TEmployer record */ emp:NewRecord() emp:Field_Name := "US ROBOTICS" emp:Field_Phone := "1 555 555555" /* adds a new TEmployee record */ emp:Field_Employees:NewRecord() emp:Field_Employees:Field_FirstName := "John" emp:Field_Employees:Field_LastName := "A" emp:Field_Employees:Field_Birth := "1/1/1970" emp:Field_Employees:Field_HiredOn := "1/1/2000" emp:Field_Employees:Field_Genre := "M" emp:Field_Employees:Field_Salary := 80000 emp:Field_Employees:Post() pers := TPerson():New() /* adds a new TPerson record */ pers:NewRecord() pers:Field_FirstName := "Jane" pers:Field_LastName := "B" pers:Field_Birth := "1/1/1980" pers:Field_Genre := "F" pers:Post() /* adds the previous TPerson record to TEmployer */ emp:Field_Employees:NewRecordFrom( pers ) emp:Field_Employees:Field_Salary := 80000 emp:Field_Employees:Field_HiredOn := "1/1/2000" emp:Field_Employees:Post() /* prints the whole TEmployer database with his employees */ WHILE !emp:Eof() ? "Employer: ", emp:Field_Name, emp:Field_Phone WHILE !emp:Field_Employees:Eof() ? " Employee:" ? " Genre:", emp:Field_Employees:Field_Genre ? " FullName:", emp:Field_Employees:Field_FullName ? " Age:", emp:Field_Employees:Field_Age ? " Salary:", emp:Field_Employees:Field_Salary emp:Field_Employees:Skip() ENDDO emp:Skip() ENDDO RETURN NIL </prg> best regards, Teo _______________________________________________ Harbour-users mailing list (attachment size limit: 40KB) [email protected] http://lists.harbour-project.org/mailman/listinfo/harbour-users
