Re: Re: Re: Return in function
- To: mathgroup at smc.vnet.net
- Subject: [mg106107] Re: [mg106045] Re: [mg106018] Re: Return in function
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Fri, 1 Jan 2010 05:38:06 -0500 (EST)
- References: <hftbe9$cjh$1@smc.vnet.net> <200912300915.EAA17319@smc.vnet.net>
Hi Bobby, On Thu, Dec 31, 2009 at 10:26 AM, DrMajorBob <btreat1 at austin.rr.com> wrote: > Explanations hidden in technical reports do not count as documentation, and > neither do private communications between experts. (For the same reason.) > > If the behavior of Return is not a bug, it should be documented where users > are likely to see it when looking up "Return" in Help. > Agreed. You have a point, and I also think that the documentation for Return is inadequate. That said, most if not all of people participated in the discussion in this thread are advanced Mathematica users, to say the least. And although I don't know the exact circumstances and context in which the OP (Daniel) encountered this problem, I have no doubt that he could and did find a workaround even before posting the question. I think that we all ask questions like this not because we are totally stuck and see no way out, but in order to understand the system better, including its darker corners. For a system as large and complex as Mathematica, I think it is unavoidable to have a large number of such pitfalls, especially because the system is evolving. Now, there are two ways of answering this sort of questions: one is to rightly blame the documentation (which generally is by far not the worst among those for the software I use) , and another is to give some perhaps not hundred percent authoritative or "official" but reasonable explanations. I find the latter more constructive, given that it is the latter that most people with sufficient Mathematica background seem to be interested in. > The explanation below seems to be "retrospective cataloging of observed > behavior", not "designed behavior". I disagree. I think it is the designed behavior. And the fact that it has been documented (albeit in a technical report) as early as in 1992, I think speaks in favor of my guess. The problem is that the semantics of function calls is emulated in Mathematica by the rule substitution. OTOH, for the consistency of the system, Return must obey the standard mechanics of evaluation process, as any other head. Since the decision do discard Return is comming from the "external" to Return context, you can not just define built-in DownValues for Return. Moreover, since Return performs a non-local jump, you can not universally define UpValues for Return either. What are your choices then? Here is my guess. Making Return work in a block of code is not difficult - all you have to do is to define an extra rule for CompoundExpression, which will make it ignore its arguments standing after Return. In this way you avoid the complexities and overhead of checking for Return in each of the many kinds of scoping constructs. By not discarding Return at this stage you make it possible to nest (break out of nested CompoundExpression-s): In[1]:= (c; d; (a; b; Return[e]); f) Out[1]= Return[e] But this means that Return must be an idle head. Who will then be responsible for discarding Return at the end? Not Return itself, and not the scoping constructs which presumably know nothing about Return. It may be that a universal solution to this problem does not exist or is very hard to find/prove correct. The design decision concerning Return seems to have been made such in order for a user of Return to see no difference from the action of Return in other languages, *in most sensible cases*. Since the overwhelming majority of uses of Return are inside some user-defined functions (rules), a single simple rule of discarding Return generated through application of user-defined rules covers all such cases. This seems to be one of the cases where generality has been traded for simplicity, and in this particular case this looks like a very reasonable solution to me.I wonder how many beginners or even intermediate Mathematica users ever stumbled upon anything like Daniel's original example - I think very few. > > > This seems to explain the behavior of Return in all cases (at least in my >> experience). >> > > Exactly. Your next experience may be different, and you'd simply add it to > the list. > True. But notice that the list is quite short, and it summarizes experiences of several people, not just me. And somehow in the case of Return I doubt that it will grow significantly, if at all. Regards, Leonid > > Bobby > > > On Thu, 31 Dec 2009 02:15:35 -0600, Leonid Shifrin <lshifr at gmail.com> > wrote: > > Norbert, >> >> Had you followed the development of this thread and you would have noticed >> my post where I argued that this is *not* a bug, although indeed a rather >> unintuitive feature. The main authoritative source of information on this >> matter (apart from the standard documentation) seems to be the technical >> report by David Withoff named "Mathematica internals", of 1992. After >> making >> my post I was additionally informed by Fred Simons that the behavior of >> Return has been very nicely summarized by Allan Hayes back in 2002. I >> think >> this may be of general interest so I repeat it here: >> >> If Return[x] is generated as a value in Do or Scan then x is immediately >> returned; >> If Return[x] is generated as an entry in CompoundExpression or as a value >> of >> the body of a While or For loop then Return[x] (not x) is immediately >> returned; >> If Return[x] is generated as the value of a user-defined function then the >> function returns x (not Return[x]) >> Otherwise Return[x] behaves as a ordinary expression. >> >> This seems to explain the behavior of Return in all cases (at least in my >> experience). >> >> Regards, >> Leonid >> >> >> >> On Wed, Dec 30, 2009 at 12:15 PM, Norbert P. <bertapozar at gmail.com> >> wrote: >> >> On Dec 11, 3:46 am, dh <d... at metrohm.com> wrote: >>> > Version 7.0.1 >>> > >>> > Hello, >>> > >>> > I am not sure if this is a feature or a bug. If you use Return in an >>> > >>> > anonymous function, not only the return value is returned, but also >>> > >>> > "Return" itself. Consider: >>> > >>> > (If[# == 2, Return[a]; #, #]) & /@ {1, 2, 3} >>> > >>> > this gives: >>> > >>> > {1, Return[a], 3} >>> > >>> > The same thing happens with: >>> > >>> > Function[x, If[x == 2, Return[a]; x, x]] /@ {1, 2, 3} >>> > >>> > However, the following works as expected: >>> > >>> > f[x_] := (If[x == 2, Return[a]; x, x]); >>> > >>> > f /@ {1, 2, 3} >>> > >>> > Daniel >>> >>> Even though I think that it's a bad habit to use Return, it might be >>> useful at times. And since it's been in Mathematica since the version >>> 1, it should've been fixed a long time ago. >>> >>> To make the code even simpler, try (version 6.0.2): >>> >>> In[1]:= f[]:=(Return[a];1); >>> >>> In[2]:= f[] >>> Out[2]= a >>> >>> It works as expected. Now try >>> >>> In[3]:= (Return[a];1)&[] >>> Out[3]= Return[a] >>> >>> This is obviously a bug. One would expect to see "a" if Return worked >>> properly, or "1" if Return didn't work inside Function, but only in >>> definitions such as f[]:=... above. >>> >>> I get a similar result using RuleDelayed as in >>> >>> In[4]:= 2/. 2:>(Return[a];1) >>> Out[4]= Return[a] >>> >>> The documentation is also contradictory. In the description of Return, >>> there's an example that shows that Return exists only the innermost >>> loop (construct) such as Do. Much like Break[], why isn't there Break >>> [expr] instead? But in tutorial/LoopsAndControlStructures they say: >>> Return[expr] return the value expr, exiting all procedures and loops >>> in a function >>> >>> Best, >>> Norbert >>> >>> >>> >> >> > > -- > DrMajorBob at yahoo.com >