Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to get the return value of a prg? 6

Status
Not open for further replies.

Mandy_crw

Programmer
Jul 23, 2020
585
PH
Hi everyone, i found a program from this site, and saw it will be useful to my project, my question is how can i copy the reurn value of the program? I want to put the return value LcPhrase to a variable so that i could print it... thanks in advance....

** Author : Ramani (Subramanian.G)
** áFoxAcc Software / Winners Software
** ** Type á: Freeware with reservation to Copyrights
** Warranty : Nothing implied or explicit
** Last modified : June, 2003
*********************************************************
** How to Run..
** 1. Save the following code as Num2Word.PRG
** 2. From within your PRG or Report call it as
** áááNum2Word(nYourAmount)
*********************************************************
** Modify decimal places suitably, if > 2 decimals required
*********************************************************

** FUNCTION num2word

LPARAMETER amt
amt = ABS(amt)

IF amt > 999999999999.99 && => 1000 billion
=MESSAGEBOX("Amount exceeds word convertion provision. Contact system administrator", ;
0+16, "CAUTION. Check total amount !")
ENDIF
IF amt = 0
RETURN "Zero Only."
ENDIF

** used by Function numWord

PRIVATE pcWord1, pcWord2, pcWord3, pcWord4, pcWord5, pcWord6, pcWord7, ;
pcWord8, pcWord9, pcWord10, pcWord11, pcWord12, pcWord13, pcWord14, ;
pcWord15, pcWord16, pcWord17, pcWord18, pcWord19, pcWord20, pcWord30, ;
pcWord40, pcWord50, pcWord60, pcWord70, pcWord80, pcWord90
pcWord1 = "One "
pcWord2 = "Two "
pcWord3 = "Three "
pcWord4 = "Four "
pcWord5 = "Five "
pcWord6 = "Six "
pcWord7 = "Seven "
pcWord8 = "Eight "
pcWord9 = "Nine "
pcWord10 = "Ten "
pcWord11 = "Eleven "
pcWord12 = "Twelve "
pcWord13 = "Thirteen "
pcWord14 = "Fourteen "
pcWord15 = "Fifteen "
pcWord16 = "Sixteen "
pcWord17 = "Seventeen "
pcWord18 = "Eighteen "
pcWord19 = "Ninteen "
pcWord20 = "Twenty "
pcWord30 = "Thirty "
pcWord40 = "Forty "
pcWord50 = "Fifty "
pcWord60 = "Sixty "
pcWord70 = "Seventy "
pcWord80 = "Eighty "
pcWord90 = "Ninety "
**
LOCAL lcNumPhrase, lcNumStr

m.lcNumphrase = ""
m.lcNumStr = STR(amt,17,4)

IF VAL(SUBSTR(m.lcNumStr,1,3)) > 0 && Amount in Billions
m.lcNumphrase = m.lcNumphrase + Numword(SUBSTR(m.lcNumStr,1,3)) + ;
" Billion "
ENDIF

IF VAL(SUBSTR(m.lcNumStr,4,3)) > 0 && Amount in millions
m.lcNumphrase = m.lcNumphrase + Numword(SUBSTR(m.lcNumStr,4,3)) + ;
" Million "
ENDIF

IF VAL(SUBSTR(m.lcNumStr,7,3)) > 0 && Amount in thousands
m.lcNumphrase = m.lcNumphrase + Numword(SUBSTR(m.lcNumStr,7,3)) + ;
" Thousand "
ENDIF

IF VAL(SUBSTR(m.lcNumStr,10,3)) > 0 && Amount below thousands
m.lcNumphrase = m.lcNumphrase + Numword(SUBSTR(m.lcNumStr,10,3))
ENDIF

IF VAL(SUBSTR(m.lcNumStr,14,2)) > 0 && Amount in Decimals
** needs tingering depending on digits - Default is 2 decimals
IF LEN(ALLTRIM(m.lcNumphrase)) > 1
m.lcNumphrase = ALLTRIM(m.lcNumphrase) + " and "
ELSE
m.lcNumphrase = "Zero and "
ENDIF
m.lcNumphrase = m.lcNumphrase + SUBSTR(m.lcNumStr,14,2) + "/100"
ENDIF

IF LEN(ALLTRIM(m.lcNumphrase)) > 1
m.lcNumphrase = ALLTRIM(m.lcNumphrase) + " Only."
ENDIF

? m.lcNumPhrase

RETURN m.lcNumphrase


*********************************************************
** Called by: numtoword() (function in NUMWORD.PRG)
*********************************************************


FUNCTION numword
LPARAMETERS tStr

LOCAL lnStr, lcPhrase, lcStr
lcPhrase = " "
lnStr = VAL(tStr)

** Hundredth position
IF lnStr > 99
lcStr = LEFT(tStr,1)
lcPhrase = pcWord&lcStr + "Hundred "
ENDIF

** Balance Position
lnStr = VAL(RIGHT(tStr,2))
IF BETWEEN(lnStr,1,20)
lcStr = ALLTRIM(STR(lnStr))
lcPhrase = lcPhrase + pcWord&lcStr
ENDIF
IF BETWEEN(lnStr,21,99)
IF lnStr > 20
lcStr = SUBSTR(tStr,2,1)+"0"
lcPhrase = lcPhrase + pcWord&lcStr
ENDIF
IF RIGHT(tStr,1) > '0'
lcStr = RIGHT(tStr,1)
lcPhrase = lcPhrase + pcWord&lcStr
ENDIF
ENDIF
RETURN ALLTRIM(lcPhrase)
 
Mandy,

while that's a new question and interesting enough for future readers to make it a new thread, I'll try to give it a 1 post answer. If that won't answer it for you and you have questions, then please make this a new thread.

1. RETURN is the only command to return something from anywhere (procedure, function, PRG , method/event) It's usable in any code, returns to the caller, and returns one value. What this can return is fully described in its help topic, and it can't, for example, return two values in the form RETURN var1,var2. That won't work. Edit: In Python you can do that, and in fact in Python you also can define tuples as a variable type and thereby turn any return of two single values into a return of one tuple and don't need the mechanism. But jst to mention it, something like that exists, just not in VFP and most other languages.

2. It should be clear, but I'll mention explicitly, you can't return arrays. If you think the array name without specifying any index like arrayname[5] will mean the whole array, you'll learn that without an index you'll only address the first element of the array.

3. You can do something from the caller, you can pass in parameters by reference, when prefixing variable names with @. If you call function(@var1) the function gets this parameter and can work on it as usual, but everything it does to this variable, everything it stores to this variable, will also become the value of your variable. This doesn't mean you can force a return value through this, a function only reading this parameter will not change it, but you can design functions to work on parameters, also two or more parameters, and thus you can design something that'll suit your need to get two results back.

Such passing by reference mechanism is also called in-out parameters in other programming languages, which describes it much better as "reference".

4. While we're at passing by reference, there's one type of parameter that's always passed by reference: An object. No matter if you call function(objectvariable) or function(thisform.text1), the object in the variable or the direct object name means the parameter of the function is that object and you can change it, and that changes the object itself, so it passes back whatever you do.

Points 3 and 4 both happen without any RETURN.

5. You can also create objects within a function and return them. And objects can have to or more properties and therefore return 2 or more values. That perhaps should have been number 1, but I think it's only really understandable when you learned about 1-4 in the first place.

6. What works besides the usual mechanism of passing in something in and returning something are private variables. A function cannot access local variables from the caller, but variables you declare private you share with anything that you call. This is bad OOP encapsulation, but it is indeed also encapsulating, whatever variables you create without declaring them LOCAL at first are variables also readable by a function or PRG (btw anything that works for a function also works for a PRG). So there just has to be the knowledge of the function that private variables of specific names exist and can be used and manipulated so to get back something to you. In this way you can also work on multiple variables as if they were passed in by reference with @var1, @var2, for example. But you neither need to call function(@var1, @var2) nor do you need LPARAMETER statement that receives these parameters by value, you just know the private variables exist. It's making this an encapsulated knowledge convention of both caller and function.

7. If that's still not enough options I don't know. If I would think hard enough I'd maybe come up with more ideas. For example, as I often say code can manipulate anything like files in VFP most probably tables files, through which you can also "return" many things in the same manner as by objects passed in by reference, as this data changes will "return" by simple being the new state everywhere, also for the caller. Which means this point 7 should cover that you don't even need an explicit return mechanism to receive a result. The result could be the modification of something that the caller then can read. For example in reports, calling a function even without any parameters, this function will also have access to the workarea of the report and would be able to change data of the current record (or even further records) before it is printed. If you're fine with manipulating data as you print it, that's one more possibility.

Point 7 alone actually means something like RETURN is not a necessary construct at all. If you don't realize code can manipulate anything and that can be made temporary or permanent but will effect this so other code, including the caller, can get it from there and that's far more versatile anyway. The reason RETURN exists in all languages is it's still a comfortable way and usually you also only need one return value.

All that said I have a question for you: Why do you need 2 return values? If you can't tell so in a short sentence, that's a good reason to start a new thread and ask that question again, in the context of your specific need. You have to realize that your questions have to become better to get better and more concrete answers or solutions to the actual problem. I bet in a bigger context you never need a return of 2 values, you either need two functions each returning one value or a function that does not only compute those two results you "need" but also acts with them as you would do as the caller. Or a function that manipulates the things that will be used by the context the caller is in and thus those two results will be automatically available without an explicit RETURN of them.

It's a bold statement to say, but it's true simply by what point 7 explains. Things manipulated by code are seen anywhere else, so there is no specific need of a RETURN mechanism. Programming would only become more complicated if you'd always need to know where to look for the effect of a call that you're interested in.

Chriss
 
Whew!! Thats a very comprehensive answer Chris!! When i got the answer from the question ive asked about returning a value from a program, i have imagined to create another program to enhance my application… ive thought returning alot of variables, like name surname mobile number etc every time an id number is entered… so i want a procedure that will display all these info… so that i can get rid of the repeated codes.. im sorry chriss i am really a newbie in vfp, but more than willing to learn alot… that why i ask frequently… i just want more in my app but i really lack knowledge… but dont worry ill creat another thread for this question if ever… thank you so much Chriss you are ao generous and kind… God bless…
 
It's okay, and things like best use of the forum to make answers findable can always be mended later on, by just copying over what was already posted into a new thread, too.

The short answer to returning a whole record of an id, is, well, not returning the values, but simply positioning on the record of that id, so it can be accessed by the caller. So a SEEK, for example. We discussed this in length and detail in another of your threads.

Chriss
 
Mandy, I don't want to detract from Chris's detailed answer, but I would elaborate his points about passing parameters by reference, and passing arrays as parameters (his points 3 and 4).

Basically, if you pass a parameter by reference, it means that the function can change its value, and the calling program will then see those changes. So that's an alternative method of returning a value. And if the parameter happens to be an array, then you can use that to return multiple values.

Here is an example:

Code:
* Define an array (with 4 elements)
DIMENSION laVals(4)

* Initialise it (to empty values)
STORE "" TO laVals

* Call your function, passing the array as
* a parameter (the @ symbol means that you are
* passing it by reference)
MyFunction(@laVals)

* The array now contains the four returned values
? laVals(1), laVals(2), laVals(3), laVals(4)


FUNCTION MyFunction
LPARAMETERS taArray
  * This is your function, which receives the array
  * as a parameter. Note that the array does not 
  * have to have the same name as in the calling prog.
  
  *** do stuff here ***
  
  * Store the values that you want to return
  taArray(1) = "Lucy"
  taArray(2) = "Desi"
  taArray(3) = "Fred"  
  taArray(4) = "Ethel"  
  
  * Note that there is no need to return the array.
  * It still exists in the calling prog.

ENDFUNC

In this example, we are returning four character strings. But you can use the same technique to return any number of values, of almost any data type.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I was about to give one example for each of the ways to return something, but I think I spare that to when you start a new thread, Mandy.

One thing to add besides points 1-7 is, that only a RETURN will make the returned value the direct result of the call. So if the caller is the expression of a property or a report control, then ways to use by reference parameters or private variables won't help, the property is set to the direct return value and that's given by an explicit RETURN or if that's omitted and the function returns because it ends, that will be .T., what you can't do in such a situation is make a call and after it want the property to have one of the private variables or array elements or one of the object properties as value to store or to print. So while an expression is code that can call a function, it's direct result value is what needs to fit there. I have the strange feeling a report is where you wanted to use this but a report control expression can't print two things, it can only print the direct single return value coming back from the function. What's also not working is passing fields by reference, which means functions could not modify fields by having them passed in by reference and being able to act on them as variables.

You could dig deep in the bag of tricks and call EXECSCRIPT to execute multiple lines of code, but also that call would need to end on RETURN of one single value. So overall, when thinking about report control expressions, no mechanism for two or more return values will work.

And finally, the only way a single value can look like multiple values is when you use the most versatile data type, the string. Obviously a string could be a full name as "Lastname, Firstname", for example or whatever. It could even be a whole file. But that doesn't make it two separate values.

So only code that's in a PRG or method or event can make use of the mechanisms that work with parameters by reference or objects or such thigs. You always need to follow the call with further lines of code making use if the return values. Using a function which RETURNs an object with two or more properties to a report control, what will be printed is the string "(object"), not one of its properties. Which shows that most of the workarounds won't help in the case of an expression. The only thing that you can do to print something not in the report workarea but another one, is setting the report control to otheralias.field and navigating in that other workarea by a relation you set before running the report with SET RELATION. Which means while the report scans the report driving workarea each time the record pointer moves there, relations set by SET RELATION move to related records in other workareas and you need no call of anything for that to work, that is automatic and will be triggered anytime the record pointer in the root workare of a relation is moved. That's the proposed way of working with multiple workareas in a report.

But the more often used concept is to prepare the data to print in one workarea, so you don't need anything from a bag of tricks.

And closing the circle by going back to the Num2Word function, this is surely a good example of a function to use on a report where needed. You can't put this into an expression, you need the function in this case. Or you prepare all data before printing. And that's the choice most of us make to not have the need for any expressions other than field names.

Chriss
 
Although I've not contributed to this thread, I have been following it with interest. The thread as given me some useful ideas for my own applications.

Thank you to Mike, Chris and others for your helpful contributions, much appreciated.



Regards,

David

Recreational Developer and End User of VFP for my personal use in 'Amateur Radio' and 'British Railways' related Applications.
 
Hi Mandy,

You have certainly received some great expert advice on this. Just to add a thought:

I don't claim to have the best (or only) style of programming, but I have always made heavy use of the AddProperty function, especially in the Init() method. A property can always be changed in any part of your app regardless of HOW it is passed (or not passed). Multiple properties can be passed, changed and normally don't need to be RETURNed. They can also be referenced in reports.

Just a thought.

Steve
 
Again, SET PATH already was covered in the first answer from 23 Apr 22 05:39.

But I agree with one thing: You could be confused by too much info. With a new question you should always start a new thread, we should already have advised that for your question about copyright.

I would add that the questions you ask show, that you should rather ask what to do, if you want to achieve something, because you ask for concepts that are rarely useful. Otherwise they would be integrated into the functions and commands of the language. And RETURN is something you should know from your legacy Foxpro programming days already. And you can always look into the help for any language construct,, the command, the functions, the classes that exist in VFP, they are all described. And there is no RETUN a,b syntax described in the help topic of RETURN.

The only thing missing in this thread is making a final comment and then ask your next question in a new thread, please Mandy. That will not only be helpful for us, but also for yourself and for future users searching the forum for answers. They will mostly decide what threads to read by thread title, and your title has absolutely nothing to do with copyright or with returning two values at once. So our answers ar available for you, but lost for people not believing that a keyword like copyright leads them to a thread titled "How to get the return value of a prg?"

At this point please note what a FAQ for this forum tells you about how to make best use of this forum as someone asking questions:
faq184-2483

Chriss
 
Thank you all... my feelings right now is overwhelming... i felt i have alot of peope to back me up... Thanks Chriss Mike Myearwood Steve and everyone you are all amazing and generous... noted on all your advices... God bless...
 
I agree this thread should be closed by now.

myearwood said:
you cannot be sure she understands SET PROCEDURE or SET PATH

True, but she can ask, that's for sure. And you can find how to use any command or function in the help. If she doesn't find that, again, she can ask.
Since I didn't gave a full example here, the more so.

Chriss
 
Ok myearwood... I'll try to study it well... thanks and God bless...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top