<?xml version="1.0" encoding="windows-1252"?>
<node id="955070" title="Context propagation into subs and evals" created="2012-02-20 08:23:43" updated="2012-02-20 08:23:43">
<type id="115">
perlquestion</type>
<author id="708738">
LanX</author>
<data>
<field name="doctext">
Hi&lt;P&gt;

We had a confused discussion at last Darmstadt Perlmongers meeting, about how the callers context of a sub effects the context within the sub. &lt;P&gt;

Side question was how to reliably force void-context.&lt;P&gt;


Though the perldocs of [doc://return] could be clearer, I came up with basic rules I wanna share and discuss here:&lt;P&gt;

1. Only &lt;B&gt;returned&lt;/B&gt; statements/lines have the callers context.
&lt;P&gt;
2. All other lines are per &lt;b&gt;default in void&lt;/b&gt; context.
&lt;P&gt;
3. &lt;b&gt;Implicitly returned&lt;/b&gt; statements - i.e. final but without [doc://return] keyword - are like in case 1 also in callers context.&lt;P&gt;

The last point can be sometimes confusing, because with nested control flow it's not always instantly clear where a sub possibly drops out.&lt;P&gt;

Please see the following testcode and output for deeper understanding and as a base for your own tests.
&lt;p&gt;
Questions, discussions and modifications are welcome.&lt;P&gt;

&lt;readmore&gt;
&lt;c&gt;
# --------------------
#  force context
# --------------------
sub VOID (&amp;) {
  print "VOID:\t";
  $_[0]-&gt;();
  return;
}

sub LIST (&amp;) {
  print "LIST:\t";
  () = $_[0]-&gt;();
  return;
}

sub SCALAR (&amp;) {
  print "SCALAR:\t";
  scalar $_[0]-&gt;();
  return;
}

# --------------------
# tests
# --------------------

sub tst_context {
   unless (defined wantarray) {
      print "is void\n";
   } elsif (wantarray) {
      print "is list\n";
   } else {
      print "is scalar\n";
   }
}

SCALAR { tst_context() };

LIST { tst_context() };

VOID { tst_context() };


# --------------------
# implicit_returns
# --------------------

sub implicit_returns {
  print "implicit_returns(@_)\t";
  if ($_[0]) {
    tst_context()	              # caller's context
  } else {
    tst_context()		      # caller's context
  }
}


SCALAR { implicit_returns(1) };
SCALAR { implicit_returns(0) };

LIST { implicit_returns(1) };
LIST { implicit_returns(0) };

VOID { implicit_returns(1) };
VOID { implicit_returns(0) };


# --------------------
# no_implicit_returns 
# --------------------

sub no_implicit_returns {
  print "no_implicit_returns(@_)\t";
  if ($_[0]) {
    tst_context()		      # void context
  } else {
    tst_context()		      # void context
  }
  return;                             # last execution!
}


SCALAR { no_implicit_returns(1) };
SCALAR { no_implicit_returns(0) };

LIST { no_implicit_returns(1) };
LIST { no_implicit_returns(0) };

VOID { no_implicit_returns(1) };
VOID { no_implicit_returns(0) };
&lt;/c&gt;
&lt;/readmore&gt;&lt;P&gt;

Output:
&lt;c&gt;
SCALAR:	is scalar
LIST:	is list
VOID:	is void
SCALAR:	implicit_returns(1)	is scalar
SCALAR:	implicit_returns(0)	is scalar
LIST:	implicit_returns(1)	is list
LIST:	implicit_returns(0)	is list
VOID:	implicit_returns(1)	is void
VOID:	implicit_returns(0)	is void
SCALAR:	no_implicit_returns(1)	is void
SCALAR:	no_implicit_returns(0)	is void
LIST:	no_implicit_returns(1)	is void
LIST:	no_implicit_returns(0)	is void
VOID:	no_implicit_returns(1)	is void
VOID:	no_implicit_returns(0)	is void
&lt;/c&gt;&lt;P&gt;

UPDATE:

same rules apply to evals:

&lt;c&gt;
# --------------------
# eval
# --------------------
 
LIST { eval "print 'eval '; return tst_context(); 'never executed'" };

#-&gt; LIST:	eval is list
&lt;/c&gt;



&lt;!-- Node text goes above. Div tags should contain sig only --&gt;
&lt;div class="pmsig"&gt;&lt;div class="pmsig-708738"&gt;
&lt;p&gt;Cheers Rolf
&lt;/div&gt;&lt;/div&gt;</field>
</data>
</node>
