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 Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Calling a subroutine and passing a parameter

Status
Not open for further replies.

dmusicant

Programmer
Mar 29, 2005
252
US
I had a line in a PRG:

Replace recordings with recordings()

Recordings is a field in the open table.

recordings() returns a value determined by PROCEDURE recordings.

When I wrote this, the procedure didn't require a parameter, but I decided to pass a parameter to the procedure, so the first two lines of the procedure then read:

PROCEDURE recordings
PARAMETER tcPasskey

At the end of the procedure was the line
RETURN cresult


So, how do I call PROCEDURE recordings and ask to replace recordings with recordings() if I have to pass a parameter in the call?

IOW, my call to PROCEDURE recordings has to look like REPLACE recordings WITH recordings(passvalue) instead of REPLACE recordings WITH recordings()

I worked around this seeming obstacle by creating a variable cpasskey before my call to PROCEDURE recordings and then referred to cpasskey within PROCEDURE recordings. Am I missing something or did I really have to do it that way?
 
Hi

I *think* you know how to do this - the first thing is that recordings has ceased to be a procedure, it is now a function - because it returns a value.
I think you should probably rename it to fnRecordings, because otherwise it has the same name as one of your fields.

Code:
Private cSomeDarnThing
cSomeDarnThing = "notMyPassKey"
Replace mytable.Recordings with fnRecordings("MyPassKey")
** mytable.Recordings = "Whoppee"
Replace mytable.Recordings with fnRecordings(cSomeDarnThing)
** mytable.Recordings = "UhHuh"

function fnRecordings
  Parameter tcPassKey
  local tcPassKey
  local cResult
  cResult = "UhHuh" 
  if tcPassKey = "MyPassKey"
     cResult = "Whoopee"
  endif
return(cResult)


Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are not good for you.
 
I am confused by your insistence of using the name Recording all the time. Why not use separate names for the different purposes? Remember the very important acronym KISS, "Keep It Simple, Sam". Something like

[pre]Procedure RecordingReplace
lParameter tcValue
Replace recording with RecordingValue(tcValue

Procedure RecordingValue
lparameter tcValue
Return MySpecialCalculationInvolvingtcValue[/pre]
 
how do I call PROCEDURE recordings and ask to replace recordings with recordings() if I have to pass a parameter in the call?

You've already answered your own question:

REPLACE recordings WITH recordings(passvalue) instead of REPLACE recordings WITH recordings()

Passing the parameter does not change the way you call the function or the way you handle the returned value. It does change the way the function works internally, but that's not the issue here.

And I definitely agree with Tore and Griff: It's a bad idea to use the same name for the function as for the field. Although the code will still work, it is inherently confusing, and should be avoided.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks for the excellent answers. Yes, not best coding practice to use the same name as the field name for the procedure that produces it.

My head was a little muddled there. I'd had to do some debugging that first required my undoing possible damage to data, which required me to reenter data, then run altered code with fingers crossed. Anyway, I think it's all straightened out now but won't know for sure until next week when I have fresh data, yeah, one of those.

Anyway, it's fun to be coding, I love it.
 
Also, if you pass in a variable as a parameter ( cpasskey ) then you need to declare a name for it in the PARAMETERS phrase as was shown in the examples above. You don't need to keep the same name within the subroutine, just be sure that whatever name you use within the function is the same name you send back on the RETURN line.

The purpose of having the ability to pass in parameters is that you can make the subroutine/function somewhat generic. For example, one time you may want to send in cpasskey and then another time send in cpasskey2, etc. The function doesn't care what the name of the variable coming from the calling code, all it needs to to know how to reference that information inside the function and then pass back the results on the PARAMETERS line. This design concept allows flexibility, structure and modular behavior.

You will find that there are some subtle behavior differences between PROCEDURE and FUNCTION regarding passed-in variables. You can review the Help topics for more in-depth details.
 
Yes, the other night I'd forgotten about the distinctions between function and procedure. In this case I would do better with a function. One reason I had the problem is that I created the procedure elsewhere in my code. I needed it again here, with some changes and just dropped it in and made changes, but it wasn't working. I had to take a close look to find out why the code had failed when I first ran it. My app came to an abrupt halt with a SUSPEND. It was a head scratcher because I had nothing in the code that would prompt a suspend. There was a SQL select into a cursor and then a SCAN of the cursor. Thing is, the SELECT had a fatal flaw and couldn't execute. So, there was nothing there to scan. Once I fixed the select clause it ran OK.

I might be able to modularize the procedure so that it exists in just one place instead of two. I started this app way back about 1994-5, it was the project for my FPD 2.6 course. I did it in FPW, which had just come out, the instructor OKed my using FPW. I've used it ever since, built on its humble beginnings a great deal. I think the original concept was fantastic. However, at the time I was not aware of good coding practices and there's a ton of stuff that should have been done differently. There are subtle data entry determining factors that I've long forgotten, dozens of them, and only a revisit of the code will bring them to mind. I remember the important stuff, of course. 97% of it is PRGs.
 
You will find that there are some subtle behavior differences between PROCEDURE and FUNCTION regarding passed-in variables.

For what it's worth, the only difference is that, by default, procedures receive their parameters by reference, and functions by value. Arguably, that's not such a subtle difference. And it's really a difference in the way in which procedures and functions are called, rather than the syntax of the routine itself.

In other words, if you were to change all your FUNCTION headings to PROCEDURE, and vice versa, it wouldn't make a scrap of difference to your program.

In practice, I very rarely use procedures. In the fairly rare cases that I want to pass parameters by reference, I use the "@" notation. I would guess that most other developers do the same - but feel free to correct me if that's not the case.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
> run altered code with fingers crossed.

In case I'm unsure, I simply create a new PJX and make some experiments. You can always create some cursors, if not copy some dbfs to make some experiments without riscing anything.

It seem you were caught in the idea a procedure strictly needs to be called in the way DO procedure WITH parameter, but then you already used the syntax procedure() to call it with brackets, which hold parameters and are empty for parameterless functions or proceddures.

Mike already said the differences between functions and procedures vanished, indeed you can even call a PRG with someprg() or someprg(param1,param2).

Bye, Olaf.
 
Yes, in the command window I like to enter things like:

=cal()

That brings up a calendar function where I can see dates. I embed that in code where I want to pick a date.

Part of my dilemma with the problems I was having the other night is that this app uses temporary tables. My instructor in the FPD 2.6 course was very into that. I adopted that technique. I guess it's not a bad idea. All the data entry is made to temporary tables and when I am done with a data entry session the app asks me if I'm ready to update the permanent tables. If I hit Enter, the transfer is made and the temporary tables are zapped.

Now in this case where I'm not sure that my data is going to be handled correctly because of my having added a field and some code to populate the field, I think I should back up my temporary tables before going through with the moving of data to the permanent tables. That way if there's something wrong, I won't have to do all the data entry again. The other day I was concerned that my permanent tables may have gotten erroneous data too, but I had backed them up and simply restored them from backup before reentering the data to the temporary tables. There wasn't that much data entry involved in this case, however I was concerned at the time because I was far from confident that I'd fixed the problem! I'm much more confident now, not sure though. I'll be a little careful and inspect my data until I'm sure.
 
Since FPD 2.6 many things have changed, what you do with temp tables can be done with buffering. To be sure about data changes you do auditing, logging the changes, via stored procedure triggers, for example.

Anyway, such a small change first only affects your temp tables, doesn't it? It's a one time call at the command window, to see such a replace works.

Bye, Olaf.
 
Right, Olaf. It pays to always remember that VFP is really a radically different programming language from FPD/FPW in many (but not all) ways. Continuing to use FPD methodologies is often the worst way and in addition it's more work just to pour salt in the wound.

My very first public presentation about VFP directly contradicted the whiny nay-sayers that complained "but I don't want to throw away all my old code". I went through several examples showing why you probably WANTED to throw away old code and methodologies, and how much work it would actually save you. [lipstick2]

 
Olaf said:
Anyway, such a small change first only affects your temp tables, doesn't it? It's a one time call at the command window, to see such a replace works.

That code works within a program so that just running it in a command window wouldn't work without setting up the environment. Also, a permanent table is updated by that function. Not all changes within the app use the temporary table methodology.

By the time I was aware of VFP (my employer at the time, as a side thing actually ran VFP training courses and sent me to two of them), my FPD code was very extensive and I didn't want to ditch it and start over in VFP. It did what I wanted to do on a continuing basis, there have only been occasional changes/additions. Yes, I could have ditched the FPD/FPW code, I was unaware of compelling reasons to do so. The code still works, with occasional problems only, the only one that comes to mind now is the thing throwing a nasty error when returning to the opening screen, as I've said. Creating a VFP form recently seems to have worked around that problem.
 
Well, you just wanted to test a simple change of a call of a procedure. As I said earlier you can always create a new prg, new dbfs, even a new pjx to test something without touching production data. And that can be done on the command window too, if it's just about a single change like this.

Indeed I have a copy of data for testing and development anyway. One of the major good practices leading to good sleep.

Bye, Olaf.
 
Yes, I think most of us have something similar. I've got an entire directory populated with test DBFs and DBCs, forms containing various controls, various types of reports, etc. If I'm not sure how something works in VFP, I can easily create a quick test, quite separate from my main development environment. Eventually the directory gets filled with rubbish, so I throw it all away and start again.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Olaf said:
Indeed I have a copy of data for testing and development anyway. One of the major good practices leading to good sleep.
I've managed to never get myself into hot water with my coding. In my last full time job I could easily have done that on a daily basis. I thoroughly tested my work before unleashing it on my users, who were company employees, either on site or at our many other locations.

With my own data I'm backed up. I don't back up every day, average is once a week, so I could screw things up short term and have to backtrack a little.

My email client once in a while goes crazy. It's happened a couple of times over the last 6 months, one large folder (the Inbox, which is for stuff to me that doesn't get routed into categories) instead of downloading new emails wants to download ~30,000 emails!!! I don't know how to fix it other than copy another machine's installation and restore the outbox (which hasn't gotten corrupted). Then it is pretty much OK. The only real difference between that app's installation on my various PCs is the outbox. I would like to figure out a way I could move that app's data to a different program, I'm sure it's doable. The app is Forte Agent 1.93x. I think the tables are pretty standard stuff. The file extensions are .DAT and .IDX.
 
I don't ALWAYS test QUITE as thoroughly as I probably should.

It's very hard to test all possibilities... I've had a nightmare with stamping
PDF files with QR barcodes for example.

There are so many PDF creators, of varying 'quality' it's very hard to find a reliable
stamper, and when you do - it's nigh on impossible to find the 'top-left' corner with
any sense of security... you get page sizes 3 units wide by 4 units tall, which sounds like
it might be portrait, but it might be rotated by 0, 90, 180 or 270 degrees. Why would anyone
produce a 3x4 (portrait) and rotate it by 270 degrees to make it a backwards/upside down landscape
where the top left is now the bottom right?




Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are not good for you.
 
I take your point, Griff.

I'm currently writing a program that converts a binary file format to HTML. I was getting into a real twist with testing for every possible combination of format codes, including such awkwardnesses as:

[tt]<b>Example<i> of some</b> formatted text.</i>[/tt]

Then I reminded myself that the program will only ever be used once, on just a single file. If any such anomalies arise in practice, it will probably be easier for me to hand-edit the output file.

But in this case, I'm the user, so there's no question of my "unleashing" it on anyone else.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
>I thoroughly tested my work before unleashing it on my users

Indeed we all do, but what does it mean. In the end you run it, and you better run it against copies of the data, test and development data? Why three stages? First any new development most of the time also means you change tables, that shouldn't be done on production data, as long as your code is not thoroughly tested and released to end users. So you do that on the development database. Next stage is testing, this gets almost stable versions of your changes to test with a test user base, you also test the database upgrade process, but still not on production data, you test that on test data.

You can always downgrade test and development data to the level of production data to repeat tests. That way you don't fiddle with repairing half working updates, you simple restart from the stable situation.

I canÄt say what you did, when you said "thoroughly tested my work before unleashing it", but your answer implies you didnÄt do that on data copies. Maybe you did and just didn't call the copies of data you worked on test and development data. But if you didn't, what do you call thoroughly testing? Testing on prod data and reverting the data from backups if something went wrong? Reverting the work of end users for the day? It's expensive if hundreds or thousands of working hours are reverted.

So what is there to say against the concept of data copies you do your development with? You came here to ask for second and third oppinion about a code change you can simply test on restorabe data copies, can't you? So it seems you don't live that concept so far and I jsut ask myself why?

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top