=head1 TITLE Subroutines: Replace C with a generic C function =head1 VERSION Maintainer: Damian Conway Date: 6 Aug 2000 Last Modified: 18 Sep 2000 Mailing List: perl6-language@perl.org Number: 21 Version: 2 Status: Frozen =head1 ABSTRACT This RFC proposes extending the number of detectable calling contexts and replacing the limited (and misnamed) context detection of C with a more precise and general mechanism. =head1 DESCRIPTION C> C C returns a value or list of values indicating the calling context of the current subroutine (i.e. the subroutine in which C is called). C may also be passed a list of values that describe aspects of the context in which the current subroutine has been called. In that case, its return value also indicates whether the specified contexts are currently valid. When C is called without arguments in a scalar context: $primary_context = want; it returns a string indicating the (primary) context in which the current subroutine was called: one of "VOID", "SCALAR", or "LIST. When C is called without arguments in a list context: ($primary, $count, @secondary) = want; it returns a list of at least two values, indicating the contexts in which the current subroutine was called. The first two values in the list are the primary context (i.e the scalar return value) and the expectation count (see L below). Any extra contexts that C may detect (see L below) are appended to these two items. When C is called without arguments in a hashref context (see L below): if (want->{LVALUE}) { ... } unless (want->{COUNT} < 2) { ... } it returns a reference to a hash whose keys are the valid contexts plus the special key "COUNT". The values for the context keys are always 1; the value for the "COUNT" key is always the expectation count. When C is called with arguments in a scalar context: $primary_context = want 'LIST', 2, 'LVALUE'; it checks whether all the specified contexts are valid for the current subroutine. If any is not currently valid, C returns C. Otherwise it returns the primary context string (just as scalar C with no arguments does). When C is called with arguments in a list context: ($primary, $count, @secondary) = want 'SCALAR', 'RVALUE', 'HASHREF'; it again checks whether all the specified contexts are valid for the current subroutine. If any is not currently valid, C returns an empty list. Otherwise it returns the same list of context values as it would have if called without arguments. To summarize these five alternatives: =over 4 =item * If C is itself called in a scalar context, it returns only the primary context string. =item * If C is itself called in a list context, it returns all known context information via a list. =item * If C is itself called in a hashref context, it returns all known context information via a reference to a hash. =item * If C is called with arguments, the contexts specified by those arguments must be valid for the current subroutine, or else C returns false (either C or C<()>). =back =head2 Expectation counts The second value returned by C in a list context is the current subroutine's "expectation count". This is an integer indicating the number of return values expected by the subroutine's caller. For void contexts, the expectation count is always zero; for scalar contexts, it is always zero or one; for array contexts it may be any non-negative number. If the context is expecting an unspecified number of return values (typically because the result is being assigned to an array variable), the expectation count is the largest representable integer (C<~0>). When C is called with a numeric value as an argument, it returns true only if the current subroutine's calling context requires at least that many values. For example: if (want 2) { return ($x, $y) } # context wants >= 2 values else { return ($x); } # context wants < 2 values =head2 Valid contexts The various contexts that may be specified as arguments to C and may be returned by it (as list values or hashref keys) are: =over 8 =item 'LIST' The subroutine was called in a list context: @vals = func(); print func(); =item 'SCALAR' The subroutine was called in a scalar context: $val = func(); print scalar func(); =item 'VOID' The subroutine was called in a void context: func(); =item 'COUNT' Only returned as a literal string when used as a hashref key. Normally passed to C -- and returned by it -- as an integer. func(); # COUNT == 0 scalar func(); # COUNT == 0 () = func(); # COUNT == 0 $x = func(); # COUNT == 1 if (func()) { ... } # COUNT == 1 ($x) = func(); # COUNT == 1 ($x, $y) = func(); # COUNT == 2 ($x, $y, $z) = func(); # COUNT == 3 @a = func(); # COUNT == ~0 ($x,@a) = func(); # COUNT == ~0 =item 'HASH' The subroutine was called in a context where its return value is assigned to a hash: %hash = func(); =item 'STRING' The subroutine was called in a stringifying context: $val = $hash{func()}; print func(); =item 'NUMBER' The subroutine was called in a numerifying context: $val = func() * 2; $val = sin(func()); $val = $array[func()]; =item 'INTEGER' The subroutine was called in a numerifying context that requires an integer: $val = $array[func()]; $val = "str" x func(); =item 'BOOLEAN' The subroutine was called in a boolean context: if ( func() ) {} $val = func() || 0; =item 'SCALARREF' The subroutine was called in a context that expects a scalar reference: $val = ${func()}; \$val = func(); # possible typeglob replacement? =item 'ARRAYREF' The subroutine was called in a context that requires an array reference be returned: func()->[$index]; push @{func()}, $val; \@array = func(); # possible typeglob replacement? =item 'HASHREF' The subroutine was called in a context that requires a hash reference be returned: func()->{key}; @keys = keys %{func()}; \%hash = func(); # possible typeglob replacement? =item 'OBJREF' The subroutine was called in a context that requires an object reference be returned: func()->method(); =item 'CODEREF' The subroutine was called in a context that requires a code reference be returned: func()->(); &{func()}(); \&hash = func(); # possible typeglob replacement =item 'IOREF' The subroutine was called in a context that requires a filehandle reference be returned: print {func()} @data; =item 'LVALUE' The subroutine call is being used as an lvalue: func() = 0; =item 'RVALUE' The subroutine call is being used as an rvalue: $val = func(); @vals = func(); =item I The subroutine was called in a context that expects to see an object of the named class returned: my Dog $spot = func(); # want('Dog') returns true =back =head2 Example our ($data, @data) ; sub lastdata : lvalue { if ($DEBUG) { my ($primary, $expcnt, @secondaries) = want; print "lastdata called in $primary context\n; print "Also in contexts: @secondaries\n"; print "expected $expcnt return values\n"; } return if want->{VOID}; return $data if want qw(LVALUE SCALAR); return "$data" if want 'SCALAR', 'STRING return eval{$data+0}||0 if want 'SCALAR', 'NUMBER'; return !!$data if want 'SCALAR', 'BOOLEAN'; if ((undef,$count) = want 'LIST') { return @data if $count > @data; return @data[0..$count-1]; } } =head2 Listing of possible context combinations: within &func, &want returns: when: ============================ ===== (VOID, 0, RVALUE) ;func(); (SCALAR, 1, LVALUE) func() = $x; (SCALAR, 0, RVALUE) ; scalar func(); (SCALAR, 1, RVALUE) $x = func(); (SCALAR, 1, RVALUE, STRING ) $x .= func(); (SCALAR, 1, RVALUE, BOOLEAN) die if func(); (SCALAR, 1, RVALUE, NUMBER ) $x + func(); (SCALAR, 1, RVALUE, NUMBER, INTEGER) ~func(); $array[func()]; (SCALAR, 1, RVALUE, SCALARREF) ${func()}; (SCALAR, 1, RVALUE, ARRAYREF) func()->[$index]; (SCALAR, 1, RVALUE, HASHREF) func()->{key}; (SCALAR, 1, RVALUE, CODEREF) func()->(@args); (SCALAR, 1, RVALUE, OBJREF) func()->method(); (SCALAR, 1, RVALUE, IOREF) print {func()} @data; (SCALAR, 1, RVALUE, Dog) my Dog $spot = func(); (LIST, 0, RVALUE) () = func(); (LIST, 1, RVALUE) ($x) = func(); (LIST, ~0, RVALUE) ($x, @array) = func(); (LIST, ~0, RVALUE) @array = func(); (LIST, ~0, RVALUE) print func(); (LIST, ~0, RVALUE, HASH) %hash = func(); =head1 IMPLEMENTATION Dammit, Jim, I'm a doctor, not an engineer! =head1 REFERENCES perlfunc (C) RFC 259: Builtins : Make use of hashref context for garrulous builtins