Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: Re: What should be returned in scalar context?

by hardburn (Abbot)
on Dec 02, 2003 at 20:24 UTC ( [id://311731]=note: print w/replies, xml ) Need Help??


in reply to Re: What should be returned in scalar context?
in thread What should be returned in scalar context?

The subdivision of scalar context into string and numeric. And the numeric context subdivided into integer and real.

That might be easy in these cases:

if( $foo == bar($baz) ) { . . . } if( $foo eq bar($baz) ) { . . . }

But how could you handle the simple case of assigning the return value to a variable? I suppose the current type of the SV could be used if it already had data in it, but what about variables that were just declared?

List context should be subdivided into list, array and hash context.

I know the differences between list and array context are very subtle, but I'm not sure that there is any use for distinguishing the two here.

----
I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer

: () { :|:& };:

Note: All code is untested, unless otherwise stated

Replies are listed 'Best First'.
Re: Re: Re: What should be returned in scalar context?
by BrowserUk (Patriarch) on Dec 02, 2003 at 21:54 UTC
    But how could you handle the simple case of assigning the return value to a variable?

    The keyword was "subdivision". When the context cannot be broken down to a string or numeric context as in the case of assignment to a variable, then the context would be returned as simply 'SCALAR'. If the context can be further broken down, then that context would also be indicated. I haven't thought through how this would be done, but one way might be to return 'SCALAR/STRING' and 'SCALAR/NUMERIC' respectively in the case of your two if statements. Instead of coding if( want() eq 'SCALAR' ) {

    You would code if( want() =~ /^SCALAR/ ) { if you were only interested in determining scalar context. Integer and real contexts could be a supplement to that.

    Alternatively, use a parameter to want() if( want( 'SCALAR' ) ) { would return true if the context was scalar string, scalar numeric, scalar numeric real or scalar numeric integer, but if( want( 'INTEGER' ) ) { would only return true if the return was being used in an inherently integer context like an array indices, range boundary or as an argument to a function that had been indicated as an integer (using the much improved prototyping facility:).

    The main reason I thought of for wanting to distinguish between a list context and an array context, is the following

    sub dostuff { my @array; # doing stuff building @array return @array; } ... my @returned = dostuff();

    In the above scenario, we have a lexically local @array built up within the sub. When it comes time to return this to the caller, the array is flattened to a list, which currently appears to consume some extra memory over the array itself. On the basis of experiment, this appears to be less than the full size of the array, but is still a fairly substantial chunk of memory if the array is large. This list is then assigned to the array in the outer code consuming another large chunk of ram.

    Crude measurements indicate that the total memory allocated by the simple act of returning an array through a list to another array is close to 3 times the original size of the array. For small arrays, not a problem, but for large ones this is expensive.

    Yes, you can return a reference to the array, but the extra level of indirection involved can be a PITA, especially if the elements of the array are themselves compound structures.

    My thinking is that if the programmer could determine that the destination is an array, then he might also be given access to an alias to that destination array and assign his return values directly to it.

    sub DoSomething { my @array; alias( @array ) if want( 'ARRAY' ); #Do Stuff Directly to the destination array return; } ... my @returned = DoSomething();

    This would effectively use the same mechanism as for loops do now.

    If the results of the sub were being used in a list context, being pushed onto an array or printed in the calling code and the algorithm of the sub permits, then it can sometimes make sense not to acumulate the data into an array internally, but rather simple build and return a list.

    sub DoStuff { die 'Nothing to do in a void context' if want( 'VOID' ); if( want( 'LIST' ) ) { return map{ # Do stuff to generate the list } ...; } my @array; alias( @array ) if want( 'ARRAY' ); push @array, $stuff for ....; return \@array if want( 'ARRAY/REF' ); # The callers array has been filled directly # If we were called in an array context. return; }

    LW and TheDamian are probably way ahead of me on this, and it is possible that some of the benefits of this type of optimisation can be achieved transparently by comterpreter, but I think that there are cases were it would be useful for the programmer to have this level of control.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!
    Wanted!

      I haven't thought through how this would be done, but one way might be to return 'SCALAR/STRING' and 'SCALAR/NUMERIC' respectively in the case of your two if statements.

      Sounds like a good use of junctions:

      if( want() eq all( 'SCALAR', 'STRING' ) ) { . . . }

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

        That has possibilities, though I think I would prefer to pass the junction in to want() and have it return a boolean in the boolean context than have it pass back a junction and then compare that junction against another?

        Of course, once we get the select/when construct, it probably makes more sense and will be more efficient to not pass the parameter to want(), and have it return the junction to the select and code the variations as when clauses.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Hooray!
        Wanted!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://311731]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (6)
As of 2024-03-29 10:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found