FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour understanding OOP returning more than value from a method
Posts: 334
Joined: Fri Oct 14, 2005 01:54 PM
understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 08:16 AM
I have calculate method which calculate the age in years . How can I return months and days from that method as well as I return years . Pointers in C used to return more than one value from a function . What is the equalvent in fivewin.
Thanks
Code (fw): Select all Collapse
#include "fivewin.ch"

function main()
local oPerson1,oPerson2

set date format to "DD/MM/YYYY"

oPerson1 :=Tperson():new("Enas Samir",ctod("17/02/1967"))
oPerson2 :=Tperson():new("Ehab Samir",ctod("20/02/1972"))

msginfo (oPerson1:cName)
msginfo (oPerson1:dDob)
msginfo (oPerson1:age())
msginfo (oPerson1:calculate())


msginfo (oPerson2:cName)

msginfo (oPerson2:dDob)

msginfo (oPerson2:age())

msginfo (oPerson2:calculate())

return nil

create class TPerson
        var cName
        var dDob
        var nAge_years
        var nAge_months
        var nAge_days
        method new
        method age
        method calculate

endclass





method age
*---------------
::nAge_days:= (date()-::dDob)
return (::nAge_days)

method new(cName,dDob,nAge_years,nAge_months,nAge_days)
*-----------------------------------------------------
default cName:="",dDob:=ctod(" / /    "),nAge_years:=0,nAge_months:=0,nAge_days:=0
::cName:=cName
::dDob:=dDob
::nAge_years:=nAge_years
::nAge_months:=nAge_months
::nAge_days:=nAge_days


return self

method calculate()
*-----------------------
::nAge_years:=int (::nAge_days/365)

::nAge_months:=int (::nAge_days/12)

::nAge_days:=::nAge_days%12

return (::nAge_years)
Posts: 274
Joined: Fri Apr 04, 2008 01:25 PM
Re: understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 09:33 AM

After calling the methods age() and calculate() you simply can access the values oPerson1:nAge_Months and oPerson1:nAge_Days

Best Regards,

Gilbert Kuhnert
CTO Software GmbH
http://www.ctosoftware.de
Posts: 334
Joined: Fri Oct 14, 2005 01:54 PM
Re: understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 10:13 AM
If I seprated the 3 functions (calculate_years,calculate_months,calculate_days) as not as calculate()

msginfo (oPerson1:calculate_years+ "year" +str (oPerson1:calculate_months())+" month" + str(oPerson1:calculate_days())+" days" )

is not as the same statement :

msginfo (str(oPerson1:nAge_years)+ "year" +str(oPerson1:nAge_months)+" month" + str(oPerson1:nAge_days)+" days" )

Code (fw): Select all Collapse
#include "fivewin.ch"

function main()
local oPerson1,oPerson2

set date format to "DD/MM/YYYY"

oPerson1 :=Tperson():new("Enas Samir",ctod("17/02/1967"))
oPerson2 :=Tperson():new("Ehab Samir",ctod("20/02/1972")):calculate()


msginfo ("Name : " + oPerson1:cName + "    Date of Birth : "+ dtoc(oPerson1:dDob) + "     Age : " + str(oPerson1:age())+ " day  ")
msginfo ("Name : " + oPerson2:cName + "    Date of Birth : "+ dtoc(oPerson2:dDob) + "     Age : " + str(oPerson2:age())+ " day  ")

msginfo (" For " + (oPerson1:cName) + str(oPerson1:calculate_years)+ "year" +str (oPerson1:calculate_months())+" month" + str(oPerson1:calculate_days())+" days" )

msginfo (" For " + (oPerson2:cName) +str(oPerson2:nAge_years)+ "year" +str(oPerson2:nAge_months)+" month" + str(oPerson2:nAge_days)+" days" )


return nil

create class TPerson
        var cName
        var dDob
        var nAge_years
        var nAge_months
        var nAge_days
        method new
        method age
        method calculate
        method calculate_years
        method calculate_months
        method calculate_days

endclass





method age
*---------------
::nAge_days:= (date()-::dDob)
return (::nAge_days)

method new(cName,dDob,nAge_years,nAge_months,nAge_days)
*-----------------------------------------------------
default cName:="",dDob:=ctod(" / /    "),nAge_years:=0,nAge_months:=0,nAge_days:=0
::cName:=cName
::dDob:=dDob
::nAge_years:=nAge_years
::nAge_months:=nAge_months
::nAge_days:=nAge_days


return self

method calculate()
*-----------------------
::nAge_years:=int (::nAge_days/365)
::nAge_months:=::nAge_days-(::nAge_years*365)
//? "reaminader months : " + str(::nAge_months)

::nAge_months:=int(::nAge_months/12)
::nAge_days=::nAge_days-(::nAge_years)*365-(::nAge_months*12)
//? "reaminader days : " + str(::nAge_days)


return self


method calculate_years()
*-----------------------
::nAge_years:=int (::nAge_days/365)
return (::nAge_years)


method calculate_months()
*-----------------------

::nAge_months:=::nAge_days-(::nAge_years*365)
//? "reaminader months : " + str(::nAge_months)

::nAge_months:=int(::nAge_months/12)
::nAge_days=::nAge_days-(::nAge_years)*365-(::nAge_months*12)
//? "reaminader days : " + str(::nAge_days)
//? (::nAge_days)
//? (::nAge_months)
//::nAge_days=::nAge_months-int(::nAge_months/12)



//::nAge_months:=int(::nAge_days/12)

return (::nAge_months)

method calculate_days()
*-----------------------
//? (::nAge_days)
//::nAge_days=::nAge_days-(::nAge_months)*30
//? (::nAge_days)
//? (::nAge_months)

return (::nAge_days)
Posts: 883
Joined: Tue Oct 11, 2005 11:57 AM
Re: understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 12:37 PM

Ehab...
My personal opinion...

I don't think a CLASS has to be made to fullfil the requirements you want.
just a Simple function With and Array as a return Value.
Simplier and faster...

define Years 1

define Months 2

define Days 3

//-------------------------------------------
Function Whatever(SentDate)
Local Age:=CalculateAge(SentDate)

? Age[Years]
? Age[Months]
? Age[Days]

Return Nil

//-------------------------------------------
Function CalculateAge(SentDate)
Local nYears:=0
Local nMonths:=0
Local nDays:=0

nYears:= ...formula1
nMonths:= ...formula2
nDays:= ...formula3

Return {nYears,nMonths,nDays}

;-) Ji,ji,ji... buena la cosa... "all you need is code"

http://www.xdata.cl - Desarrollo Inteligente
----------
Asus TUF F15, 32GB Ram, 2 * 1 TB NVME M.2, GTX 1650
Posts: 464
Joined: Tue May 16, 2006 07:47 AM
Re: understanding OOP returning more than value from a method
Posted: Wed May 05, 2010 09:51 AM
Hi all

I would like to add a few comments to this discussion.

Perhaps most importantly the quoted code

Code (fw): Select all Collapse
::nAge_years:=int (::nAge_days/365)


will give incorrect results around a person's birthday due to the effect of leap years and should definitely not be used.. Even the following code

Code (fw): Select all Collapse
::nAge_years:=int (::nAge_days/365.25)


will give errors for the same reason, although it will give less errors. I gave the best way to calculate age in years in a recent post on this forum dealing with the calculation of number of days. The basic technique is to calculate a "trial"age in years as follows:

Code (fw): Select all Collapse
nTrialAge = Year( date_AgeAsAt ) - Year (date_Birth )


This of course is the person's age if their birthday has already occurred in the year of the date you are calculating their age to. If that date has not passed you need to subtract 1 from nTrialAge. The logic for this is easy enough. Firstly compare months, and if they are equal compare days. Something like this:

Code (fw): Select all Collapse
IF Month( date_AgeAt ) > Month( date_Birth )
  RETURN nTrialAge 
ENDIF
IF Month( date_AgeAt ) < Month( date_Birth  )
  RETURN nTrialAge - 1
ENDIF
// if we reach here we are in the month of the persons birthday
IF Day( date_AgeAt ) >= Day( date_Birth )
  RETURN nTrialAge 
 ELSE
  RETURN nTrialAge - 1
ENDIF


Secondly with regards to passing the result back.

If the result is ever only going to be displayed you could pass it back in a single string.

You could use an array, a hash would be neater. A better way would probably be to pass by reference

Code (fw): Select all Collapse
nYears := 0
nMonths := 0
nDays := 0
CalculateAge( dBirth, Date(), @nYears, @nMonths, @nDays )


Of course you could just set properties of your class and use them, something like

Code (fw): Select all Collapse
oPerson:CalculateAge( Date() )
? oPerson:nYears
? oPerson:nMonths
? oPerson:nDays


Using this approach you have to be careful that you don't access these properties without having done the calculation first.

I hope that this post might be of some interest / help.

Regards
xProgrammer
Posts: 1487
Joined: Tue Jun 14, 2016 07:51 AM
Return age (year,Mnd,day) from a date
Posted: Mon Oct 16, 2017 09:36 PM

I found this tread for calculating the age, but It seems that it give no correct values.

I Found also a Exel formula that works pretty ok : = nice result

=ALS(EN(MAAND(B12)=MAAND(A12);DAG(B12)<DAG(A12));J AAR( B12)-JAAR(A12)-1&" jr ";ALS(MAAND(B12)-MAAND(A12)<0;JAAR(B12)-JAAR(A12)-1;JAAR(B12)-JAAR(A12))&" jr " )&ALS(EN(MAAND(B12)=MAAND(A12);DAG(B12)<DAG(A12)); MAAN D(B12)-1-MAAND(A12)+12&" mnd ";ALS(DAG(B12)-DAG(A12)<0;(ALS(MAAND(B12)-MAAND(A12)<0;(MAAND(B12)-MAAND(A12)+12);MAAND(B12)-MAAND(A12)))-1;(ALS(MAAND(B12)-MAAND(A12)<0;(MAAND(B12)-MAAND(A12)+12);MAAND(B12)-MAAND(A12))))&" mnd ")&ALS(DAG(B12)<DAG(A12);((DATUMWAARDE(1&"/"&ALS(MAAND(A12)+1=13;1;MAAND(A12)+1)&"/"&ALS(MAAND(A12)+1=13;JAAR(A12)+1;JAAR(A12)))-(A12+1-DAG(A12)))+DAG(B12)-DAG(A12));DAG(B12)-DAG(A12))&" dgn"

Put date in exell B12 and A12 and see result (ok)

Has anyone ever terminated the FW code to get the same result ?

Marc Venken

Using: FWH 23.08 with Harbour
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
Re: understanding OOP returning more than value from a method
Posted: Mon Oct 16, 2017 10:41 PM

Ehab,

First let me say that I would never recommend creating a Calculate() method (unless it was hidden). You don't want to have to call two methods to get the result.

When you request an age, that is what you should get. You should not have to remember to request a calculation first. The calculation should be done in the Age() method.

I have never needed a person's age in years, months and days so this question has never come up. A person's age in years, months, and days is a rare need. I would use three methods, Age(), AgeMonths(), and AgeDays(). So, when you request age() you get it in years as is normal. Otherwise, if you need months and days, also then you can request them too. All of these values would be returned as numbers.

And if you needed them in a string (to be displayed), then you could add another method AgeYMD() which returns the result as a string. This method would call the other three methods to get the needed numbers and paste them together in a string.

As others have mentioned, you do need to account for leap years in the calculations.

James

FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 1487
Joined: Tue Jun 14, 2016 07:51 AM
Re: understanding OOP returning more than value from a method
Posted: Mon Oct 16, 2017 11:08 PM

Hello James,

It was a very old post started by Ehab in 2010

I picked it up because I need the Year, Month and day for my soccer application.

As mentioned also, there is no need for OOP, because this can be done in a small function (like the exel sample)
Maybe someone has done it before. If not, I need to create it from that sample.

Thanks

Marc Venken

Using: FWH 23.08 with Harbour
Posts: 169
Joined: Mon Feb 25, 2008 02:42 AM
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 01:03 PM
Hello,
Please test..

Code (fw): Select all Collapse
#include "fivewin.ch"

function main()
local oPerson1,oPerson2

  SET _3DLOOK ON
  set date british
  set century on
  set delete on
  set confirm on
  SET EPOCH TO Year( Date() ) - 60
  
set date format to "DD/MM/YYYY"

oPerson1 :=Tperson():new("Enas Samir",ctod("09/05/1967"))

?alltrim(oPerson1:cName)+CRLF+;
        "DOB : "+dtoc(oPerson1:dDob)+CRLF+;
        "Today : "+dtoc(date())+CRLF+;
        str(oPerson1:nAge_years,3) +" years "+CRLF+;
        str(oPerson1:nAge_months,3)+" months "+CRLF+;
        str(oPerson1:nAge_days,3)  +" days "+CRLF


return nil


CLASS Tperson 
      data cName
      data dDob
      data nAge_years
      data nAge_months
      data nAge_days
      METHOD new(cName,dDob,nAge_years,nAge_months,nAge_days) CONSTRUCTOR 
      METHOD CalculateAge()
ENDCLASS

method new(cName,dDob,nAge_years,nAge_months,nAge_days) CLASS Tperson 
*-----------------------------------------------------
default cName:="",dDob:=ctod(""),nAge_years:=0,nAge_months:=0,nAge_days:=0
::cName:=cName
::dDob:=dDob
::nAge_years:=nAge_years
::nAge_months:=nAge_months
::nAge_days:=nAge_days
::CalculateAge()
return self

method CalculateAge() CLASS Tperson 

local nAge1 := 0
local nAge2 := 0
local nAge3 := 0
  
  if year(date()) <= year(::dDob)
     nAge1 := 0
  endif 
  
  if year(date()) > year(::dDob)
     nAge1 := year(date()) - year(::dDob)
  endif 
  
  if month(date()) == month(::dDob)
     nAge2 := 0
  endif 
  
  if month(date()) > month(::dDob)
     nAge2 := month(date()) - month(::dDob)
  endif 
  
  if month(date()) < month(::dDob)
     nAge2 := (12-month(::dDob))+ month(date())
     nAge1 -= 1
  endif 
  
  
  if day(date()) <= day(::dDob)
     nAge3 := 0
  endif
  
  if day(date()) > day(::dDob)
     nAge3 := day(date()) - day(::dDob)
  endif
  
  if ::dDob >= date()
     nAge1 := nAge2 := nAge3 := 0
  endif
  
      ::nAge_years:=nAge1
      ::nAge_months:=nAge2
      ::nAge_days:=nAge3

return nil

regards
fafi
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 01:13 PM
Very good Fafi. Many thanks. Congratulations!

fafi wrote:Hello,
Please test..

Code (fw): Select all Collapse
#include "fivewin.ch"

function main()
local oPerson1,oPerson2

  SET _3DLOOK ON
  set date british
  set century on
  set delete on
  set confirm on
  SET EPOCH TO Year( Date() ) - 60
  
set date format to "DD/MM/YYYY"

oPerson1 :=Tperson():new("Enas Samir",ctod("09/05/1967"))

?alltrim(oPerson1:cName)+CRLF+;
        "DOB : "+dtoc(oPerson1:dDob)+CRLF+;
        "Today : "+dtoc(date())+CRLF+;
        str(oPerson1:nAge_years,3) +" years "+CRLF+;
        str(oPerson1:nAge_months,3)+" months "+CRLF+;
        str(oPerson1:nAge_days,3)  +" days "+CRLF


return nil


CLASS Tperson 
      data cName
      data dDob
      data nAge_years
      data nAge_months
      data nAge_days
      METHOD new(cName,dDob,nAge_years,nAge_months,nAge_days) CONSTRUCTOR 
      METHOD CalculateAge()
ENDCLASS

method new(cName,dDob,nAge_years,nAge_months,nAge_days) CLASS Tperson 
*-----------------------------------------------------
default cName:="",dDob:=ctod(""),nAge_years:=0,nAge_months:=0,nAge_days:=0
::cName:=cName
::dDob:=dDob
::nAge_years:=nAge_years
::nAge_months:=nAge_months
::nAge_days:=nAge_days
::CalculateAge()
return self

method CalculateAge() CLASS Tperson 

local nAge1 := 0
local nAge2 := 0
local nAge3 := 0
  
  if year(date()) <= year(::dDob)
     nAge1 := 0
  endif 
  
  if year(date()) > year(::dDob)
     nAge1 := year(date()) - year(::dDob)
  endif 
  
  if month(date()) == month(::dDob)
     nAge2 := 0
  endif 
  
  if month(date()) > month(::dDob)
     nAge2 := month(date()) - month(::dDob)
  endif 
  
  if month(date()) < month(::dDob)
     nAge2 := (12-month(::dDob))+ month(date())
     nAge1 -= 1
  endif 
  
  
  if day(date()) <= day(::dDob)
     nAge3 := 0
  endif
  
  if day(date()) > day(::dDob)
     nAge3 := day(date()) - day(::dDob)
  endif
  
  if ::dDob >= date()
     nAge1 := nAge2 := nAge3 := 0
  endif
  
      ::nAge_years:=nAge1
      ::nAge_months:=nAge2
      ::nAge_days:=nAge3

return nil

regards
fafi
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 1487
Joined: Tue Jun 14, 2016 07:51 AM
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 06:56 PM

For a date like : 26/11/1965

This has to change right ? Else the result for day = always 0

if day(date()) <= day(::dDob)
// nAge3 := 0
nAge3 := day(::dDob) - day(date())

endif

Marc Venken

Using: FWH 23.08 with Harbour
Posts: 169
Joined: Mon Feb 25, 2008 02:42 AM
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 07:22 PM
Marc Venken wrote:For a date like : 26/11/1965

This has to change right ? Else the result for day = always 0

if day(date()) <= day(::dDob)
// nAge3 := 0
nAge3 := day(::dDob) - day(date())

endif


Thank you Mr. Marc

:-)

oPerson1 :=Tperson():new("Marc Venken",ctod("26/11/1965"))

I think that is your DOB, right ? :-)

Best Regards
oPerson1 :=Tperson():new("Fafi",ctod("09/05/1967"))
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
Re: understanding OOP returning more than value from a method
Posted: Wed Oct 18, 2017 12:08 AM
Marc,

This is how do it using a class. Ideally, this should be modified to be a subclass of TRecord, then it will read it's own data from the DBF.

As you can see from the sample you just do:

Code (fw): Select all Collapse
oPlayer:= TPlayer():new()

msgInfo( oPlayer:AgeYMD() )  // displays age in years, months, days


Two lines of code, that's all! A player should know his/her own age, so you should just be able to ask the player object for it.

Well, two lines to use the class.

Regards,
James

Code (fw): Select all Collapse
/*
Purpose  : Player class
Program  : 
Author   : James Bott, <!-- e --><a href="mailto:jbott@compuserve.com">jbott@compuserve.com</a><!-- e -->
Date     : 10/17/2017 04:41:00 PM
Company  : Intellitech
Language : Fivewin/xHarbour
Updated  : 
Notes    : For Mark Venken
           Not fully tested, but seems to be working.
           Should be modifed to be a subclass of Intellitech's TRecord class,
           then it would read it's own data from the parent database.

*/

#include "fivewin.ch"

Function Main()
   Local oPlayer
   set date american  // Adjust to your local format
   set century on
   SET EPOCH TO 1980 

   oPlayer:= TPlayer():new()
   
   msgInfo( oPlayer:name, "oPlayer:name" )
   msgInfo( oPlayer:dob, "oPlayer:DOB" )
   msgInfo( oPlayer:age(), "oPlayer:age()" )
   msgInfo( oPlayer:AgeMonths(), "oPlayer:ageMonths()")
   MsgInfo( oPlayer:AgeDays(), "oPlayer:AgeDays()" )
   msgInfo( oPlayer:AgeYMD(), "oPlayer:AgeYMD()" )

Return nil

//----------------------------------------------------------------------------//

class TPlayer
   Var Name    
   Var Dob        
   Method New()
   Method Age()       // age in years
   Method AgeMonths()
   Method AgeDays()
   Method AgeYMD()    // age in string with years, months, days
endclass

//----------------------------------------------------------------------------//

Method New() Class TPlayer
   // These should be fields
   ::Name:= "Marc Venken"
   ::DOB := ctod("11/26/1965")
Return self

//----------------------------------------------------------------------------//

Method Age( dRefDate ) Class TPlayer
   
   LOCAL nAge := 0
   
   IF VALTYPE(dRefDate) <> "D"
      dRefDate := date()
   ENDIF

   IF ! EMPTY( ::DOB )

      nAge := YEAR(dRefDate) - YEAR( ::DOB )
      
      IF MONTH(dRefDate) < MONTH( ::DOB ) .OR. ;
         ( MONTH(dRefDate) == MONTH( ::DOB ) .AND. ;
           DAY(dRefDate) < DAY( ::DOB ) )
          nAge--
      ENDIF

   ENDIF

RETURN nAge

//----------------------------------------------------------------------------//

// Not fully tested
Method AgeDays() Class TPlayer
   Local nDays 
Return DOM( date() )

//----------------------------------------------------------------------------//

// Not fully tested
Method AgeMonths() Class TPlayer
   Local nMonths := 0
   if month(::DOB) > month( date() )
      nMonths := month( date() ) - month(::DOB) + 12 
   else
      nMonths:=  month( Date() ) - month( ::DOB ) - 1
   endif
Return nMonths

//----------------------------------------------------------------------------//

Method AgeYMD()
Return alltrim(str(::Age())) +" years, "+ alltrim(str(::AgeMonths())) + ;
   " months, " + allTrim(str(::AgeDays()))+" days" 

//----------------------------------------------------------------------------//

// EOF
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 1487
Joined: Tue Jun 14, 2016 07:51 AM
Re: understanding OOP returning more than value from a method
Posted: Wed Oct 18, 2017 07:46 AM

Thanks.

Will do some more testing with diff. dates, but seems pretty OK !

I just had to change

// Not fully tested
Method AgeDays() Class TPlayer
Local nDays
//Return DOM( date() )
Return day( date() )

DOM = a function of yours ? Is the change correct ?

Marc Venken

Using: FWH 23.08 with Harbour
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
Re: understanding OOP returning more than value from a method
Posted: Wed Oct 18, 2017 01:38 PM

Marc,

RE: DOM() and Day()

Sorry, yes, DOM stands for day-of-month and I wrote it many years ago. Day() returns the same number and it was originally a Clipper function, now a (x)Harbour function. I don't know if the day() function didn't exist when I wrote DOM(), or if I just didn't know it existed.

I hope you can now see how to move functions into Methods. This way they are encapsulated in the class. This makes them easier to find, and edit. And further, your code outside the class becomes much easier to read and understand. You also reduce a lot of variable passing, since you often use class data instead.

James

FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10

Continue the discussion