Front page | perl.perl6.language |
Postings from March 2005
Re: return of copies vs references
Thread Previous
|
Thread Next
From:
Luke Palmer
Date:
March 17, 2005 01:04
Subject:
Re: return of copies vs references
Message ID:
20050317090645.GA20605@navi.cx
Larry Wall writes:
> Perl 5 always makes a copy of return values, but that just turns
> out to not matter for references, since a copy of a reference is as
> good as the original reference. Perl 5 also propagates scalar/list
> context into subs. For $:foo it doesn't matter--it always behaves
> as a scalar value even in list context. In list context, @:bar and
> %:baz should probably return copies of their values much like they
> do in Perl 5, (or more likely, some kind of lazy COW reference that
> can lazily interpolate into the surrounding lazy list context).
> Whether $self.:bar and $self.:baz should behave the same is an
> interesting question. They *look* scalar, so maybe they should imply
> reference return, and you'd have to say
>
> return $self.:bar[];
> return $self.:baz{};
I'll just point out, the rest of this message, with all the autocopy
complexity (according to /some/ people), uses this assumption. It all
happily goes away if $self.:bar returns a list if @:bar is declared.
And I can't, off hand, see any other problems with it. Maybe I'm just
blind, though.
Luke
> to get the equivalent of
>
> return @:bar;
> return %:baz;
>
> But bare
>
> return $self.:bar;
> return $self.:baz;
>
> would be equivalent to:
>
> return \@:bar;
> return \%:baz;
>
> But I could argue it the other way too.
>
> : For each, will the calling code be able to
> : modify $obj's attributes by modifying the return values, or not?
>
> The caller can modify the value only if an explicit ref is returned (or
> the accessor is marked "rw").
>
> Where we seem to differ from Perl 5 is that in scalar context, a bare
> array or hash automatically enreferences itself rather than returning
> some kind of size. So in scalar context, it would seem that
>
> return @:bar;
> return %:baz;
>
> and
>
> return $self.:bar;
> return $self.:baz;
>
> are equivalent to:
>
> return \@:bar;
> return \%:baz;
>
> (Again, $:foo is never a problem unless it's already a reference.)
>
> So the issue is whether this interpretation will encourage people to accidentally
> return references to things they didn't want to give write access to. On the
> other hand, making the private methods context sensitive doesn't actually
> seem to fix this particular problem, but just pushes it down one level into
> the implicit accessor. Maybe we need to work something up where
> references returned from read-only accessors are always COW references.
> If we assume that [...] is lazy when it can be, then that would be saying that
> scalar context forces
>
> return @:bar;
>
> to mean
>
> return [@:bar];
>
> and you'd have to write an explicit
>
> return \@:bar;
>
> to get around that. But that seems kind of hacky and special-casey.
>
> On the other hand, there are going to be strong cultural forces
> discouraging people from writing such accessors in the first place,
> so maybe we just go ahead and let people return hard refs in scalar
> context on the assumption they know what they're doing. I suspect
> that most actual accessors to arrays and hashes will just look like
> ordinary getter and setter methods with extra args for subscripts, or
> will return an explicit proxy if they want to behave like an lvalue.
> And in either of those cases, you don't try to return the entire
> array or hash. So maybe we should settle for the clean but slightly
> dangerous semantics here.
>
> Except that we've defined default read-only accessors that would,
> under the "clean" rules, give people automatic access to arrays and
> hashes if called in scalar context. So I think we really only have
> three options here for the public accessors:
>
> Don't generate autogenerate accessors at all for arrays and hashes.
> Generate array and hash accessors that refuse to work in scalar context.
> Generate array and hash accessors that autocopy in scalar context.
>
> Of those three, the last seems the most friendly.
>
> : Going further, what is the exact syntax for each type of attribute to
> : specify whether a copy or a reference is returned?
> :
> : In Perl 5, with the latter two, the difference was a "return $bar" vs
> : "return [@{$bar}]" for reference vs copy. I would like that Perl 6
> : is also at least as clearly disambiguated.
>
> If we go "dwimmy" rather than "clean", and assume private array and
> hash accessors always return refs, then these return refs from public
> accessors:
>
> return \$self.:foo; # in any context
> return $self.:bar; # in any context
> return $self.:baz; # in any context
> return \$:foo; # in any context
> return \@:bar; # in any context
> return \%:baz; # in any context
>
> and these return copies:
>
> return $self.:foo # in any context
> return $self.:bar[]; # in list context
> return $self.:baz{}; # in list context
> return $:foo; # in any context
> return @:bar; # in any context
> return %:baz; # in any context
>
> That's actually simpler than the tables I made up when I was believin in
> the "clean" solution. What it essentially boils down to is that return
> from a public accessor always forces list context on its arguments even
> if the accessor was called in scalar context (in which case a ref to
> a COW list is stored in the scalar).
>
> I'm wondering if we should just up and say that "return" always forces list
> context on its arguments. It would simplify some things, and complicate others...
>
> : Note that specifying this in the attribute definition isn't
> : appropriate, since an attribute could just as easily be an array of
> : arrays, or hash of hashes, and I am returning an inner array or hash
> : that I either do or don't want to be modifiable by calling code.
>
> Yes, even with the return context hack, it'd only go one level down.
> I think at some point we have to rely on people not to write stupid
> accessors, and rely on culture to enforce that. I really, really
> want to avoid falling into C++ const hell.
>
> Maybe we can define some kind of deepcow operator for the nested cases.
> Or maybe there's some other solution I don't see yet, or that someone has
> already told me about and I've forgotten...
>
> : Separate question, just to confirm, I assume that plain '=' always does a
> : copy?
>
> Yes. And with := it's mandatory for "is copy" parameters, optional
> for "is constant" parameters, and prohibited for "is rw" parameters.
>
> Hopefully if values come back COW from a routine, we can avoid a
> duplicate copy on the assignment.
>
> : Thank you for any clarification.
>
> Well, I don't know if I clarified it that much, but you're welcome
> to the mud too. :-)
>
> Larry
>
Thread Previous
|
Thread Next