Page 1 of 1
understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 8:16 am
by Ehab Samir Aziz
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
#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)
Re: understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 9:33 am
by gkuhnert
After calling the methods age() and calculate() you simply can access the values oPerson1:nAge_Months and oPerson1:nAge_Days
Re: understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 10:13 am
by Ehab Samir Aziz
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
#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)
Re: understanding OOP returning more than value from a method
Posted: Tue May 04, 2010 12:37 pm
by Adolfo
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}
Re: understanding OOP returning more than value from a method
Posted: Wed May 05, 2010 9:51 am
by xProgrammer
Hi all
I would like to add a few comments to this discussion.
Perhaps most importantly the quoted code
Code: Select all
::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
::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
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
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
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
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
Return age (year,Mnd,day) from a date
Posted: Mon Oct 16, 2017 9:36 pm
by Marc Venken
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 ?
Re: understanding OOP returning more than value from a method
Posted: Mon Oct 16, 2017 10:41 pm
by James Bott
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
Re: understanding OOP returning more than value from a method
Posted: Mon Oct 16, 2017 11:08 pm
by Marc Venken
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
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 1:03 pm
by fafi
Hello,
Please test..
Code: Select all
#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
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 1:13 pm
by karinha
Very good Fafi. Many thanks. Congratulations!
fafi wrote:Hello,
Please test..
Code: Select all
#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
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 6:56 pm
by Marc Venken
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
Re: understanding OOP returning more than value from a method
Posted: Tue Oct 17, 2017 7:22 pm
by fafi
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"))
Re: understanding OOP returning more than value from a method
Posted: Wed Oct 18, 2017 12:08 am
by James Bott
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
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
/*
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
Re: understanding OOP returning more than value from a method
Posted: Wed Oct 18, 2017 7:46 am
by Marc Venken
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 ?
Re: understanding OOP returning more than value from a method
Posted: Wed Oct 18, 2017 1:38 pm
by James Bott
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