Returning multiple results from a subroutine ?

D

Dr John Stockton

What are the best ways of returning multiple results from a subroutine ?

I've been using
... return [a, b, c] }
which is inelegant.

I'm used to Pascal's
procedure X(const A, B : integer; var C, D : byte) ;
where A, B are inputs only, and C, D are in/out.

The needed parameters tend to be numbers, and don't need to be objects.

... return {aa:a, bb:b, cc:c} } // seems OK

but with that the parameter names aa, bb, cc are not visible in the
calling statement, which is a defect.

I'm specifically trying to extend, neaten, & improve <URL:http://www.mer
lyn.demon.co.uk/js-date5#DDTA>.
 
D

David

It may be less elegant than what you have now, but you could put all
the numbers into an array. Then just pass a single variable (the array
name) in and out of the sub-routine and access the elements of the
array as required.

David
 
R

rh

Lasse Reichstein Nielsen said:
(e-mail address removed) (asdf asdf) writes:
I miss the tuples and simultaneous assignments of languages like SML
and Perl. There is no equivalent in Javascript. The closest would be
a returning an object and using a "with" statement.

Or, at the risk of offending those who so far only moderately despise
"with", and highly despise "eval", you could alternatively re-manifest
the return object properties into caller variables by:

for (var j in retObj) eval(j +"=retObj['"+j+"']");

which might come a little closer to call by name than the use of
"with". That's in the vein of a somewhat neutral observation, as
opposed to a recommendation, however.

(By the way, I fully concur with the attempt to stamp out the evil of
[completely unnecessary use of] eval. Nonetheless, I have run into
cases where only the name of a variable is known, and in the absence
of an available reference, have taken the reasonable course and
eval'ed in order to assign/retrieve a value. If there's a good
alternative, the doh'lt is yet to discover it.)

../rh
 
D

Douglas Crockford

(By the way, I fully concur with the attempt to stamp out the evil of
[completely unnecessary use of] eval. Nonetheless, I have run into
cases where only the name of a variable is known, and in the absence
of an available reference, have taken the reasonable course and
eval'ed in order to assign/retrieve a value. If there's a good
alternative, the doh'lt is yet to discover it.)

var global = this; // This is more portable than relying on 'window'.
....
var variable_name = "foo";
var value = global[variable_name];

http://www.crockford.com/javascript/remedial.html
 
L

Lasse Reichstein Nielsen

Or, at the risk of offending those who so far only moderately despise
"with", and highly despise "eval",

That would be me :)
you could alternatively re-manifest the return object properties
into caller variables by:

for (var j in retObj) eval(j +"=retObj['"+j+"']");

This differs from using "with" in two ways:

- You only get the values of the enumerable properties of retObj.
Using "with" makes all the properties visible. That is not so much of
a difference, since the non-enumerable properties of a new object (the
ones in Object.prototype) are already visible as properties of the
global object.

- It assigns the values to local variables if they exist, but those
properties that don't have a local variable of the same name are
created as global variables. With a "with", they are all made local
variables, but will shadow preexisting local variables of the same
name.

This is actually a use for eval that I can't find a way around:
setting the value of a local variable given its name as a string.
It is also bad coding practice. Local variables should be free to
be renamed without changing the how the program works, but this
code will let a function from anywhere in the program change a local
variable by name. I recommend against it.

I would recommend returning an array and have the caller decide which
variables to assign to, or returning an object, and letting the caller
decide how to access the properties.
which might come a little closer to call by name than the use of
"with".

Maybe a little closer, but it is not call-by-name. It is
call-by-copy-restore, but I think that is the best we can get anyway.
That's in the vein of a somewhat neutral observation, as
opposed to a recommendation, however.
:)

(By the way, I fully concur with the attempt to stamp out the evil of
[completely unnecessary use of] eval. Nonetheless, I have run into
cases where only the name of a variable is known, and in the absence
of an available reference, have taken the reasonable course and
eval'ed in order to assign/retrieve a value. If there's a good
alternative, the doh'lt is yet to discover it.)

If the variable is a local variable, then I can't see another way,
since we don't have a reference to the activation object. I highly
recommend not to throw around the names of local variables, though.
Make the global if someone outside of the scope needs to have access
to them.

/L
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
news:comp.lang.javascript said:
(e-mail address removed) (asdf asdf) writes:

If you want to emulate call-by-name (the "var" parameter of Pascal or
&-parameter of C++), you can pass a return-object, and set the values
as propertie of it, instead of creating the object in the called
function. It is the closest to a Pascal "var"-parameter that I can
find.

I miss the tuples and simultaneous assignments of languages like SML
and Perl. There is no equivalent in Javascript. The closest would be
a returning an object and using a "with" statement.

Those do not, AFAICS, have the property that the names of the output
items are visible in the calling statement, which is a pity at least to
one of my habits.

Also there is not the de-coupling between internal and external names,
as there is in function Neg(x) { return -x } ... z = Neg(y) .

So ISTM that either I force the parameters to be Objects, gaining
visibility; or, since this is all about a date, make the outputs
parameters of a Date Object, albeit one that does not really mean the
time_t of its valueOf().

Thanks to all.
 
R

rh

Lasse Reichstein Nielsen said:
That would be me :)

And me :)
you could alternatively re-manifest the return object properties
into caller variables by:

for (var j in retObj) eval(j +"=retObj['"+j+"']");

This differs from using "with" in two ways:

- You only get the values of the enumerable properties of retObj.
...

While that may be a difference in the use of "with", my assumption was
that retObj would be generated as an object literal as the return
expression in the called function. As such, there wouldn't be any
non-enumerable properties.
- It assigns the values to local variables if they exist, but those
properties that don't have a local variable of the same name are
created as global variables. With a "with", they are all made local
variables, but will shadow preexisting local variables of the same
name.

See below regarding restriction.
This is actually a use for eval that I can't find a way around:
setting the value of a local variable given its name as a string.

Thanks for confirming.
It is also bad coding practice. Local variables should be free to
be renamed without changing the how the program works, but this
code will let a function from anywhere in the program change a local
variable by name. I recommend against it.

The eval is in the calling function, so the only functions that could
change local variables within are those where there is an explicit
intention to allow it. It would be trivial to restrict the variables
in the caller that would be open to change by the callee (by evaling
on the restricted set, as opposed to the property names provided by
retObj). If you don't want to trust, you don't have to.
I would recommend returning an array and have the caller decide which
variables to assign to, or returning an object, and letting the caller
decide how to access the properties.

I tend to use an array if there are two or three return values. More
than that, I create an object literal and access the properties.
Maybe a little closer, but it is not call-by-name. It is
call-by-copy-restore, but I think that is the best we can get anyway.


:)

If the variable is a local variable, then I can't see another way,
since we don't have a reference to the activation object. I highly
recommend not to throw around the names of local variables, though.
Make the global if someone outside of the scope needs to have access
to them.

As pointed out above, you don't really have to "throw around the
names". I hold a similar aversion to putting things into the global
namespace -- seems to me there's already too much potential for name
conflict and side-effects there.

Just trying to hold your feet to the fire a bit here. ;)

../rh
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top