understanding OOP returning more than value from a method

understanding OOP returning more than value from a method

Postby Ehab Samir Aziz » Tue May 04, 2010 8: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: Select all  Expand view  RUN
#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)
 
Ehab Samir Aziz
 
Posts: 334
Joined: Fri Oct 14, 2005 1:54 pm

Re: understanding OOP returning more than value from a method

Postby gkuhnert » Tue May 04, 2010 9: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
User avatar
gkuhnert
 
Posts: 274
Joined: Fri Apr 04, 2008 1:25 pm
Location: Aachen - Germany // Kerkrade - Netherlands

Re: understanding OOP returning more than value from a method

Postby Ehab Samir Aziz » 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: Select all  Expand view  RUN
#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)
 
Ehab Samir Aziz
 
Posts: 334
Joined: Fri Oct 14, 2005 1:54 pm

Re: understanding OOP returning more than value from a method

Postby Adolfo » 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
User avatar
Adolfo
 
Posts: 860
Joined: Tue Oct 11, 2005 11:57 am
Location: Chile

Re: understanding OOP returning more than value from a method

Postby xProgrammer » Wed May 05, 2010 9:51 am

Hi all

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

Perhaps most importantly the quoted code

Code: Select all  Expand view  RUN
::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: Select all  Expand view  RUN
::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: Select all  Expand view  RUN
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: Select all  Expand view  RUN
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: Select all  Expand view  RUN
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: Select all  Expand view  RUN
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
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Return age (year,Mnd,day) from a date

Postby Marc Venken » Mon Oct 16, 2017 9: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.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: understanding OOP returning more than value from a method

Postby James Bott » 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
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: understanding OOP returning more than value from a method

Postby Marc Venken » 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.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: understanding OOP returning more than value from a method

Postby fafi » Tue Oct 17, 2017 1:03 pm

Hello,
Please test..

Code: Select all  Expand view  RUN


#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
User avatar
fafi
 
Posts: 169
Joined: Mon Feb 25, 2008 2:42 am

Re: understanding OOP returning more than value from a method

Postby karinha » Tue Oct 17, 2017 1:13 pm

Very good Fafi. Many thanks. Congratulations!

fafi wrote:Hello,
Please test..

Code: Select all  Expand view  RUN


#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
User avatar
karinha
 
Posts: 7831
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: understanding OOP returning more than value from a method

Postby Marc Venken » Tue Oct 17, 2017 6: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.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: understanding OOP returning more than value from a method

Postby fafi » Tue Oct 17, 2017 7: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

:D

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

I think that is your DOB, right ? :lol:

Best Regards
oPerson1 :=Tperson():new("Fafi",ctod("09/05/1967"))
User avatar
fafi
 
Posts: 169
Joined: Mon Feb 25, 2008 2:42 am

Re: understanding OOP returning more than value from a method

Postby James Bott » 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: Select all  Expand view  RUN
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: Select all  Expand view  RUN
/*
Purpose  : Player class
Program  :
Author   : James Bott, jbott@compuserve.com
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
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: understanding OOP returning more than value from a method

Postby Marc Venken » Wed Oct 18, 2017 7: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.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: understanding OOP returning more than value from a method

Postby James Bott » Wed Oct 18, 2017 1: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
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 56 guests