Re: Why pass by reference?

2009-06-19 Thread Martin D Kealey

 Matthew Walton wrote:
  If a user of your API contrives to make it change while you're
  running, that's their own foot they've just shot, because they can
  look at the signature and know the semantics of the parameter
  passing being used and know that if they change the value externally
  before you return Bad Things Could Happen.

On Tue, 16 Jun 2009, TSa wrote:
 I agree that the caller is responsible for the constness of the value
 he gives to a function. With this we get the best performance.

At the language level this is wrong. Programmers are BAD at this sort of
thing, unless the compiler *always* has enough to throw a compile-time
error, and even then it's dicey because we may defer compilation.

It seems to me this is pushing something onto the author of the caller
that they shouldn't have to deal with, especially when you consider that
the parameter they're passing into the function may come from somewhere
else, which hasn't been made -- and indeed CAN'T be made -- to promise
not to meddle with the value (note *1).

If the compiler can't spot it, how do you expect a fallible human being
to do so?

If a function requires an invariant parameter then the compiler should
ensure that that guarantee is met, and not rely on the programmer to do
something that is impossibly hard in the general case. A simple way
would be to call $parameter := $parameter.INVARIANT()  (*2) on the
caller's behalf before calling the function.

Conversely, when calling a function where the parameter is declared :rw,
the compiler can call $parameter := $parameter.LVALUE() (*3) on the
caller's behalf first if it needs to convert an immutable object to a
mutable one.  (Or throw up its hands and assert that it's not allowed.)

If we really expect the optimizer to make Perl6 run well on a CPU with
1024 cores (*4), we have to make it easy to write programs that will
allow the optimizer to do its job, and (at least a little bit) harder to
write programs that defeat the optimizer.

To that end I would propose that:
 - parameters should be read-only AND invariant by default, and
 - that invariance should be enforced passing a deep immutable clone
   (*5) in place of any object that isn't already immutable.

-Martin

Footnotes:

*1: There are many possible reasons, but for example the caller didn't
declare it :readonly in turn to its callers because it *did* plan to meddle
with it -- but just not by calling this function with its :readonly
parameter.


*2: Yes I made up INVARIANT. The trick is that the compiler only needs
to insert the call if can't prove the invariance of $parameter, which it
*can* prove when:
 - it arrived in a :readonly parameter; or
 - it's locally scoped, and hasn't escaped.

In addition the implementation of INVARIANT() could:
 - return $self for any value class; and
 - return the encapsulated immutable object for the case outlined in the
   following footnote.

Otherwise the default implementation of INVARIANT() would be like
deepclone().

(Declaring a value class would ideally be shorter than declaring a
container class, but I'm a bit stuck as to how to achieve that. Ideas are
welcome...)


*3: The LVALUE method produces the sort of proxy object that others have
described, but with the reverse function: it acts as a scalar container
that can only hold immutable objects, and proxies all method calls to
it, but allows assignment to replace the contained object.  Calling
INVARIANT on such a container object simply returns the encapsulated
immutable object.


*4: As a generalization, the assumptions floating round that the
compiler will optimize things just aren't facing reality: programmers
are about the worst people when it comes to learning from the past
mistakes of others, and future generations of Perl6 programmers will
inevitably create evil container classes with no corresponding value
classes, and thus most parallelizing optimizations will be defeated.


*5: At the language level at least, copying is NOT the enemy of
optimization. On the contrary, if you always copy and *never* mutate,
that ensures that the compiler can always determine the provenance and
visibility of any given datum, and thus has *more* opportunities to
avoid *actually* copying anything. And it can parallelize to the full
extent of available hardware because it can guarantee that updates won't
overlap.


Re: Why pass by reference?

2009-06-19 Thread Martin D Kealey
On Fri, 19 Jun 2009, Martin D Kealey wrote:
 To that end I would propose that:
  - parameters should be read-only AND invariant by default, and
  - that invariance should be enforced passing a deep immutable clone
(*5) in place of any object that isn't already immutable.

Sorry, typo: that last word should have been invariant, meaning that it
*won't* change, rather than immutable, meaning that it *can't*.

Compilers can rely on invariance to perform a range of very powerful
optimizations; immutability is one way to guarantee invariance, but not the
only way.

-Martin


Re: Why pass by reference?

2009-06-17 Thread John M. Dlugosz

TSa Thomas.Sandlass-at-vts-systems.de |Perl 6| wrote:

HaloO,

Matthew Walton wrote:

If a user of your API contrives to make it change while you're
running, that's their own foot they've just shot, because they can
look at the signature and know the semantics of the parameter passing
being used and know that if they change the value externally before
you return Bad Things Could Happen.


I agree that the caller is responsible for the constness of the value
he gives to a function. With this we get the best performance. I don't
understand why John thinks that an intermediate proxy is needed. A very
shallow wrapper that ensures the readonlyness suffices. Most of the
time not even that when the constness is known statically.


Regards TSa.
shallow wrapper is what I'm talking about.  That is indeed a proxy: if 
a full-blown run-time check is needed (when it gets passed beyond its 
ability to track at compile time) it forwards methods, intercepts 
others, and modifies accessors.


Re: Why pass by reference?

2009-06-16 Thread TSa

HaloO,

Matthew Walton wrote:

If a user of your API contrives to make it change while you're
running, that's their own foot they've just shot, because they can
look at the signature and know the semantics of the parameter passing
being used and know that if they change the value externally before
you return Bad Things Could Happen.


I agree that the caller is responsible for the constness of the value
he gives to a function. With this we get the best performance. I don't
understand why John thinks that an intermediate proxy is needed. A very
shallow wrapper that ensures the readonlyness suffices. Most of the
time not even that when the constness is known statically.


Regards TSa.
--

The unavoidable price of reliability is simplicity -- C.A.R. Hoare
Simplicity does not precede complexity, but follows it. -- A.J. Perlis
1 + 2 + 3 + 4 + ... = -1/12  -- Srinivasa Ramanujan


Re: Why pass by reference?

2009-06-15 Thread Matthew Walton
 Complex or not in that sense, it complicates things in allowing the value to
 be changed by another path.  I think that is something we want to avoid
 doing, not present as a feature.  Much of my original post concerns the
 actual meaning, not whether it is considered simple.

 Since then, I see that it is useful for plural containers.  We don't want to
 copy them!  But for items, why do we not even _have_ pass by value?  The
 compiler must assume the worst and can't optimize as well.

'is copy' is pass-by-value... remember everything in Perl 6 is a
reference, of sorts. Pass-by-value of the reference is covered by 'is
ref'. A more useful variant of that being 'is rw', which gives you an
extra assurance with its lvalue checking that the user's not giving
you something that's going to explode when you try to modify it.
Pass-by-value of the thing the reference points to is covered by 'is
copy', which is the semantics people would generally expect when they
hear 'pass-by-value'.

Pass-by-reference-but-don't-accidentally-change-what-it-points-to is
covered by the default case or 'is readonly'. This seems to me to be
the ideal - we don't copy huge values around when the user doesn't
need them, but we also don't have hugely dangerous mutable parameters
by default (they should be extremely explicit for the user of an API).

Most of the time, there won't be another path where the value could
change. Under a threaded model allowing shared variables, sure it
could be changed by another thread, but hopefully you're under lock
there. If a user of your API contrives to make it change while you're
running, that's their own foot they've just shot, because they can
look at the signature and know the semantics of the parameter passing
being used and know that if they change the value externally before
you return Bad Things Could Happen.

Matthew


Re: Why pass by reference?

2009-06-15 Thread Matthew Walton
 Complex or not in that sense, it complicates things in allowing the value to
 be changed by another path.  I think that is something we want to avoid
 doing, not present as a feature.  Much of my original post concerns the
 actual meaning, not whether it is considered simple.

 Since then, I see that it is useful for plural containers.  We don't want to
 copy them!  But for items, why do we not even _have_ pass by value?  The
 compiler must assume the worst and can't optimize as well.

'is copy' is pass-by-value... remember everything in Perl 6 is a
reference, of sorts. Pass-by-value of the reference is covered by 'is
ref'. A more useful variant of that being 'is rw', which gives you an
extra assurance with its lvalue checking that the user's not giving
you something that's going to explode when you try to modify it.
Pass-by-value of the thing the reference points to is covered by 'is
copy', which is the semantics people would generally expect when they
hear 'pass-by-value'.

Pass-by-reference-but-don't-accidentally-change-what-it-points-to is
covered by the default case or 'is readonly'. This seems to me to be
the ideal - we don't copy huge values around when the user doesn't
need them, but we also don't have hugely dangerous mutable parameters
by default (they should be extremely explicit for the user of an API).

Most of the time, there won't be another path where the value could
change. Under a threaded model allowing shared variables, sure it
could be changed by another thread, but hopefully you're under lock
there. If a user of your API contrives to make it change while you're
running, that's their own foot they've just shot, because they can
look at the signature and know the semantics of the parameter passing
being used and know that if they change the value externally before
you return Bad Things Could Happen.

Matthew


Re: Why pass by reference?

2009-06-14 Thread Daniel Ruoso
Em Dom, 2009-06-14 às 15:53 -0500, John M. Dlugosz escreveu:
 In Perl 6, the default parameter passing is to make a read-only alias 
 for the caller's lvalue.  This means that the function may not change 
 the caller's variable, but must track changes to it made by other means.
 What is the point?
 It is a contrivance to illustrate how the variable can be changed by 
 other means, and requires a global variable, the same variable passed as 
 two different parameters, or the variable and a closure that affects the 
 variable be passed.

Actually, it only looks complicated while you think only on the callee
side. Because when you take the caller side, you'll note that it builds
a capture to send to the call, and the capture is always a reference, so
the signature just makes sure that references becomes read-only. To
illustrate:

 my $a = 1;
 foo($a);

In this case, the capture sent must contain a direct reference to the
scalar held in '$a', so both signatures with is ref or signatures with
is copy can work.

So, if foo has the signature

 sub foo($a is ref) {...}

it will be able to change the scalar outside foo. If it is

 sub foo($a) {...}

It will be a read-only access to that scalar

 sub foo($a is rw) {...}

Works almost like is ref, but encloses immutables into a container in
order to always provide rw semantics.

 sub foo($a is copy) {...}

Is the completely opposite to is ref, copying the actual value to a
new container.

So, it is not at all complicated, it's just oriented to the Capture, and
the capture provides semantics to the call that are not present in any
other language I'm aware of.

daniel



Re: Why pass by reference?

2009-06-14 Thread John M. Dlugosz

Daniel Ruoso daniel-at-ruoso.com |Perl 6| wrote:

Actually, it only looks complicated while you think only on the callee
side. 
No, in general it requires introducing a read-only proxy in front of the 
container.  This may be optimized away when it can be tracked at 
compile-time, but that's certainly not simple as compared to not 
having it nor the aliased item container at all.




Because when you take the caller side, you'll note that it builds
a capture to send to the call, and the capture is always a reference, so
the signature just makes sure that references becomes read-only. To
illustrate:

 my $a = 1;
 foo($a);

In this case, the capture sent must contain a direct reference to the
scalar held in '$a', so both signatures with is ref or signatures with
is copy can work.

So, if foo has the signature

 sub foo($a is ref) {...}

it will be able to change the scalar outside foo. If it is

 sub foo($a) {...}

It will be a read-only access to that scalar

 sub foo($a is rw) {...}

Works almost like is ref, but encloses immutables into a container in
order to always provide rw semantics.
  
No, is rw does not like immutables.  It will cause autovivification to 
take place, but will not accept something that is not an lvalue such as 
1 or Hello literals.  This was just doubled-checked with S06, S09, and 
discussion with Larry in #perl6.  If Ra


   ruosorakudo: sub foo($a is rw) { $a += 1; say $a }; foo(1);
   p6eval   rakudo 77f9d7: OUTPUT«2␤»

that directly contradicts S06, which states Otherwise the signature 
fails to bind, and this candidate routine cannot be considered for 
servicing this particular call.  Doing otherwise affects the semantics 
of MMD for allowing overloading based on whether the parameter is an 
lvalue or not.


Somebody who works with rakudo could submit a bug, if it's not in there 
already?






 sub foo($a is copy) {...}

Is the completely opposite to is ref, copying the actual value to a
new container.
  

Agreed.

So, it is not at all complicated, it's just oriented to the Capture, and
the capture provides semantics to the call that are not present in any
other language I'm aware of.

  


Complex or not in that sense, it complicates things in allowing the 
value to be changed by another path.  I think that is something we want 
to avoid doing, not present as a feature.  Much of my original post 
concerns the actual meaning, not whether it is considered simple.


Since then, I see that it is useful for plural containers.  We don't 
want to copy them!  But for items, why do we not even _have_ pass by 
value?  The compiler must assume the worst and can't optimize as well.


--John