in reply to Re: Contexts and Perl 6
in thread Contexts and Perl 6

I think I see what you're hinting at in the reference post.

Instead of stuffing the object with the various values for all contexts, the function just puts code in for each possible context, and only executes the one actually picked on.

So the list-cardinality thing would return a lazy list that plugs back into the real code, and pre-populate the count. The function called doesn't contain the "real" code.

I like that as it ties in with the lazy list concepts. Easy to do, using current specs (I think):

sub arduous ($param -->@) { return @() ... { return reticent($param) } }
That is, with an empty list on the left, it should use the iterator for all elements. In this case, it's not an iterator but the real function that generates all the elements (it might itself be implemented to return a lazy list). Cute syntax, but this doesn't pre-set the length. We should have an easy way of writing functions that do that: a function appears to return the list, but really just sets up a lazy list.

sub arduous ($param -->@) { my ArduousIterator $it .= new($param); return $it; }
Here, since ArduousIterator is derived from a friendly iterator creator class that does whatever the name of the standard iterator role is, it supports .lines which returns all the items, but can be lazy. And it has the @ contextualizer, which calls .lines. Since the function is defined to return a list, that is called automatically without worrying about what my caller is doing with it.

The ArduousIterator.new function would set up the length (or at least provide for it if anyone ever wants to know) and a function to generate elements.

I like that. It handles the opposite case, where the length is difficult to compute and ends up just getting all the elements anyway. There, you are better off not asking for the length and just waiting for the end of the list to happen.

If the construct that made the return list was itself a lazy list maker, such as map, you don't have to be so explicit about it. Once you introduce lazyness at the bottom layer, it should take care of itself.

I do think, though, that hiding the different potential faces of the object down at this level reduces the ability to optimize. If you inline the call, for example, it's not at all clear which bits create the face you are interested in.

—John

Replies are listed 'Best First'.
Re^3: Contexts and Perl 6
by moritz (Cardinal) on May 18, 2009 at 20:56 UTC
    Actually the current spec allows something along these lines:
    sub my_context_sensitive { return $someobject but { method Str { # code for computing the string representation } method list { # code that's called in list context } ... } }

    So the cost of that is just creating a closure for each "overloaded" context.

      So, you go through all the trouble of cloning the closures and creating the one-off "butted" type. Even if inlined or the compiler otherwise does know the context, it still can't easily figure out that whole methods can be removed.

      If the function knew it was called in numeric context, it could return Array but compute_length();. If optimized over, the property contains no closures, so is easily cut down to just the desired function call.

        Even if inlined or the compiler otherwise does know the context, it still can't easily figure out that whole methods can be removed.
        Why not?