develooper 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


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About