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

return multiple results in a function 1

Status
Not open for further replies.

AP81

Programmer
Apr 11, 2003
740
AU
Is there a way to return multiple results in a function:

e.g.

function DoQuery(sQuery : String) : boolean; string;




------------------------------------
There's no place like 127.0.0.1
------------------------------------
 
You could do this by using the VAR parameter as in:

function DoQuery(sQuery : String, var RetVal1 : string) : boolean;

in the function body, you will obviously need to set RetVal1 to something (so that it can be returned) and also return a boolean as a result in the normal way.

you could then call the function using something like:

var
ReturnVal, QueryString : string;
BoolVal : boolean;

QueryString := 'Some Value';
ReturnVal := ''; //not really needed
BoolVal := DoQuery(QueryString, ReturnVal)

if BoolVal etc, etc
if ReturnVal = (or <>) etc etc


Hope this helps.

[vampire][bat]
 
Thanks,

Did the trick.




------------------------------------
There's no place like 127.0.0.1
------------------------------------
 
Or - you could return a record:

Code:
type
  TMyRec = record
    Str : String;
    Boo : Boolean;
  end;

function DoQuery(AQuery: String): TMyRec;
begin
  // do stuff
  Result.Str := 'hello';
  Result.Boo := False;
end;

procedure CallQuery;
begin
  with DoQuery('this is my query') do
    if Boo then
      Edit1.Text := Str;
end;
 
Its not considered good 'style' to use var parameters with functions, but you can do it!!
Gryffyn's method is OK.

Steve: Delphi a feersum engin indeed.
 
If you find you need to return unrelated multiple results from a function, it might be wise to have another look at your function and see if it can be refactored into smaller functions that each have a specific task.

Bundling together unrelated results into a record structure/object just for the sake of it is obviously not good design and indicates that your function is too generic and/or large.

Code is much easier to read when arduous tasks are broken down into smaller, specific functions/procedures that have been given meaningful names.

Clive
Runner_1Revised.gif

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"To err is human, but to really foul things up you need a computer." (Paul Ehrlich)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To get the best answers from this forum see: faq102-5096
 
Ironically, my first thought was to return a record, but after re-reading the original question I felt that a var parameter was a closer answer to the request. I should really have included a record as an alternative.



[vampire][bat]
 
When I have to return multiple results i just create global vars and use a procedure to get them

[bobafett] BobbaFet [bobafett]

Code:
if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');
faq102-5352
 
It was my understanding that global vars were frowned upon for 'general' use such as that.

I tend to use records to return variables if I will be using that record structure in more than one place in my code. Otherwise I'll just use one or more var parameters as earthandfire demonstrated.
 
The global vars thing originates from the old days when computer's didnt have much memory to spare, coupled with the clarity thing, though i'm not sure if shunting data about between procedures and functions makes things any clearer?
Also OOP purists will always frown on the use of Globals, because they don't 'belong' to anything.
I tend to write a lot of serial comms stuff and getting data in and out of Com port driver components can be a problem. Its much easier to 'throw one together', if you use globals.
The same for timers I would say.
So there are globals in my programs, but I do try to keep them to a minimum, just force of habit mainly.


Steve: Delphi a feersum engin indeed.
 
Well, I've got nothing to do with OOP purists, I'm only interested in getting stuff to work :)

[bobafett] BobbaFet [bobafett]

Code:
if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');
faq102-5352
 
Global variables....
-Dont use'em unless you really need'em.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-"There is always another way to solve it, but I prefer my way.
 
Why?

[bobafett] BobbaFet [bobafett]

Code:
if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');
faq102-5352
 
You can't be sure of the state of the global variable.
It might have been altered in another function/procedure.

And then, what if you are a group of programmers updating the same project? Can you be sure of the state of the variables?

Using global variables is kind of old school practice (Before the OOP era).

Now it's your turn to defend the use of global variables, BobbaFet... ;-)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-"There is always another way to solve it, but I prefer my way.
 
I'll chime in here...

Global variables are ideal for communicating between threads, and when implemented along with the knowledge of what bits of code use them can be handy to communicate between modular pieces of code.

Regarding global variables and their 'unknown' state - Not sure what sort of program is one where variables are allowed to be clobbered by different functions/procedures. Maybe I misunderstood what you're saying Nordlund, but not knowing something about the program one is writing sounds kinda sloppy and is more of an issue than the humble global variable :)
 
Nordlund said:
Global variables....
-Dont use'em unless you really need'em.

BobbaFet said:

My 2 cents worth:

One word: maintenance.

If your program will never be modified (even by you) it makes no difference whether you use global variables or not. However, if there is any chance that the program will need revision/modification/enhnacement in the future (whether by you or not), the use of global variables can cause problems (except in very small programs).

If the piece of code you are changing references a global variable, and the change requires modification in the way that the global variable is calculated, then that "one small change" may require changes in many places. And, whether or not other changes are required, you at least have to consider the possibility and spend time looking at other parts of the code.

The idea is to limit the scope of each variable to no larger span than is absolutely required. Ideally, that "one small change" can be made without having to worry about unintended side effects elsewhere in the program.

So, if your program will only live for a few weeks, or if you can guarantee that it will never be changed, or if you will always be around to be the one who makes all changes, then go ahead and use globals to your heart's content. But if not, beware!

 
what about in a situation like this:

I've been creating a report generator that is called from AS400/RPG programs. Each report has two versions, an English and a Spanish. There is a single directory for the Document Templates and within that directory there are two folders, one holds the spanish versions, one the English version. There are at this time 6 different reports. The calling program passes in:

Param 1 - Which report to call:
Code:
Case StrToInt(Paramstr(1)) of
     1:  GeneratePSR.PSRGenerator(UpperCase(ParamStr(2)), ParamStr(3));
     2:  GeneratePSR.DamageAssessment(UpperCase(ParamStr(2)), ParamStr(3));
     3:  GeneratePSR.RestitutionAgreement(UpperCase(ParamStr(2)), ParamStr(3));
     4:  GeneratePSR.TreatmentReferral(UpperCase(ParamStr(2)), ParamStr(3), ParamStr(6));
     5:  GeneratePSR.FailToComply(UpperCase(ParamStr(2)), ParamStr(3));
     6:  GeneratePSR.Conditions(UpperCase(ParamStr(2)), ParamStr(3));
     7:  GeneratePSR.RestitutionPayment(UpperCase(ParamStr(2)), ParamStr(3));
   end;

2. CasePrefix
3. CaseNumber
4. UserId
5. Spanish (Y/N)

There are no forms in this project.

I have a global variable: booSpanish

this variable is set based on the parameters passed in from the AS400/RPG program and sets which directory to find the correct document and is used to determine which variable text items to use (some reports have additional text added in dynamically and that text also needs to have the translations)

Would you consider this an appropriate use of a global? If not, how would you handle this application?

Leslie

Anything worth doing is a lot more difficult than it's worth - Unknown Induhvidual

Essential reading for anyone working with databases: The Fundamentals of Relational Database Design
 
I wouldn't quibble about using a global in this case to switch the state of the application between English and Spanish, IF YOU KNOW FOR CERTAIN THAT ONLY THOSE TWO LANGUAGES WILL EVER BE NEEDED. That probably wouldn't give the maintenance programmer heartburn. However, what are you going to do when a third (and fourth, etc.) languange is added? Create more booleans? What does that do the logic where the language (folder) is chosen?

I would probably want to do something like this:
Code:
type
  TLanguage = (dlEnglish, dlSpanish);
  
  TPSRReport = (psrGenerator, psrDamageAssessment, psrRestitutionAgreement, psrTreatmentReferral, psrFailToComply, psrConditions, psrRestitutionPayment)

  TLanguageSupport = class
  private
    { Private declarations }
  public
    { Public declarations }
    class function TemplateFolder(ALanguage:TLanguage):string;
  end;

  TCase = class
  private
    { Private declarations }
    FPrefix:string;
    FCaseNumber:integer;
    FUserID:string;
  public
    { Public declarations }
    constructor Create( AUserID,APrefix:string; ACaseNumber:integer);
    property Prefix:string      read FPrefix;
    property CaseNumber:integer read FCaseNumber;
    property UserID:string      read FUserID;
  end; 
:
:
:
implementation

procedure PrintReport( APSRReport:TPSRReport; ACase:TCase; ALanguage:TLanguage );
begin
  case APSRReport of
    psrGenerator:  PSRGenerator( ACase:TCase, ALanguage:TLanguage );
    psrDamageAssessment:  etc.
    psrRestitutionAgreement:
    psrTreatmentReferral:
    psrFailToComply:
    psrConditions:
    psrRestitutionPayment:
  end;
end;

class function TLanguageSupport.TemplateFolder(ALanguage:TLanguage):string;
begin
  case ALanguage of
    dlEnglish: Result := 'c:\Templates\English\';
    dlSpanish: Result := 'c:\Templates\Spanish\';
  else
    raise .......
  end;
end;

That's pretty rough, but it should give you the idea. It allows me to add languages and reports without a major alteration to the structure that controls the process. And each report routine stands by itself.



 
Hi.
Every application has to have some kind of platform.
Standard Delphi project has a MainForm.
Services/ServiceApplications has TService class....

In this case, your command switches are the base of your report generator.

I would create a platform with the command switches as the first set of properties, almost like Zathras example above...





~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-"There is always another way to solve it, but I prefer my way.
 
thanks for the information, I'll look it over and see what I can learn! In this case there will probably only be the two languages (I'm in New Mexico and bi-lingual is here to stay!)

Have a great day!

Leslie
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top