Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

# Re: something nice I found today, return multiple values from a function

255 views

### Nasser M. Abbasi

Oct 12, 2010, 1:53:27â€¯PM10/12/10
to
On 10/12/2010 3:52 AM, Nasser M. Abbasi wrote:

>
> --------------------
> getPointCoordinates[] := Module[{x,y}, {x -> 10, y -> 7}]
>
> p = getPointCoordinates[];
> x = x /. data;
> y = y /. data;
>
> Print["x=", x]
> Print["y=", y]
>
> x=10
> y=7
> ---------------------
>

Opps, I was in middle of editing and pasted earlier version, here is the
final version:

------------------
getPointCoordinates[x_, y_] := Module[{}, {x -> 10, y -> 7}]

p = getPointCoordinates[x, y];
x = x /. p;
y = y /. p;

Print["x=", x]
Print["y=", y]

x=10
y=7

--------------------

--Nasser

### Nasser M. Abbasi

Oct 12, 2010, 1:53:16â€¯PM10/12/10
to
I just found I can duplicate a struct like in Mathematica very easily.

This can be used to return multiple values from a function. Much better
than just return a list of data items.

This is an example:

--------------------
getPointCoordinates[] := Module[{x,y}, {x -> 10, y -> 7}]

p = getPointCoordinates[];
x = x /. data;
y = y /. data;

Print["x=", x]
Print["y=", y]

x=10
y=7
---------------------

Ok, I know the experts here are saying, what is the big deal, we all
knew that, but I really did not know I could do that until today.

Now I can make my Mathematica code better as before I used to just
return a list of the values, and then I had to be careful I access the
correct ones by the correct position as they were put in the list by the
called function.

I never liked having to do that. The above is so much better.

I keep learning new things about Mathematica every day. Amazing.

--Nasser

### Ingolf Dahl

Oct 13, 2010, 2:40:45â€¯AM10/13/10
to
You might use just

getPointCoordinates[x_, y_] := {x -> 10, y -> 7}

without Module. Module is superfluous without variables. If you need some
parentheses for multiple expressions, you might use ordinary ( )

Best regards

Ingolf Dahl

> -----Original Message-----
> From: Nasser M. Abbasi [mailto:n...@12000.org]
> Sent: den 12 oktober 2010 19:52
> To: math...@smc.vnet.net
> Subject: Re: something nice I found today, return multiple
values from a
> function
>

> On 10/12/2010 3:52 AM, Nasser M. Abbasi wrote:
>
> >

> > --------------------
> > getPointCoordinates[] := Module[{x,y}, {x -> 10, y -> 7}]
> >
> > p = getPointCoordinates[];
> > x = x /. data;
> > y = y /. data;
> >
> > Print["x=", x]
> > Print["y=", y]
> >
> > x=10
> > y=7
> > ---------------------
> >
>

> Opps, I was in middle of editing and pasted earlier version, here is the
> final version:
>
> ------------------
> getPointCoordinates[x_, y_] := Module[{}, {x -> 10, y -> 7}]
>
> p = getPointCoordinates[x, y];
> x = x /. p;
> y = y /. p;
>

> Print["x=", x]
> Print["y=", y]
>
> x=10
> y=7
>
> --------------------
>

> --Nasser

### Albert Retey

Oct 13, 2010, 2:42:00â€¯AM10/13/10
to
Hi,

> Opps, I was in middle of editing and pasted earlier version, here is the
> final version:
>
> ------------------
> getPointCoordinates[x_, y_] := Module[{}, {x -> 10, y -> 7}]
>
> p = getPointCoordinates[x, y];
> x = x /. p;
> y = y /. p;
>
> Print["x=", x]
> Print["y=", y]
>
> x=10
> y=7
>

1) I think it has been mentioned in another post today: Module with an
empty list is just an elaborate noop: You better just say:

getPointCoordinates[x_, y_] := {x -> 10, y -> 7}

2) you also might like this:

makepoint[p_Symbol,xx_,yy_]:=(p[x]=xx;p[y]=yy; p);

makepoint[p,10,7]

p@x
p@y

hth,

albert

### Nasser M. Abbasi

Oct 13, 2010, 11:33:12â€¯PM10/13/10
to
I thought I should also show how this method works when used in Tables.

Given this:

computeSomething[r_] := Module[{var1 = -99, var2 = 20, result},
result["x"] = var1*r;
result["y"] = var2*r;
result
];

And now call it many times:

tbl = Table[computeSomething[30], {i, 5}];

Now to access each result, it will be like this:

tbl[[1]]["x"] ---> in place of the old way: tbl[[1,1]]
tbl[[1]]["y"] ---> in place of the old way: tbl[[1,2]]

tbl[[2]]["x"] ---> in place of the old way: tbl[[2,1]]

or

For[i=1,i<5,i++,Print[tbl[[i]]["x"]]]
-2970
-2970
-2970
-2970

etc...

Should I patent this method? :)

--Nasser

### Nasser M. Abbasi

Oct 13, 2010, 11:33:56â€¯PM10/13/10
to
On 10/12/2010 11:42 PM, Albert Retey wrote:

>>
>
> 1) I think it has been mentioned in another post today: Module with an
> empty list is just an elaborate noop: You better just say:
>
> getPointCoordinates[x_, y_] := {x -> 10, y -> 7}
>

Ok, but I was just using an example to illustrate the main point of how
to package multiple return values neatly.

> 2) you also might like this:
>
>
> makepoint[p_Symbol,xx_,yy_]:=(p[x]=xx;p[y]=yy; p);
>
> makepoint[p,10,7]
>
> p@x
> p@y
>
> hth,
>
> albert
>

Well, after more playing around, I know settled on this 'pattern'.

But before I show it, let me be clear what I am trying to do: Sometimes
I call a Module[] with some input parameters, and it does some
computation, and return back number of results. I used to return the
result in a LIST to the caller. Had to make sure I access the return
values from the list on return in the same order they are put in.

A struct would have solved this. But now I can do this, please let me
know what you think of this new way:

In[11]:= computeSomething[r_] := Module[{var1 = -99, var2 = 20, result},

result["x"] = var1*r; result["y"] = var2*r;
result];

In[12]:= result = computeSomething[30];
x = result["x"]
y = result["y"]
Out[13]= -2970
Out[14]= 600

---- define some module to do some work and return many results

computeSomething[r_] := Module[{var1 = -99, var2 = 20, result},
result["x"] = var1*r;
result["y"] = var2*r;
result]

---- now call it with some data to compute something
result = computeSomething[30];

--- now result is in a struct-like, I can access the
--- result by NAME, which is important

x = result["x"]
y = result["y"]
Out[9]= -2970
Out[10]= 600

---------------------------

Now I think I have what seems like a good struct emulation in
Mathematica. unless I found a problem with this 'pattern', I think I
will start using it.

The above is better than what I used to do which is:

------------------------------

computeSomething[r_] := Module[{var1 = -99, var2 = 20, result},

result = {var1*r, var2*r}
];

result = computeSomething[30];

x = result[[1]]
y = result[[2]]
Out[7]= -2970
Out[8]= 600
-------------------------------------

The difference is that now I do not have to worry about which position
each individual result is at. Instead of result[[1]], I write result["x"]

Thanks all for the input.

--Nasser

### Andreas

Oct 15, 2010, 2:02:56â€¯PM10/15/10
to
Nasser

I've followed this thread for a couple of days and it surprises me
that it hasn't drawn more discussion. I think this approach makes
lots of sense and makes dealing with a wide variety of collections of
data and results much easier to handle.

I have often found myself "tagging" levels or even elements in a
output list to try to emulate the same thing, but your idea works much
better.

I haven't thought this through completely, but do you see this
approach having any drawbacks? Might a struct restrict preclude some
Mapping operations which one could do on a nested list?

I'd like to see this as a package that we could use to define structs
easily across any notebook.

Very interesting idea.

A.

P.S. I've posted this through Google Groups but notice that sometimes
things posted through Google Groups don't seem to appear on the
original Drexel site. Anyone else have the trouble?

### Andreas

Oct 16, 2010, 12:15:28â€¯PM10/16/10
to

### Nasser M. Abbasi

Oct 16, 2010, 1:20:22â€¯PM10/16/10
to
On 10/15/2010 11:02 AM, Andreas wrote:
> Nasser
>
> I've followed this thread for a couple of days and it surprises me
> that it hasn't drawn more discussion. I think this approach makes
> lots of sense and makes dealing with a wide variety of collections of
> data and results much easier to handle.
>
> I have often found myself "tagging" levels or even elements in a
> output list to try to emulate the same thing, but your idea works much
> better.
>

me too.

> I haven't thought this through completely, but do you see this
> approach having any drawbacks? Might a struct restrict preclude some
> Mapping operations which one could do on a nested list?
>

Let give a name to this method. How about tagged list? since when we
write p["x"]=5 we are like tagging it. So, lets say the tagged list
method.

I just been using this tagged lists method just to pass information back
and forth between functions. And for no other purposes. so far, it seems
OK, but I did not try too much to find what problems it can cause.

For example, instead of calling a function with 5 or 6 separate
parameters, I can now call it now with one tagged list, as in:

--------------------------
force[p_] := Module[{}, p["mass"]*p["acc"]]

p["mass"] = 2343.5;
p["acc"] = 25;
force[p]

58587.5
---------------------------

I am not sure how good this method is now, I am just trying things. May
be having all the parameters spelled out in the call is better so one
can see them and do pattern checking on them.

I just sometimes think that having only the 'list' as the main "compound
data structure" to use can make doing some things a little harder in
terms of organizing and managing/packaging complex data in a program.
(oh I forgot, there is a String also).

But at the same time, one can argue that it can also make things
simpler, since one only have the list to worry about. :)

--Nasser

### Leonid Shifrin

Oct 16, 2010, 1:21:05â€¯PM10/16/10
to

Here is my take on this issue. Sometimes structs are really a good option
either because of readability or because of the stateful nature of the
problem. Here is a sort of code which I use to generate structs with certain
properties:

Unprotect[new, delete, get, set, getFields];
ClearAll[new, makeStruct, delete, get, set, structExistsQ,
destroyStruct, getFields];
Protect[new, delete, get, set, getFields];
Module[{structs, structValidQ, getProp, structFieldNames,
releaseInstanceStorage, fieldNameCount},
fieldNameCount[_] = 0;

getProp[x_, prop_, f_: First, Hold[failCode_]] :=
If[# === {},
failCode,
First@#] &@Cases[x, _prop, 1];

structExistsQ[structName_Symbol] :=
ValueQ[structFieldNames[structName]];

destroyStruct::nostr = "The struct with the name `1` does not exist";
destroyStruct[structName_Symbol?structExistsQ] :=
With[{heldStructInstances =
Hold[structs[structName]] /. DownValues[structs],
fieldNames = structFieldNames[structName]},
Map[releaseInstanceStorage[structName], structs[structName]];
Unset @@ heldStructInstances;
structs[structName] =.;
structFieldNames[structName] =.;
structValidQ[structName] =.;
Map[fieldNameCount[#]-- &, fieldNames];
With[{delfields = Select[fieldNames, fieldNameCount[#] == 0 &]},
Unprotect @@ delfields;
ClearAll @@ delfields;
]];

destroyStruct[
structName_Symbol] := (Message[destroyStruct::nostr,
structName]; \$Failed);

makeStruct[structName_Symbol, fieldNames__Symbol] :=
Module[{structInstances, getInstance},
ClearAll[structName];
structName::noprop = "No property with the name `1` found";
"The structure has not been created with the <new> operator and \
is not valid.";
structFieldNames[structName] = {fieldNames};
Select[{fieldNames}, fieldNameCount[#] == 0 &]},
Map[fieldNameCount[#]++ &, {fieldNames}];

structs[structName] = structInstances;
getInstance[instanceRef_] := structInstances[First[instanceRef]];

releaseInstanceStorage[structName][instance_] :=
Cases[instance,
(Alternatives @@ structFieldNames[structName])[y_Symbol] :>
Remove[y]];

structValidQ[structName] :=
Function[instance,
MatchQ[instance, structName[_Symbol]] &&
MatchQ[getInstance[instance],
structName @@ Map[#[_Symbol] &, {fieldNames}]]];

structName /: structName.new[] :=
With[{stateVars = Table[Unique[], {Length[{fieldNames}]}],
objectId = Unique[]},
structInstances[objectId] =
Evaluate[stateVars] = Table[Null, {Length[stateVars]}];
structName[objectId]
];

structName /: structName.getFields[] := {fieldNames};

structName /: structName.getAllInstances[] :=
Apply[structName, DownValues[structInstances][[All, 1]], {2}] /.
Verbatim[HoldPattern][x_] :> x;

structName /: (x_structName /; (structValidQ[structName][x])).set[
property_Symbol, value_] :=
Catch[getProp[getInstance[x], property,
Hold[Message[structName::noprop, property];
Throw[\$Failed]]] /. property[y_] :> (y = value)];

structName /: x_structName.set[property_Symbol, value_] :=

structName /: (x_structName /; (structValidQ[structName][x])).get[
property_Symbol] :=
Catch[First@getProp[getInstance[x], property,
Hold[Message[structName::noprop, property]; Throw[\$Failed]]]];

structName /: x_structName.get[property_Symbol] :=

structName /: (x_structName /; (structValidQ[structName][
x])).delete[] :=
(
releaseInstanceStorage[structName][getInstance[x]];
structInstances[First@x] =.;
);
];
];

This is a minimal API to generate structs from the name of the
struct and names of the fields (symbols). It is significantly more complex
than Nasser's suggestion, but it has a number of advantages, in particular
it does not promote the use of global variables (the state is
encapsulated), and it allows introspection in the style of Java
reflection, which is often a pretty powerful tool. Here are some examples:

In[4]:= makeStruct[rectangle,width,height]

In[5]:= obj = rectangle.new[]

Out[5]= rectangle[\$3]

In[6]:= obj.get[width]

In[7]:= obj.get[widt]

During evaluation of In[7]:= rectangle::noprop: No property with the name
widt found
Out[7]= \$Failed

In[8]:= obj.set[widt,1]

During evaluation of In[8]:= rectangle::noprop: No property with the name
widt found
Out[8]= \$Failed

In[9]:= obj.set[width,1]

Out[9]= 1

In[10]:= obj.get[width]

Out[10]= 1

In[11]:= obj2 = rectangle.new[]

Out[11]= rectangle[\$6]

In[12]:= obj2.set[height,2]

Out[12]= 2

In[13]:= instances = rectangle.getAllInstances[]

Out[13]= {rectangle[\$3],rectangle[\$6]}

In[14]:= #.delete[]&/@instances

Out[14]= {Null,Null}

In[15]:= rectangle.getAllInstances[]

Out[15]= {}

In[16]:= destroyStruct[rectangle]

In[17]:= destroyStruct[rectangle]
During evaluation of In[17]:= destroyStruct::nostr: The struct with the name
rectangle does not exist
Out[17]= \$Failed

In[18]:= makeStruct[rectangle,width,height]

In[19]:= rectangles = Table[rectangle.new[],{5}]

Out[19]=
{rectangle[\$4],rectangle[\$8],rectangle[\$11],rectangle[\$14],rectangle[\$17]}

Out[20]= {1,2,3,4,5}

In[21]:= Map[#.get[width]&,rectangles]

Out[21]= {1,2,3,4,5}

In[22]:= rectangle.getFields[]

Out[22]= {width,height}

In[23]:= destroyStruct[rectangle]

There is some overhead associated with this method. However, if one needs
frequent in-place modifications, this may be more efficient than copying
immutable structures and modifying the copy, which is the standard way
most Mathematica functions work. Some of the expensive type-checks can be
removed to improve speed, if needed.

Regards,
Leonid

On Fri, Oct 15, 2010 at 10:50 AM, Andreas <aa...@ix.netcom.com> wrote:

> Nasser
>
> I've followed this thread for a couple of days and it surprises me
> that it hasn't drawn more discussion. I think this approach makes
> lots of sense and makes dealing with a wide variety of collections of
> data and results much easier to handle.
>
> I have often found myself "tagging" levels or even elements in a
> output list to try to emulate the same thing, but your idea works much
> better.
>

> I haven't thought this through completely, but do you see this
> approach having any drawbacks? Might a struct restrict preclude some
> Mapping operations which one could do on a nested list?
>

0 new messages