Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-04-05 Thread Thomas Sandlaß
Larry Wall wrote:
Roles cannot be derived from, so they're always final in that sense.
We should probably consider them closed by default as well, or at least
closed after first use.  If a role specifies implementation, it's always
default implementation, so overriding implementation always occurs in a class
instead.
Ohh, is the following illegal?
role Blahh does Blubber {...}
Or is that just not considered derivation but, hmm, specialisation, subtyping
subroleing or some such?
So, does the above produce the subtyping relation Blahh : Blubber?
--
TSa (Thomas Sandla)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-04-05 Thread Thomas Sandlaß
HaloO Larry,
you wrote:
On Thu, Mar 31, 2005 at 06:35:06PM +0200, Thomas Sandlaß wrote:
: Is typing optional in the sense that it is no syntax error but
: otherwise ignored? To me this is pain but no gain :(
Well, you guys keep ignoring the answer.  Let me put it a bit more
mathematically.  The information in
my X $a;
is *necessary* but not *sufficient* to do method existence testing in
standard Perl 6 at compile time.  You can do it IFF you have the class
information AND the classes are willing to cooperate in your scheme.
In the current design, you can pragmatically request that all classes
cooperate, and you will get the cooperation of all classes that haven't
specifically been requested to be non-cooperative.  This is what all
the mumbo-jumbo about open/closed and final/non-final classes comes
down to.
That is clear, especially the part where you talk about necessary and
sufficient.  Please consider myself a disciple from now on :)
Actually I'm not obsessed with the compile time checking but with the
semantics. Which to me means that with the above declaration a method
must come from *this X or its supertypes* in the scope of the declaration.
To illustrate consider the following 4 cases:
| state when $a.m() |
declaration | is attempted  | semantics
+---+
1) my   $a; | $a doesn't m()| ignored or undef or exception
2) my   $a; | $a does m()   | call $a.m()
3) my X $a; | X doesn't m() | type error
4) my X $a; | X does m()| call most specific Xish $a.m()
The semantics of case 1) will be augmented by pragma I guess.
The above becomes more interesting if considering MMD. Then it
must be ensured that there is exactly one unique, most specialized
implementation available for handling type X. Note that this is a
stronger constraint than that the dispatch would succed for the
value of $a in question---and not achievable with a Manhattan metric.
And one more: when the runtime system doesn't manage to find a matching
X it could call into the compiler, class composer, type engine or however
this subsystem is called and try to make an appropriate type and a class
implementing it! And *that* is what I consider a dynamic language---or
meta language on the Parrot level.
Regards,
--
TSa (Thomas Sandlaß)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-04-05 Thread Larry Wall
On Tue, Apr 05, 2005 at 04:00:09PM +0200, Thomas Sandlaß wrote:
: Larry Wall wrote:
: Roles cannot be derived from, so they're always final in that sense.
: We should probably consider them closed by default as well, or at least
: closed after first use.  If a role specifies implementation, it's always
: default implementation, so overriding implementation always occurs in a 
: class
: instead.
: 
: Ohh, is the following illegal?
: 
: role Blahh does Blubber {...}
: 
: Or is that just not considered derivation but, hmm, specialisation, 
: subtyping
: subroleing or some such?

It does composition.

: So, does the above produce the subtyping relation Blahh : Blubber?

It means that both .does(Blahh) and .does(Blubber) return true.
It implies that Blahh contains the Blubber interface, but does not
imply that it has the same default implementation.  (It can, in fact,
advertise that it does Blubber but mangle the Blubber interface
completely if it chooses to, but that might be considered antisocial.
So the compiler might feel free to issue various warnings in that case.)

I, er, kinda fibbed above when I said that overriding implementation
only occurs in a class.  What I really meant was that, once you've
declared a role, it's closed, and you can warp its meaning only via
composition into some other role or class.  In isolation, a role
isn't really about subtyping--it's just a form of generic code.
But that same purity is what makes it useful for specifying subtype
relationships elsewhere.  And once roles start composing other roles,
it can be construed as a form of subtyping.

So, basically, yes.

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-04-02 Thread Larry Wall
On Thu, Mar 31, 2005 at 01:11:37PM -0500, Aaron Sherman wrote:
: If you declare a variable to be of a type (let's even say a class to be
: specific), then you have hinted to the compiler as to the nature of that
: variable, but nothing is certain.
: 
: That is to say that the compiler cannot:
: 
:   * Make any type-massaging choices yet on (implicit or explicit)
: method invocations
:   * Issue any errors based on signature miss-matches
: 
: Ok?

Yes.  You might perhaps be able to get warnings on things that
look like signature mismatches, but I certainly wouldn't make it
mandatory, or even the default.

: Now we move on to the idea of finalization. Please correct me where I
: conflate finalization and openness. I'm not sure I understand the
: difference at all (no, I'm certain I don't).

I think you already dug this up, but no harm in reiterating:

open/closed: whether you can munge the class definition itself.
final/non-final: whether this is guaranteed to be a leaf node class.

: We assert (don't have the docs handy, but I'll just arm-wave the syntax)
: that the class is now finalized.

We don't allow assertions that a particular class is final, because that's a
reversed dependency.  We only allow you to assert that a particular class is
non-final.  One way to do that is simply to derive from it.

: This means any attempt to re-define the
: interface of the class is a compile-time error, correct?

If we let you do it, but we don't.  :-)

The interface can be assumed frozen by the compiler only if the
entire application requests the class finalization optimization,
and if by CHECK time nobody has registered a dependency on the class
by either deriving from it or claiming that they will derive from it
in the future.  Applications with pluggable architecture should probably
not request the optimization unless there is some point in time at which
it can be determined that all plugins have been linked in.

: What about
: changing the internals of the class (e.g. changing the code associated
: with a method without re-defining the signature)?

That's more like the open/closed distinction, though for an open
class you could also change the interface on the fly, which would
invalidate some or all of your method dispatch caches.

The optimizer is also in control of open/closed classes, and you
may only declare that a class must remain open.  You may not declare
a class closed.  Again, your application may ask that all closable
classes be closed.

Final classes are a subset of closed classes, so if the optimizer
determines that it can finalize a class but not close a class, the
class is not finalized either.  That's not actually a big problem,
because unlike with finalization, classes may only remain open
by explicit declaration of the dependency, whereas classes may be
implicitly made non-final by deriving from them.

This is all policy of the default metaclasses.  You may, of course,
have other metaclasses that establish different policies.  There are
applications where you probably want your classes to be born closed.
This may negativly impact your ability to do AOP.

: Next, what are the conditions under which a class can be finalized?
: 
:   * Can we finalize a class which has non-finalized ancestors?

All ancestors are by definition non-final.

:   * What if it has method parameters/return values or member
: variables whose types are not finalized?

Depends on the extent to which we support named type equivalence vs
structural type equivalence, I suppose, and whether the compiler uses
type name information to make assumptions about the structure.

:   * What if it applies roles which are not finalized?

Roles cannot be derived from, so they're always final in that sense.
We should probably consider them closed by default as well, or at least
closed after first use.  If a role specifies implementation, it's always
default implementation, so overriding implementation always occurs in a class
instead.

Basically, in Perl 6 I think roles take on the, er, role of finalized
classes in specifying immutable interfaces, to a large extent.

: Obviously each one of these questions comes with a host of what happens
: if questions given a yes answer
: 
: Another question: how does finalization interact with a class's
: metaclass? Does the metaclass become a const? Is the type of a metaclass
: itself a finalized class? If not, can it be finalized by user code?

Metaclasses can do whatever they like.  They're worse than traits,
if that's possible.

As I say, the default metaclass is what provides the standard policies,
but they can be warped in whatever direction you like, if you want
everyone to hate you.

:  One additional wrinkle is that *anyone* is allowed to declare a
:  class non-cooperative (open or non-final) during *any* part of the
:  compilation
: 
: ... even after it is declared final?

Can't declare anything final in Standard Perl.

: Will core types be 

Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Thomas Sandlaß
Thomas Sandla wrote:
  Int|Str : Str  Str : Int|Str  Int|Str : Int  Int : Int|Str
holds.
Uhh, I hardly believe that it was me writing that last night!
Int|Str is of course a proper supertype of Int and Str respectively.
So we really have: Str : Str|Int  Int : Str|Int, which warps us
back to the co-/contravar problem of polymorphic rw containers.
And that doesn't help very much in achieving high flexibility under
the benevolence of strong typing.

Given an even more complex Any type that encompasses the general
purpose types of Perl6---namely Str, Int, Num, Bool and Refs thereof---
the lazy Perl6 programmer gets what Perl5 did all the time. This is
what is called Render the Illusion of Simplicity.
The solution is to make the juntive supertype on the polymorphic array
itself, which actually is much clearer:
class Array does Array of Str | Array of Int | ...
{ ... }
I'm not saying that this is easy to implement, but I'd appreciate
if it were part of Perl6 for a comprehensive set of types. I would
also expect some work on the side of new classes/types to participate
in this rw Array scheme.
--
TSa (Thomas Sandla)


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Miroslav Silovic
[EMAIL PROTECTED] wrote:
Er, isn't that not just the wrong way around? The point is to do the
bookkeeping that an object is needed that does .meth() and that it
is stored in $a, and to complain when that is not the case when it
should be. The earlier the better.
I don't understand why writing 'my X $a' needs at least a declaration
of X, but then '$a.meth()' does not consider '.meth' as a bare method
that needs a declaration in X?
Because you can do
sub infect(X $a is rw)
{
   role bla {
  method meth() {...}
   }
   $a does bla;
}
my X $a;
infect($a);
a.meth();
Remember, you can even change the class of instanced objects using 
'does' (or 'but', but it'll at least copy the object). And as the 
example above shows, this is statically intractable - it can happen in a 
sub in a different autoloaded module.

Also, what do you want to do if you actually want $a.meth() to throw a 
catchable exception if $a doesn't implement meth? It's what many OO 
languages do. In fact, I can't recall a single OO language that isn't 
derived from C++ that does /not/ just throw a runtime exception on 
unknown method.

   Miro



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Thomas Sandlaß
Miroslav Silovic wrote:
Remember, you can even change the class of instanced objects using 
'does' (or 'but', but it'll at least copy the object). And as the 
example above shows, this is statically intractable - it can happen in a 
sub in a different autoloaded module.
Sorry this is a well established fact in this thread. If unspecificity
is what you want than you use 'my $a;' and the compiler happily parses
'$a.meth()' purely syntactically and generates code for dynamic lookup
and potential exception throwing.
Aaron's and my point is the reverse: what do we gain if the same applies
when we kindly announce that $a should do X'ish things only. That of course
includes late bound fancy versions of methods from the interface of X. If
there's no difference why bother to make declarations?
This whole thread is about semantics close to syntax. I mean we know that
everything with a dot is a method which syntactically makes dot the infix
method sigil or some such.  But I want the compiler to do a bit more than
just extracting the string after the dot from my source code and stash it
in some namespace when I requested the constraint X.
Is typing optional in the sense that it is no syntax error but
otherwise ignored? To me this is pain but no gain :(
BTW, is 'my ::X $a;' introducing X as unspecific as it could be?
Just occupying the syntactic slot of a type? That could be usefull
to start in an explorational style and eventually use the PTE
(P(arrot|erl6) Type Engine) to infer what X should look like.
I really see the PTE as the twin of the PGE---and no Perl hacker
disavows the power of regular expressions and parsers ;)

Also, what do you want to do if you actually want $a.meth() to throw a 
catchable exception if $a doesn't implement meth? It's what many OO 
languages do. In fact, I can't recall a single OO language that isn't 
derived from C++ that does /not/ just throw a runtime exception on 
unknown method.
Well that would just be role X { method meth() {...} } by virtue of
the nada operator---whatever exception it throws and how much it tells
about X::meth().
--
TSa (Thomas Sandlaß)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Larry Wall
On Thu, Mar 31, 2005 at 06:35:06PM +0200, Thomas Sandlaß wrote:
: Is typing optional in the sense that it is no syntax error but
: otherwise ignored? To me this is pain but no gain :(

Well, you guys keep ignoring the answer.  Let me put it a bit more
mathematically.  The information in

my X $a;

is *necessary* but not *sufficient* to do method existence testing in
standard Perl 6 at compile time.  You can do it IFF you have the class
information AND the classes are willing to cooperate in your scheme.
In the current design, you can pragmatically request that all classes
cooperate, and you will get the cooperation of all classes that haven't
specifically been requested to be non-cooperative.  This is what all
the mumbo-jumbo about open/closed and final/non-final classes comes
down to.

One additional wrinkle is that *anyone* is allowed to declare a
class non-cooperative (open or non-final) during *any* part of the
compilation, so your method existence checking cannot be done at
reduction time, but must be done as a separate pass from a CHECK
block at the end of whatever lexical scope requested cooperation.
CHECK blocks are construed to be the end of normal compilation;
Perl 6 very much follows the Perl 5 model here.

I hope this clears things up a little.

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Aaron Sherman
On Thu, 2005-03-31 at 11:51, Larry Wall wrote:

 my X $a;
 
 is *necessary* but not *sufficient* to do method existence testing in
 standard Perl 6 at compile time.  You can do it IFF you have the class
 information AND the classes are willing to cooperate in your scheme.
 In the current design, you can pragmatically request that all classes
 cooperate, and you will get the cooperation of all classes that haven't
 specifically been requested to be non-cooperative.  This is what all
 the mumbo-jumbo about open/closed and final/non-final classes comes
 down to.

So let me try to unpeel that (I'm not trying to be difficult, it's just
that this is a difficult topic as evidenced by the mountain of
documentation on the topic by languages that try to be only HALF as
flexible).

If you declare a variable to be of a type (let's even say a class to be
specific), then you have hinted to the compiler as to the nature of that
variable, but nothing is certain.

That is to say that the compiler cannot:

  * Make any type-massaging choices yet on (implicit or explicit)
method invocations
  * Issue any errors based on signature miss-matches

Ok?

Now we move on to the idea of finalization. Please correct me where I
conflate finalization and openness. I'm not sure I understand the
difference at all (no, I'm certain I don't).

We assert (don't have the docs handy, but I'll just arm-wave the syntax)
that the class is now finalized. This means any attempt to re-define the
interface of the class is a compile-time error, correct? What about
changing the internals of the class (e.g. changing the code associated
with a method without re-defining the signature)?

Next, what are the conditions under which a class can be finalized?

  * Can we finalize a class which has non-finalized ancestors?
  * What if it has method parameters/return values or member
variables whose types are not finalized?
  * What if it applies roles which are not finalized?

Obviously each one of these questions comes with a host of what happens
if questions given a yes answer

Another question: how does finalization interact with a class's
metaclass? Does the metaclass become a const? Is the type of a metaclass
itself a finalized class? If not, can it be finalized by user code?

 One additional wrinkle is that *anyone* is allowed to declare a
 class non-cooperative (open or non-final) during *any* part of the
 compilation

... even after it is declared final?

Will core types be finalized by default?

 I hope this clears things up a little.

Clear that's a word ;-)

Yes, your message helped. I can sense your exasperation, but it is my
hope that asking stupid questions now means that we'll have smart
answers by the time P6 is released. If I'm overly slowing the process,
please say so, and I'll stop asking.

-- 
Aaron Sherman [EMAIL PROTECTED]
Senior Systems Engineer and Toolsmith
It's the sound of a satellite saying, 'get me down!' -Shriekback




Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread chromatic
On Thu, 2005-03-31 at 13:11 -0500, Aaron Sherman wrote:

I can't answer most of these well.  However...

  One additional wrinkle is that *anyone* is allowed to declare a
  class non-cooperative (open or non-final) during *any* part of the
  compilation
 
 ... even after it is declared final?

I hope so.

 Will core types be finalized by default?

I hope not, but if so, I hope they include all of the behavior anyone
could ever possibly want from them so that no one will ever have to
decorate them to add that one little important missing feature.

Open-Closed is a great idea until the most natural and easiest way to do
something is to to redefine a little bit of the world.

-- c



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Jonathan Scott Duff
I'm no expert, but here's my take:

On Thu, Mar 31, 2005 at 01:11:37PM -0500, Aaron Sherman wrote:
 If you declare a variable to be of a type (let's even say a class to be
 specific), then you have hinted to the compiler as to the nature of that
 variable, but nothing is certain.
 
 That is to say that the compiler cannot:
 
   * Make any type-massaging choices yet on (implicit or explicit)
 method invocations
   * Issue any errors based on signature miss-matches
 
 Ok?

I don't quite know what you mean by type massaging choices, but sure
the compiler *can* issue errors on signature mismatch.  When you say

my X $a;

the compiler has to treat $a like an X even if it doesn't know
everything there is to know about X (X may not even be defined yet).
So if you pass $a to a routine that's expecting a Y, then the compiler
can and will carp.

If, by type massaging choices you mean deciding whether or not to
accept a variable in a signature slot based on its type (i.e., if the
parameter is declared as a super-type of X, do we accept a X for this
parameter), then I think the compiler can do that as well.

 Now we move on to the idea of finalization. Please correct me where I
 conflate finalization and openness. I'm not sure I understand the
 difference at all (no, I'm certain I don't).

final classes can not be derived from, non-final can.
closed classes can not have new methods added to them later on, open
classes can.

 We assert (don't have the docs handy, but I'll just arm-wave the syntax)
 that the class is now finalized. This means any attempt to re-define the
 interface of the class is a compile-time error, correct? What about
 changing the internals of the class (e.g. changing the code associated
 with a method without re-defining the signature)?

If I assume you're talking about closed classes here (as it seems),
then I'd say that you can not redefine the interface or change it's
internals.

If you really do mean finalized classes, then I'd think that you *can*
change the interface or the internals.

 Next, what are the conditions under which a class can be finalized?
 
   * Can we finalize a class which has non-finalized ancestors?

Certainly.  Even if you meant can we close a class which has
non-closed ancestors, I think you can do both.  Not sure though.

   * What if it has method parameters/return values or member
 variables whose types are not finalized?

Finalization and closing is not something you do to instances, but
rather classes.

   * What if it applies roles which are not finalized?

I don't think you can finalize roles (it doesn't make sense to me to
be able to do so anyway)  Closing roles, I think you can do though.

Also, according to 
http://dev.perl.org/perl6/synopsis/S12.html#Open_vs_Closed_Classes

There is no syntax for declaring individual classes closed or
final. The application may only request that the optimizer close
and finalize unmarked classes.

So you would have a default policy of closed/final and then
open/unfinalize individual classes, or have a default policy of
open/non-final and have no way to close/finalize individual classes.

 Another question: how does finalization interact with a class's
 metaclass? 

I don't think it does, except that that may be the hook by which we
obtain no dreviatives allowed on implementation. (i.e. the
meta-classes enforces the restrictions placed upon the class)

 Does the metaclass become a const? Is the type of a metaclass
 itself a finalized class?  If not, can it be finalized by user code?

You've strayed beyond my idea-space here :-)

  One additional wrinkle is that *anyone* is allowed to declare a
  class non-cooperative (open or non-final) during *any* part of the
  compilation
 
 ... even after it is declared final?

Sure.

 Will core types be finalized by default?

No. It would be very un-perl-like to have such an unasked for
restriction IMHO.

Caveat lector, I'm not of the cabal.

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-31 Thread Aaron Sherman

On Thu, 2005-03-31 at 15:25, chromatic wrote:
 On Thu, 2005-03-31 at 13:11 -0500, Aaron Sherman wrote:
 
 I can't answer most of these well.  However...

 Open-Closed is a great idea until the most natural and easiest way to do
 something is to to redefine a little bit of the world.

You seemed to have answered my questions on the basis of a piece of
information which I asked for, but you did not include... I took the
liberty of re-reading S12 and A12 to find it, and got two answers which
are almost the same.

After having found the bit on open vs. final, I'm even more at a loss,
but I have some answers... let me start trying to put them together for
others to scrutinize (I'm not taking a pro or con position on any of
this yet, just trying to get the details worked out).

S12 sayeth:

By default, all classes in Perl are non-final, which means you
can derive from them.

Ok, so this answers a few of my questions. Namely, you can't do anything
particularly useful by finalizing your class (and A12 tells us you can't
really anyway). You would have to finalize EVERYTHING in your class's
inheritance chain up to, but not including it, and then close your own
class in order to allow compile-time error detection and type massaging.
Also note that A12 says:

Likewise, a final class (to use the Java term) is one that you
know will never be derived from, let alone mucked with
internally.

which subtly contradicts (or at least expands on in an unexpected way)
S12 by implying that final implies closed does it?

S12 then goes on to say:

They are also open, which means you can add more methods to
them, though you have to be explicit that that is what you're
doing:

This is far too limited, isn't it? What can we normally do to a class?
In conversations here, we've previously arm-waved that we'd be able to
do damn near anything we pleased through the metaclass... but perhaps
that's not true?

I think that's pretty much what I know and don't know as of now...
anyone want to take a shot?

-- 
Aaron Sherman [EMAIL PROTECTED]
Senior Systems Engineer and Toolsmith
It's the sound of a satellite saying, 'get me down!' -Shriekback




Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
Luke Palmer wrote:
Unless the caller can't see the signature, as is the case with methods.
[..]
Again, this can't be done unless you know the signature.  And in fact,
we can't do type inference on methods unless we do type inference
everywhere, which we can't do if we want an autoloader.
This sounds to me even messier than the C header file mishap,
or even the old KR days without protoyped declarations!
How can the programmer know about the signature of a method?
I guess from some documentation. And the prime documentation of
an interface is a formal interface definition provided by the
language. This is e.g. what Ada does. Also CORBA is build around
its IDL (Interface Definition Language) and from version 3.0
onwards a CDL (Component Definition Language).
If I understand you correctly the use statement is more like a
linker/loader directive than a compile time interface include?
BTW, is it foreseen to have a clear conceptual split between the
compiler and the loader? Or is that all blurred?
--
TSa (Thomas Sandla)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Aaron Sherman
On Tue, 2005-03-29 at 16:00 -0700, Luke Palmer wrote:

 Unless the caller can't see the signature, as is the case with methods.

I need to understand this piece.

In this code:

class X {
method meth() {...}
}
class Y is X {
method meth() is rw(int $r) {...}
}
sub foo { return my Y $tmp }
my X $a = foo();
$a.meth() = 8;

What happens? Do we impose a compiler-level restriction on the call that
prevents this, or do we always allow it, and let the run-time take care
of it?

My preference by far is to let the compiler tell you that it's illegal
because there's no valid reason for a sub-class to change the semantics
of a polymorphically invoked method like this. The sub-class might
introduce new semantics, but when manipulated as a base-class those
semantics should only come into play when they are invoked via the
interface of the base class. That sounds like an almost axiomatic truism
to me, but if I read what you wrote correctly, you don't seem to agree.

It's important to look at this as a two(more?)-stage process with
different agendas and limitations, no?

More generally, I think it's always a valid thing for the compiler to
impose the restrictions of the type it knows about, regardless of what
polymorphism might discover later on at run-time. This means that you
can't do this:

class X { }
class Y { method m (int $a) {...} }
my X $ob = get_me_a_Y();
$ob.m(1);

because X does not provide an m.

 Again, this can't be done unless you know the signature.  And in fact,
 we can't do type inference on methods unless we do type inference
 everywhere, which we can't do if we want an autoloader.

You can combine and autoloader with type inference. You may not choose
to, but it's not impossible. You can load the signatures ahead of time,
and link the code at run-time. What gets dicy is this:

eval use X;
my X $a;
$a.m(1);

I think that's invalid too, but I'm not sure.




Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Aaron Sherman writes:
 On Tue, 2005-03-29 at 16:00 -0700, Luke Palmer wrote:
 
  Unless the caller can't see the signature, as is the case with methods.
 
 I need to understand this piece.
 
 In this code:
 
   class X {
   method meth() {...}
   }
   class Y is X {
   method meth() is rw(int $r) {...}
   }
   sub foo { return my Y $tmp }
   my X $a = foo();
   $a.meth() = 8;
 
 What happens? Do we impose a compiler-level restriction on the call
 that prevents this, or do we always allow it, and let the run-time
 take care of it?
 
 My preference by far is to let the compiler tell you that it's illegal
 because there's no valid reason for a sub-class to change the
 semantics of a polymorphically invoked method like this. The sub-class
 might introduce new semantics, but when manipulated as a base-class
 those semantics should only come into play when they are invoked via
 the interface of the base class. That sounds like an almost axiomatic
 truism to me, but if I read what you wrote correctly, you don't seem
 to agree.

No, I think I agree with you here.  But what happens if you change
you're second-to-last line to:

my $a = foo();
$a.meth() = 8;

Perl 6 is both a statically typed language and a dynamically typed
language, and the problems that I am addressing are mostly about the
dynamic part.

 You can combine and autoloader with type inference. You may not choose
 to, but it's not impossible. You can load the signatures ahead of time,
 and link the code at run-time. What gets dicy is this:
 
   eval use X;
   my X $a;
   $a.m(1);
 
 I think that's invalid too, but I'm not sure.

Again, that's invalid in the static world, but it should work if you
s/my X/my/.   The kinds of type inferrence people are saying would solve
our problems require us to infer code like this, which we can't do.

There _is_ a way to do it, actually, but we need to really screw around
with what kinds of things are inferred.  In the case:

my $a;
$a.m(1);

We assign the type objects with an 'm' method that can take a single
integer to $a.  This is a category of objects that spans many classes,
and does not fit into a nice little tree.  I think that before we take
on such an idea, we should look for research about this kind of type
inference.

Luke


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Larry Wall
On Wed, Mar 30, 2005 at 09:40:26AM -0700, Luke Palmer wrote:
: There _is_ a way to do it, actually, but we need to really screw around
: with what kinds of things are inferred.  In the case:
: 
: my $a;
: $a.m(1);
: 
: We assign the type objects with an 'm' method that can take a single
: integer to $a.  This is a category of objects that spans many classes,
: and does not fit into a nice little tree.

I think it's perfectly fine for the compiler to make use of whatever
information it has.  The trick is to never make any unwarranted
assumptions, such as Nobody will ever add another class with an 'm'
method.  It can assume that only if you explicitly tell it to, and
if nobody has jimmied any classes to remain open and/or non-final.
Otherwise you have to at least be prepared to recalculate the
effective meaning of your 'm' type, and know when that recalculation
is necessary.  Even if classes are open and non-final, you can
at least cache information that is temporarily true, and make good
use of it.  Perl 5 certainly takes that approach in spots.  Perl 5
doesn't do a good job of localizing the damage, however.  If you
monkey around with your classes, it basically throws away all the
cached data by incrementing a generation count.

: I think that before we take on such an idea, we should look for
: research about this kind of type inference.

As long as we includes you, that's fine by me.  :-)

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
HaloO Luke,
you wrote:
No, I think I agree with you here.  But what happens if you change
you're second-to-last line to:
my $a = foo();
$a.meth() = 8;
Perl 6 is both a statically typed language and a dynamically typed
language, and the problems that I am addressing are mostly about the
dynamic part.
My state of affairs is that these two lines of code lack declarations
that clearly announce what the user of foo and X wanted:
1) foo returns an X
2) an X does .meth()
Where, how and if these are implemented, autoloaded or what not
is another business. Client side type checking ensures that no
usage outside the declared behaviour occurs. For larger declarations
I which to put them into an interface module, package, header or
however that is called and include it.
On the implementation side we get the complementary definitions:
1) here's an X that does .meth()
2) here's a foo that returns an X
The dynamism of Perl6 should revolve around how to bring these
two sides of an interface together conveniently and efficiently.
Just using 1% of a big package shouldn't let your 10-liner
become a bloated pig!
And of course the builtin functionality and the packages available
from CPAN save the typical small scale programmer from extensive
declarations. But to use a complex module you have to read
documentation to get the idea to call .meth() in the first place.
And then I like to get the hint from the compiler that there is
no .mth() and happily correct the spelling error. Spotting these
types of errors is were computers are much better than humans :)

We assign the type objects with an 'm' method that can take a single
integer to $a.  This is a category of objects that spans many classes,
and does not fit into a nice little tree.  I think that before we take
on such an idea, we should look for research about this kind of type
inference.
Type calculations are not inherently difficult, especially when junctive
values are at hand. The problem is that the inference can quickly diverge
to the useless something is done to an anything. Dwimmery works best
when it bridges little gaps in an otherwise very rich semantic network.
--
TSa (Thomas Sandla)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Aaron Sherman
On Wed, 2005-03-30 at 11:40, Luke Palmer wrote:

 No, I think I agree with you here.  But what happens if you change
 you're second-to-last line to:
 
 my $a = foo();
 $a.meth() = 8;
 
 Perl 6 is both a statically typed language and a dynamically typed
 language, and the problems that I am addressing are mostly about the
 dynamic part.

The way I've always thought about that one (and perhaps I'm just
misguided) is that you're really saying:

my unknown $a = foo();
$a.meth() = 8;

And unknown does something strange (unique?) along the lines of:

class unknown is scalar, pragma::everything {...}

That is, logically, unknown allows you to use any interface (note that I
said pragma because sub-classes of scalar don't get this behavior),
but realistically, a compiler must simply throw up its hands on that ONE
type of variable and allow you to get away with nearly anything (and
leave it up to the run-time to use your vtable to discover the truth).

The feature you get here is that a compiler that wanted to spend hours
of compute-time validating your program COULD search every known
interface, and tell you:

Unknown method signature in dynamic call at line 100

or an even smarter compiler could say:

Method signature on line 100 unrelated to previous usage on line 98

That is, you called a method on line 98 that matches no classes above,
below or the same as the classes matched by the signature of the method
you called on line 100. This kind of lint checking would be very
handy, though I'm sure it would be too time-consuming for the general
-w case.

  eval use X;
  my X $a;
  $a.m(1);
  
  I think that's invalid too, but I'm not sure.
 
 Again, that's invalid in the static world, but it should work if you
 s/my X/my/.   The kinds of type inferrence people are saying would solve
 our problems require us to infer code like this, which we can't do.

I think there, you are well justified in saying that you can try to get
away with it, but a compiler that's smart enough to realize that you
need a run-time loaded dynamic type to make it work should punt it. Of
course, that ASSUMES that auto-loading is a two-stage process with an
interface definition and a run-time code load. Given that, what you
wanted was auto-loading, not run-time string eval. Those are not the
same thing.

If you're doing code-generation at run-time ... huh, what happens, let
me think...

Let's say you generate this code from a specification of some sort:

class __c001 { method __m001(int $__i001) {...} }
__c001.new;

and then try to call:

(eval $generated_code).__m001(1);

Ok, that's good because eval returns the same unknown scalar type as a
bare my declares. I guess you can also taint anything that comes from an
eval and just avert your gaze... you'll have to taint objects that use
non-Perl6 object systems in the same way, anyhoo:

my $thing = Runtime::Python::re::compile('.*');
$thing.search('moo');

 There _is_ a way to do it, actually, but we need to really screw around
 with what kinds of things are inferred.  In the case:
 
 my $a;
 $a.m(1);
 
 We assign the type objects with an 'm' method that can take a single
 integer to $a.  This is a category of objects that spans many classes,
 and does not fit into a nice little tree.  I think that before we take
 on such an idea, we should look for research about this kind of type
 inference.

Heh well, here's where we notice that Aaron reads and replies in series
by paragraph ;-)

-- 
Aaron Sherman [EMAIL PROTECTED]
Senior Systems Engineer and Toolsmith
It's the sound of a satellite saying, 'get me down!' -Shriekback




Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Thomas Sandla writes:
 And of course the builtin functionality and the packages available
 from CPAN save the typical small scale programmer from extensive
 declarations. But to use a complex module you have to read
 documentation to get the idea to call .meth() in the first place.
 And then I like to get the hint from the compiler that there is
 no .mth() and happily correct the spelling error. Spotting these
 types of errors is were computers are much better than humans :)

And it sure would be able to spot that kind of error, supposing the sub
declaration is in scope.  But suppose it weren't.  Maybe that's a bit
hard to fathom if you haven't written an autoloader.  Suppose, then,
that you have this code:

class CodeProxy {
has Code $.code is rw;
sub call ($a) {
$.code($a);
}
}

This is valid Perl 6, and anyone who says otherwise (because of type
signatures) is changing the Perl philosophy too much to be taken
seriously.  Now, tell me at compile time whether the call inside `call`
is valid.

Of course, the alleged type inferencer can do some magic and make sure
that it is.  It says that the $.code member variable is not just of type
`Code`, but of type `Code is sig($x) forall $x` (are siglets still
around?).  Then this code would not fail to compile, but any code that
tried to assign an incompatible routine to the .code member would fail
to compile.

At runtime, you load in a new subclass of `CodeProxy`, `DoubleCodeProxy`
(this programmer apparently doesn't know that we support variadic
signatures :-)

class DoubleCodeProxy is CodeProxy {
method call ($a, +$b) {
.code().($a, $b);
}
}

Again, undisputably valid Perl 6.  Every method takes an implicit `*%`,
so it's not an interface violation to add a new named parameter.  And
now it's okay to assign a code object to $.code which manditorily takes
two parameters, if that object happens to be a `DoubleCodeProxy`.  But
we can't tell whether it's a `DoubleCodeProxy` by type inference,
because we didn't even know what a `DoubleCodeProxy` was at compile
time.

C++ gets around this problem by disallowing a declaration like `has Code
$.code` -- All declarations must be fully specified.  Perl is not going
to do that.

Unless I've mis-argued somewhere (I've been straining to get this
message done before my next class starts, so my thinking may be sloppy),
this example case requires the check to be put off until runtime.  In
that case, you certainly can't use inferred type information to make any
semantic choices, and the best we can do is to use it as a compile-time
error checker (in the cases where it's capable of doing so) and as an
optimizer.

Luke


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
Larry Wall wrote:
I think it's perfectly fine for the compiler to make use of whatever
information it has.  The trick is to never make any unwarranted
assumptions, such as Nobody will ever add another class with an 'm'
method.
Er, isn't that not just the wrong way around? The point is to do the
bookkeeping that an object is needed that does .meth() and that it
is stored in $a, and to complain when that is not the case when it
should be. The earlier the better.
I don't understand why writing 'my X $a' needs at least a declaration
of X, but then '$a.meth()' does not consider '.meth' as a bare method
that needs a declaration in X? Polymorphism is about requiring that
objects do compare and then sort a bunch of them using that particular
role---not more not less. Or think of US Postal just transporting letters
irrespective of them containing Anthrax or not, as long as they bear the
right stamps!
--
TSa (Thomas Sandlaß)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Aaron Sherman
On Wed, 2005-03-30 at 13:53, Luke Palmer wrote:

 class CodeProxy {
 has Code $.code is rw;
 sub call ($a) {
 $.code($a);
 }
 }

 This is valid Perl 6, and anyone who says otherwise (because of type
 signatures) is changing the Perl philosophy too much to be taken
 seriously.  Now, tell me at compile time whether the call inside `call`
 is valid.

It's valid because it's a function call on a code ref. In that case, the
compiler has to hand your request off to the run-time to check the
vtable of $.code. Clearly that's a special case. I may have missed
context at the start, but are we worried about the special cases or the
general case or the implications to the general case of the special
cases?

 At runtime, you load in a new subclass of `CodeProxy`, `DoubleCodeProxy`
 (this programmer apparently doesn't know that we support variadic
 signatures :-)

I think this is where you're stepping off the path I thought we were on,
and I agree with the rest of your message FOR ONE CASE, but not all.
Runtime loading can happen in many ways, but let's break them down into
two camps: with and without a compile-time interface definition. In the
first camp you have autoload. In the second camp you have low-level
(e.g. Parrot) code that happens to have no interface definition (because
it's pure PBC or because it came from another language) and evaluated
strings.

What I do not think should be allowed (and I may be contradicting Larry
here, which I realize is taking my life in my hands ;) is violating the
compile-time view of the static type tree. That is, you can load an
object foo at run-time, without and interface definition, but it can't
change the shape of the type tree or its existing interfaces. If it
wants to do that, it has to provide an interface def (e.g. what an
autoload module should be able to provide).

Why? Because if you can do that, then this:

my X $a;
$a.m(1) = 1;

ALWAYS has to work because you might have replaced X at run-time with a
class that has a method m(int) is rw(), and the compiler must silently
(perhaps with an optional warning) permit it.

Please think carefully about how dynamic you want Perl 6 to be
Dynamic is good, but there's such a thing as too much of a good thing.

-- 
Aaron Sherman [EMAIL PROTECTED]
Senior Systems Engineer and Toolsmith
It's the sound of a satellite saying, 'get me down!' -Shriekback




Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Larry Wall
On Wed, Mar 30, 2005 at 12:05:12PM +0200, Thomas Sandlaß wrote:
: If I understand you correctly the use statement is more like a
: linker/loader directive than a compile time interface include?

That is up to the module being used.  use is a linker, but it's
only required to link enough information into the caller such that
the caller can see the interface.  Loading can happen later--though
it typically happens on first use rather than first use.  The
point is there's no separate linker step.  Everything is demand
driven, and what gets linked in at compile time depends on what gets
demanded at compile time.  If something isn't demanded till run
time, the compiler can't know it, unless you tell it in advance
somehow, which presumes that *you* know it.   And maybe you don't.
And that is when late binding is ever so much handier than early.

: BTW, is it foreseen to have a clear conceptual split between the
: compiler and the loader? Or is that all blurred?

Clear conceptual splits often hide false dichotomies.  The split is
rather blurry for Perl 5, and Perl 6 will only continue the trend.
There are good uses for both early binding and late binding, and
for various forms of binding in between--it's a continuum, and each
module is allowed to draw the boundary wherever and however it likes.
Birds naturally prefer early binding to late binding; worms will
naturally disagree.  Rolling stones gather no type constraints.

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread chromatic
On Wed, 2005-03-30 at 14:29 -0500, Aaron Sherman wrote:

 What I do not think should be allowed (and I may be contradicting Larry
 here, which I realize is taking my life in my hands ;) is violating the
 compile-time view of the static type tree. That is, you can load an
 object foo at run-time, without and interface definition, but it can't
 change the shape of the type tree or its existing interfaces. If it
 wants to do that, it has to provide an interface def (e.g. what an
 autoload module should be able to provide).

I disagree, *unless* you predeclare that you don't plan to change
anything -- as an optimization hint.  (Though if you write a module to
do this as a policy, I won't hunt you down with my +2 club of Optimize
for the Programmer, not the Compiler.)

I certainly plan to continue to instrument code at runtime (and not just
really slushy, partially slushy, and permafrost compile time).

-- c



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Aaron Sherman
On Wed, 2005-03-30 at 14:57, chromatic wrote:

 I certainly plan to continue to instrument code at runtime (and not just
 really slushy, partially slushy, and permafrost compile time).

That's FINE, and no one should stop you!

What I was referring to was only the items that an interface definition
would be concerned with (that is, those things which would invalidate
the compiler's assumptions).

An example follows.

Original code:

class X { method m(int $i) { say Hello, world } }

Valid string to eval:

q{class X { method m(int $i) { die Goodbye, world } }}

Invalid string to eval:

q{class X { method m(int $i) is rw($string) { say $string } }}

The latter changes the interface definition, and thus invalidates the
compiler's assumptions, but you can instrument the code all you like,
re-defining any darned thing you wish!

If you allow the interface definition to change, you're not optimizing
for the programmer. You're optimizing for the amount of time you spend
in the debugger. Failing to eval early because code would have changed
the interface (or type hierarchy) of your types will save thousands of
programmers everywhere much debugging time.

Like I said, if you allow run-time munging of the type interfaces, then
you can't tell if this is valid or invalid:

my X $a;
$a.m(1);

you have to allow it always, regardless of the definition of X. In fact,
you can NEVER reject ANY method or function invocation based on
signature, since it might change at run-time.

Is that really what you want?

-- 
Aaron Sherman [EMAIL PROTECTED]
Senior Systems Engineer and Toolsmith
It's the sound of a satellite saying, 'get me down!' -Shriekback




Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread chromatic
On Wed, 2005-03-30 at 15:27 -0500, Aaron Sherman wrote:

 Like I said, if you allow run-time munging of the type interfaces, then
 you can't tell if this is valid or invalid:
 
   my X $a;
   $a.m(1);
 
 you have to allow it always, regardless of the definition of X. In fact,
 you can NEVER reject ANY method or function invocation based on
 signature, since it might change at run-time.
 
 Is that really what you want?

I want the possibility to correct bad decisions of interfaces and
signatures whenever possible in the most minimally intrusive way
possible.  I don't want to work around a module or class or function or
method where someone tried to be helpful by saying Oh, this will
absolutely never change, ever and the compiler helpfully froze that
decision forever.  Sometimes that means changing it outside the
incorrect code.

I don't trust any compiler to make every decision correctly, and in
cases of ambiguity I believe that I can give it better hints than it can
reason for itself if I need the extra speed or safely.

A compiler that assumes incorrectly and disallows programmers to do
useful things because its holds those assumptions as precious is wrong
-- especially in cases where even the programmer can't tell if code is
valid or invalid until the program actually runs.

-- c



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
Luke Palmer wrote:
class CodeProxy {
has Code $.code is rw;
sub call ($a) {
$.code($a);
}
}
This is valid Perl 6,
Hmm, a sub in a class? I guess that should be a method. OTOH a
class is just a funny module, so might be OK. But that is the
syntax realm.

and anyone who says otherwise (because of type
signatures) is changing the Perl philosophy too much to be taken
seriously.  Now, tell me at compile time whether the call inside `call`
is valid.
Ups, before we start talking past each other: I think a type system
is just a tool that reminds you to your declarations. No declarations,
no reminder, it's that simple. I would like the typing of $.code as Code
to be necessary to apply the .() invocation operator on it. The rest is
deferred to runtime if that is what you want.
And I'm completly unsure how much parrot and/or perl revert back into
compile state when you bring in new source code at runtime. Or how
much load time activity is needed for a byte code file.
The question if instances of DoubleCodeProxy are subtypes of instances
of CodeProxy boils down to the question if ($) : ($, +$) with : beeing
the subtype relation. Is that the right siglet syntax? Since named-only
parameters are optional the relation holds. This subtype relation allows:
my CodeProxy $cp = DoubleCodeProxy.new; # needs DoubleCodeProxy : CodeProxy
$cp.code = sub ($x, +$y = unknown) { say x = $x, y = $y };
$cp.call( first, b = second ); # prints x = first, y = second
$cp.call( one );  # prints x = one, y = unknown
$t = $cp.code;
$cp.code = sub () { say void };  # no problem, type is Code
$cp.call( X ); # gives runtime error on closure in $.code
$cp.code = $t;
$cp.call(); # compile error: too few args
$cp.call( 1, 2 ); # compile error: too many positional args
$cp.blahh( 23 ); # compile error/warning: no such method declared
method CodeProxy::blubber(: $z ) { ... }
$cp.blubber( 42 ); # could die on ... at runtime if no .blubber autoloaded
$cp.call( 1|2|3 ); # autothreads??? I leave that to Damian :)
--
TSa (Thomas Sandla)


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
chromatic wrote:
A compiler that assumes incorrectly and disallows programmers to do
useful things because its holds those assumptions as precious is wrong
-- especially in cases where even the programmer can't tell if code is
valid or invalid until the program actually runs.
Me neither. One should think of a type system like dependency declarations
in a Makefile: you get out what you put in. Too few dependencies might result
in incomplete rebuilds. Complete dependencies might remind you how convoluted
your design is. And make doesn't manage circular dependencies :)
--
TSa (Thomas Sandlaß)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
Aaron Sherman wrote:
No, that was most of the point. foo did not declare a return type, and
while my code was simplistic, we obviously cannot be certain what foo
might return in the general case.
Sorry that I've spoiled that. But I wonder if it's just in the examples
here on the list or a general laxity to not specify a return type of
subs and methods. I consider leaving it to the compiler to infer it bad
style. BTW, what is the default return type? Just Void? Is an explicit
return statement than a compile error?
--
TSa (Thomas Sandlaß)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Thomas Sandla writes:
 Aaron Sherman wrote:
 No, that was most of the point. foo did not declare a return type, and
 while my code was simplistic, we obviously cannot be certain what foo
 might return in the general case.
 
 Sorry that I've spoiled that. But I wonder if it's just in the
 examples here on the list or a general laxity to not specify a return
 type of subs and methods. 

It depends on the programmer.  I'm sure that you and probably Aaron will
always declare your return types.  I'm quite sure that I will not except
for when it effects a semantic that I want.

Ultimately, it depends on how Perl 5-ish you want to program Perl 6 in
this regard.  I definitely enjoy Perl 5's late binding for the most
part.  Again, I usually only resort to early binding things (like type
declarations and sub prototypes) when it changes the semantics in some
way.

Luke


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Thomas Sandla writes:
 Luke Palmer wrote:
 class CodeProxy {
 has Code $.code is rw;
 sub call ($a) {
 $.code($a);
 }
 }
 
 This is valid Perl 6,
 
 Hmm, a sub in a class? I guess that should be a method. OTOH a
 class is just a funny module, so might be OK. But that is the
 syntax realm.

Hey, no pointing out errors when I'm arguing! :-)

Yes, given a s/sub/method/ it is valid Perl 6. ;-).

As for the rest of this message, see my coming reply to Aaron's message,
which points out that we're beginning to talk past each other because
the original context has been lost.

Luke

 and anyone who says otherwise (because of type
 signatures) is changing the Perl philosophy too much to be taken
 seriously.  Now, tell me at compile time whether the call inside `call`
 is valid.
 
 Ups, before we start talking past each other: I think a type system
 is just a tool that reminds you to your declarations. No declarations,
 no reminder, it's that simple. I would like the typing of $.code as Code
 to be necessary to apply the .() invocation operator on it. The rest is
 deferred to runtime if that is what you want.
 
 And I'm completly unsure how much parrot and/or perl revert back into
 compile state when you bring in new source code at runtime. Or how
 much load time activity is needed for a byte code file.
 
 The question if instances of DoubleCodeProxy are subtypes of instances
 of CodeProxy boils down to the question if ($) : ($, +$) with : beeing
 the subtype relation. Is that the right siglet syntax? Since named-only
 parameters are optional the relation holds. This subtype relation allows:
 
 my CodeProxy $cp = DoubleCodeProxy.new; # needs DoubleCodeProxy : CodeProxy
 
 $cp.code = sub ($x, +$y = unknown) { say x = $x, y = $y };
 
 $cp.call( first, b = second ); # prints x = first, y = second
 $cp.call( one );  # prints x = one, y = unknown
 
 $t = $cp.code;
 
 $cp.code = sub () { say void };  # no problem, type is Code
 $cp.call( X ); # gives runtime error on closure in $.code
 
 $cp.code = $t;
 
 $cp.call(); # compile error: too few args
 $cp.call( 1, 2 ); # compile error: too many positional args
 $cp.blahh( 23 ); # compile error/warning: no such method declared
 
 method CodeProxy::blubber(: $z ) { ... }
 
 $cp.blubber( 42 ); # could die on ... at runtime if no .blubber autoloaded
 
 $cp.call( 1|2|3 ); # autothreads??? I leave that to Damian :)
 -- 
 TSa (Thomas Sandla)
 


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Aaron Sherman writes:
 What I do not think should be allowed (and I may be contradicting
 Larry here, which I realize is taking my life in my hands ;) is
 violating the compile-time view of the static type tree. 

That sentence is getting pretty C++-derived-like, which Perl is hardly
anymore.  We have to reorganize your brain a bit.  Let's pretend that
we're in Smalltalk instead of Java (no offense or compliment to
either--I'm just taking extremes).  

Types don't form a tree.  /Classes/ form a dag, which is, for all
intents and purposes, a tree.  But types are something very different.
There are three kinds of types:

* Roles (types with behavior)
* Subtypes (roles with value restriction)
* Classes (roles with an implementation specification)

In particular, subtypes can form very complex non-tree-like structures,
and structures which are not determinable by the compiler in the general
case (if they were, then we'd have Gdel's truth machine).  But that's
okay, because it all boils down to calling the subtype closures and
having those determine the implications of the structure, bypassing the
structure itself.

Let's step back into Perl 5 for a moment and pretend that objects are
just blessed hashes again.  If every object has some metadata stuffed
into that hash, then you could really factor all three of these types of
types into the subtype category.  Subtypes are something that you can't
really do any static analysis on.  That means that I can circumvent your
static view rule by doing exactly that: putting metadata on objects
and making every type a subtype.  But because the compiler has every
ability to do that for us, and might just be the way it does things, it
seems like we've just run in a big circle: outlawing something possible,
and then walking through a loophole to make it possible again.

 That is, you can load an object foo at run-time, without and
 interface definition, but it can't change the shape of the type tree
 or its existing interfaces. If it wants to do that, it has to provide
 an interface def (e.g. what an autoload module should be able to
 provide).
 
 Why? Because if you can do that, then this:
 
   my X $a;
   $a.m(1) = 1;
 
 ALWAYS has to work because you might have replaced X at run-time with a
 class that has a method m(int) is rw(), and the compiler must silently
 (perhaps with an optional warning) permit it.

And if X were defined as `Any where { $_.can('m') }`, then could you
still make that guarantee?  You could say no, we can't so that would be
an illegal code segment at compile time, then I ask that you consider
if X were defined as `Any where { $_.can('m')  $_.CLASS.m ~~ rw }`
(testing whether it has an rw m method... barring syntax).  You'd have
to say no there, too, because there's no way to tell what that opaque
codeblock is doing. 

 Please think carefully about how dynamic you want Perl 6 to be
 Dynamic is good, but there's such a thing as too much of a good thing.

We'd like Perl 6 to be as dynamic as Perl 5.

Luke


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Aaron Sherman writes:
 On Wed, 2005-03-30 at 13:53, Luke Palmer wrote:
 
  class CodeProxy {
  has Code $.code is rw;
  sub call ($a) {
  $.code($a);
  }
  }
 
  This is valid Perl 6, and anyone who says otherwise (because of type
  signatures) is changing the Perl philosophy too much to be taken
  seriously.  Now, tell me at compile time whether the call inside `call`
  is valid.
 
 It's valid because it's a function call on a code ref. In that case, the
 compiler has to hand your request off to the run-time to check the
 vtable of $.code. Clearly that's a special case. I may have missed
 context at the start, but are we worried about the special cases or the
 general case or the implications to the general case of the special
 cases?

Okay, now we're starting to talk past each other.  I /think/ Thomas
orignially suggested that we use type inference to determine whether to
lvalue cast an argument or not, which is what I got all worked up about.
I'm saying that you can't determine that kind of thing in general at
compile time.  I'm all for an optional strong type system, as long as it
remains optional and mixable (so static things and dynamic things can
play nicely together, whether the module is static and the user dynamic
or vice-versa).  

Luke


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Luke Palmer
Aaron Sherman writes:
  Please think carefully about how dynamic you want Perl 6 to be
   Dynamic is good, but there's such a thing as too much of a good thing.
  
  We'd like Perl 6 to be as dynamic as Perl 5.
 
 We'd think that is impossible. Perl 5 had full control of the
 run-time, Perl 6 does not. 

Like hell it doesn't.  Parrot is designed to support Perl 5.  

Perl 6 can do all the fancy stuff that Perl 5 did.  If the Perl 6
compiler runs in Parrot, then it can control Parrot as it compiles, and
reap information from that as it compiles.  Parrot can easily redefine
stuff on the fly and eval code at runtime.  I don't see what full
control of the run-time Perl 5 has that Perl 6 won't (if you have
something specific in mind, enlighten me please).

 What's more, Perl 6 introduces types, mmd, function signature
 overloading, operator overloading and a host of other features which,
 combined with the level of dynamism found in Perl 5 would seem to me
 to lead to a compiler which cannot assist the user in writing
 debuggable code.

You keep mentioning this thing debuggable code and saying that adding
dynamism impairs it.  I'd say that Perl 5 is debuggable; I can certainly
debug it.  The kinds of modules that I work on introduce types and mmd,
where Perl 5 already had operator overloading.  I don't understand how
adding dyanmism impairs debuggability[1].

The reason that types and MMD can be introduced into Perl 5 is because
it's so dynamic.  We, as language designers in 2005, can't possibly know
what will be to us as MMD is to perl 5, but we want module writers to be
able to implement it, whatever it is.

Sorry I'm getting so worked up here  It's just that in designing the
next generation of a language that I cherish for its dynamism and
freedom, I don't like the idea of restricting that in the interest of...
whatever the interest is in (I can't actually tell with this argument).

I think what Perl 6 can offer us over Perl 5 in terms of safety, on a
very feature-removed level, is much more comprehensive compile
information available to the program.  We could easily leave out the
static type system from Perl 6 (not that I actually want to do this),
and a module that implements it would be a heck of a lot easier to write
than a module that implements it in Perl 5.

Perl 6 gives you so many levels of control: lexical syntax control,
hooks for everything you can dream of, possibility of generating pure
parrot code inline, continuations (which help in writing a debugger),
that I can't fathom how this could less debuggable than Perl 5.  If you
want to see when something, anything at all, is happening, stick a
debugger hook in there.  The more static we make our language--the
less dynamic we allow it to be--the more debugging power we're taking
away from the programmer.  The lose of making things dynamic is that the
compiler can't make as many assumptions, but Perl 6 allows many ways to
tell it when it can make assumptions.  As chromatic said, the programmer
usually knows when the compiler can make assumptions better than the
compiler does anyway.

Whew...

Okay, how can I turn around my rant and make it say something
productive?  

I probably can't tonight.  Nice yelling at you. :-)

Luke

[1] It might in a traditional debugger, but we are free to write our
debugger in the extremely dynamic Perl 6, running it right alongside our
program with all of our introspection needs at hand.  If our debugger
isn't good enough, we have the tools to write a better one.  And for
people like me who don't use the perl debugger, but who prefer print
statements and Data::Dumper diagnostics, more dynamism implies more
debugging power, not less.


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Chip Salzenberg
According to Luke Palmer:
 [Perl 5] had to construct lvalues out of all arguments (for which
 that made sense) because the sub might modify them.

No, actually, that wasn't the reason.  Perl 5 passes all values by
implicit mutable reference because it's faster, not because it's
better.  I suspect Larry might have passed arguments by read-only
reference in Perl 5 as well, had he found a way to make it fast.
-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Thomas Sandlaß
Luke Palmer wrote:
Okay, now we're starting to talk past each other.  I /think/ Thomas
orignially suggested that we use type inference to determine whether to
lvalue cast an argument or not, which is what I got all worked up about.
Actually I was returning to the subject of co- or contravariance of
parametric types but trying to avoid these terms. I gave an example
how to get a Str into an Array of Int when you assume in general that
Array of Int : Array of Any. Which is reasonable only for reading
because the reader doesn't care of the type and Int is compatible with
such a reading. For writing you need the reverse relation because the
writer expects an array that accepts Ints and and Array of Any does
this. For a read-write Array both cases must hold, thus only type
equality is sound. So when the compiler knows about a 'is rw' trait
on a parameter and the type of an array---and it does so the latest
when the call is attempted, but that is not the compiler then---it
should reject the call!

I'm saying that you can't determine that kind of thing in general at
compile time.
Of course not, but the question is than just shifted to: do you want a
runtime exception when sub foo( @a is rw ) is called with an Array of Int?
If you answer no, than you take the consequence that this Array of Int
might contain other things than Ints. That's all.
There is no type inference per se in my argument. It just might help the
compiler to gather the necessary type information to ask the above question
at compile time.
Larry takes the point of view that the Str goes in but the Array knows
that it should be an Int and nicely converts that for you. And actually
Any might just be a glb (greatest upper bound) of Int and Str, written
Int|Str in Perl6, so the type checker knows that *this* case is OK.
But it will complain if Any isn't a glb of SomeOtherType and you call
foo with Array of SomeOtherType. Note that
  Int|Str : Str  Str : Int|Str  Int|Str : Int  Int : Int|Str
holds. Given an even more complex Any type that encompasses the general
purpose types of Perl6---namely Str, Int, Num, Bool and Refs thereof---
the lazy Perl6 programmer gets what Perl5 did all the time. This is
what is called Render the Illusion of Simplicity.
This illusion fades when you get the compile time warning no glb for
Any and SomeOtherType and you have to go figure what to do about it ;)
But once again these might hit a strong programmer and the not so strong
ones a kept in the illusion: look I just use SomeOtherType and it works.

I'm all for an optional strong type system, as long as it
remains optional and mixable (so static things and dynamic things can
play nicely together, whether the module is static and the user dynamic
or vice-versa).  
Optional in what sense?
--
TSa (Thomas Sandla)


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread Aaron Sherman
On Wed, 2005-03-30 at 17:09, Luke Palmer wrote: 
 Aaron Sherman writes:
  What I do not think should be allowed (and I may be contradicting
  Larry here, which I realize is taking my life in my hands ;) is
  violating the compile-time view of the static type tree. 
 
 That sentence is getting pretty C++-derived-like,

I think you mis-read what I wrote, and it was in a context that flowed
from previous messages. I was referring to the part of the type tree
(multi-root, directed, acyclical graph) which I had deemed to be
static for the sake of handling interfaces sanely at compile-time.
Hence the scary-quotes on static, as we were not in agreement on that
point.

 Please think carefully about how dynamic you want Perl 6 to be
  Dynamic is good, but there's such a thing as too much of a good thing.
 
 We'd like Perl 6 to be as dynamic as Perl 5.

We'd think that is impossible. Perl 5 had full control of the run-time,
Perl 6 does not. Even Ponie cannot truly be as dynamic as vanilla Perl
5.

What's more, Perl 6 introduces types, mmd, function signature
overloading, operator overloading and a host of other features which,
combined with the level of dynamism found in Perl 5 would seem to me to
lead to a compiler which cannot assist the user in writing debuggable
code.

I like Perl 5, but Perl 6 is not Perl 5... we have to be willing to
accept that there are trade-offs for the features we've added. One
possible trade-off is increased difficulty in debugging code. One
possible trade-off is slightly less dynamic code.

Your other message:

On Wed, 2005-03-30 at 17:15, Luke Palmer wrote:
 aron Sherman writes:

  It's valid because it's a function call on a code ref. In that case, the
  compiler has to hand your request off to the run-time to check the
  vtable of $.code. Clearly that's a special case. I may have missed
  context at the start, but are we worried about the special cases or the
  general case or the implications to the general case of the special
  cases?
 
 Okay, now we're starting to talk past each other.  I /think/ Thomas
 orignially suggested that we use type inference to determine whether to
 lvalue cast an argument or not, which is what I got all worked up about.
 I'm saying that you can't determine that kind of thing in general at
 compile time.  I'm all for an optional strong type system, as long as it
 remains optional and mixable (so static things and dynamic things can
 play nicely together, whether the module is static and the user dynamic
 or vice-versa).  

Ok, so let me start from that point and ask a question:

When the Perl 6 compiler sees:

my X $a;
$a.m(1);

What should it do?

Options:

  * Accept the method call regardless of the definition of X
  * Accept the method call if it matches the signature from X
  * Accept the method call if {magic($*INTERP)}

Not to be pushy or anything, but please pick one and if it's the last,
we can start to have a conversation about what that line-noise at the
end actually does. ;-)

-- 
Aaron Sherman [EMAIL PROTECTED]
Senior Systems Engineer and Toolsmith
It's the sound of a satellite saying, 'get me down!' -Shriekback



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-30 Thread chromatic
On Wed, 2005-03-30 at 18:35 -0500, Aaron Sherman wrote:

 When the Perl 6 compiler sees:
 
 my X $a;
 $a.m(1);
 
 What should it do?
 
 Options:
 
   * Accept the method call regardless of the definition of X
   * Accept the method call if it matches the signature from X
   * Accept the method call if {magic($*INTERP)}

That's a fair question, but I think you're leaving out several important
pieces of information:

* Where does $a come from?  (As far as I see, it's just an
uninteresting undef here, but I don't know if that's the point of the
code.)
* At what point in the program are you asking what the compiler sees?
* Where's the definition of X in relation to this code?
* What pragmas are in effect here?
* What other code may have altered the type definition of X or undef?

I don't think anyone can answer your question well without assuming some
answers to my questions.

-- c


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-29 Thread Thomas Sandlaß
Luke Palmer wrote:
So if you want things modified, you'd have to pass in a reference.
Arrays and hashes would not generally have this restriction, since we
pass references of those guys anyway.
But I would really like to see a declaration of any possible modification
in the interface of a sub. Otherwise you might find quite surprising things
in your array, or terribly miss things. So after calling a sub that takes
an array parameter the array argument should be in exactly the same state
as before the call! And any attempt to use modifying operations in the sub
should result in a compile time error. This is good for the optimizer as well.
I don't see the above as a restriction. There are easy ways to achieve
modifyable values by 'is copy' for temporary modifications in the sub and
'is rw' and 'is ref' for full access. But the caller clearly sees that in
the signature. And the typechecker might throw exceptions when type
safety can't be maintained through the sub call:
sub foo (@a is rw) { @a[7] = heaven } # type of  is Str
my Int @i;
foo( @i ); # type error/warning
foo( @i as Array of Any ); # programmer takes responsibility
foo( [EMAIL PROTECTED] ); # I'm not sure about that, but could be short of the 
above
--
TSa (Thomas Sandla)



Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-29 Thread Luke Palmer
Thomas Sandla writes:
 Luke Palmer wrote:
 So if you want things modified, you'd have to pass in a reference.
 Arrays and hashes would not generally have this restriction, since we
 pass references of those guys anyway.
 
 But I would really like to see a declaration of any possible modification
 in the interface of a sub. 

Of course.  We already have this.

 Otherwise you might find quite surprising things in your array, or
 terribly miss things. So after calling a sub that takes an array
 parameter the array argument should be in exactly the same state as
 before the call! And any attempt to use modifying operations in the
 sub should result in a compile time error. This is good for the
 optimizer as well.
 
 I don't see the above as a restriction. There are easy ways to achieve
 modifyable values by 'is copy' for temporary modifications in the sub
 and 'is rw' and 'is ref' for full access. But the caller clearly sees
 that in the signature.

Unless the caller can't see the signature, as is the case with methods.
That's the point of my thinking.  Perl 5 had a performance (and a slight
semantic) problem with this.  It had to construct lvalues out of all
arguments (for which that made sense) because the sub might modify them.
We'll still have to do that unless the rw-ness is marked somehow on
the caller's side.  

 And the typechecker might throw exceptions when type safety can't be
 maintained through the sub call:
 
 sub foo (@a is rw) { @a[7] = heaven } # type of  is Str
 
 my Int @i;
 
 foo( @i ); # type error/warning

Again, this can't be done unless you know the signature.  And in fact,
we can't do type inference on methods unless we do type inference
everywhere, which we can't do if we want an autoloader.

Luke


Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Chip Salzenberg
I'm working on enhancing Perl6::Subs[*] to support more parameter
traits than just Cis required.  I have some questions about
parameters and traits.  (These questions all apply to pure Perl 6,
which I know I won't be able to translate completely, but I want to
know which target I'm missing.)

 * Given a parameter CArray @a, it's obvious I'm not allowed to
   Cpush @a,1, because I didn't say Cis rw.  But am I allowed to
   C@a[0]++?  How about C@a[0][0]++?  How deep is read-only-ness?

 * Similarly, how deep is the copy implied by Cis copy?

 * Do traits attach syntactically to the variable name, or to the
   declaration as a whole?

 variable: @a is rw of Array
   Array @a is rw

 declaration:  @a of Array is rw
   Array @a is rw

 * As far as I can tell, the choice of spelling an array parameter
   CArray @a or CArray $a is entirely cosmetic: both @a and
   $a are capable of holding an Array reference.  Is there actually
   a difference, e.g. in how they handle an undefined value?


[*] Shameless Plug:  Perl6::Subs is a source filter that lets you use
much of the Perl 6 parameter syntax in your Perl 5 programs; and
it enforces many constraints for you.  You can even add your own
constraints with Cwhere BLOCK subtyping.  Amaze your enemies!
Confound your friends!  Use Perl6::Subs today!

-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Luke Palmer
Chip Salzenberg writes:
 I'm working on enhancing Perl6::Subs[*] to support more parameter
 traits than just Cis required.  I have some questions about
 parameters and traits.  (These questions all apply to pure Perl 6,
 which I know I won't be able to translate completely, but I want to
 know which target I'm missing.)
 
  * Given a parameter CArray @a, it's obvious I'm not allowed to
Cpush @a,1, because I didn't say Cis rw.  But am I allowed to
C@a[0]++?  How about C@a[0][0]++?  How deep is read-only-ness?

I believe that the default constant parameters is so we don't have to
construct lvalues out of our arguments when we call.  So that probably
means that it's very shallow.

On the language level, I've been thinking that it would be good to go
C's way and not allow any parameter modification whatsoever.  The
problem is that in the presence of methods, we can't tell whether we
have to lvaluize anymore, so we're back to the Perl 5 trap of lvaluizing
everything.  

So if you want things modified, you'd have to pass in a reference.
Arrays and hashes would not generally have this restriction, since we
pass references of those guys anyway.

  * Similarly, how deep is the copy implied by Cis copy?

I think it's exactly as deep as read-only-ness.

  * Do traits attach syntactically to the variable name, or to the
declaration as a whole?
 
  variable: @a is rw of Array
Array @a is rw
 
  declaration:  @a of Array is rw
Array @a is rw

Well, from this example it seems like `of` should be tighter than `is`.

  * As far as I can tell, the choice of spelling an array parameter
CArray @a or CArray $a is entirely cosmetic: both @a and
$a are capable of holding an Array reference.  Is there actually
a difference, e.g. in how they handle an undefined value?

Hmmm... well I think all scalars are allowed to be undef.  Arrays
aren't.  So yeah, if you give @a undef, it probably gives you [] (or
croaks, but I don't think that's a good idea).  If you give $a undef, it
gives you undef.

 [*] Shameless Plug:  Perl6::Subs is a source filter that lets you use
 much of the Perl 6 parameter syntax in your Perl 5 programs; and
 it enforces many constraints for you.  You can even add your own
 constraints with Cwhere BLOCK subtyping.  Amaze your enemies!
 Confound your friends!  Use Perl6::Subs today!

Cool.

Luke


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Rod Adams
Chip Salzenberg wrote:
* As far as I can tell, the choice of spelling an array parameter
  CArray @a or CArray $a is entirely cosmetic: both @a and
  $a are capable of holding an Array reference.  Is there actually
  a difference, e.g. in how they handle an undefined value?
 

Uhm... It was my impression that one of those creates an Array of 
Arrays, and the other just an Array. In other words, using @ instead of 
$ puts a Array of in front of the supplied type.

This makes sense when one considers orthogonality with CInt @a and 
CInt $a. But it's easy to get tripped up it.

-- Rod Adams
(Who needs more days in the week, so he can continue work on S29).


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Chip Salzenberg
According to Rod Adams:
 Chip Salzenberg wrote:
 * As far as I can tell, the choice of spelling an array parameter
   CArray @a or CArray $a is entirely cosmetic: both @a and
   $a are capable of holding an Array reference.  Is there actually
   a difference, e.g. in how they handle an undefined value?

 Uhm... It was my impression that one of those creates an Array of 
 Arrays, and the other just an Array.

Ah, my question had a bug.  What I meant was:

 * As far as I can tell, the choice of spelling an array parameter
   C@a or CArray $a is entirely cosmetic: both @a and $a are
   capable of holding an Array reference.  Is there actually a
   difference, e.g. in how they handle an undefined value?

-- 
Chip Salzenberg- a.k.a. -[EMAIL PROTECTED]
 Open Source is not an excuse to write fun code
then leave the actual work to others.


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Larry Wall
On Sat, Mar 26, 2005 at 03:45:30PM -0500, Chip Salzenberg wrote:
: According to Rod Adams:
:  Chip Salzenberg wrote:
:  * As far as I can tell, the choice of spelling an array parameter
:CArray @a or CArray $a is entirely cosmetic: both @a and
:$a are capable of holding an Array reference.  Is there actually
:a difference, e.g. in how they handle an undefined value?
: 
:  Uhm... It was my impression that one of those creates an Array of 
:  Arrays, and the other just an Array.
: 
: Ah, my question had a bug.  What I meant was:
: 
:  * As far as I can tell, the choice of spelling an array parameter
:C@a or CArray $a is entirely cosmetic: both @a and $a are
:capable of holding an Array reference.  Is there actually a
:difference, e.g. in how they handle an undefined value?

Not really.  The main difference is that @a will flatten in a list
context, and $a won't.

That being said, in Perl 5, if you say

@a = undef;

you don't get an undefined array.  I'd like to make undef smart enough
about list contexts that @a actually does end up undefined in Perl 6.
That is, in scalar context, undef is a scalar value as in Perl 5, but
in Perl 6, undef in list context means there isn't anything here if
you try to look for it, so it's more like () in Perl 5, except that
it also undefines the array if it's the only thing in the array.

I don't know if that's an entirely consistent semantics, but I'd rather
have a little inconsistency and preserve error informaiton for later
debugging whenever possible, and that undef you tried to initialize the
array with might have some interesting commentary in it.  (Though, of
course, my example above is a rather boring value of undef.)

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Larry Wall
On Sat, Mar 26, 2005 at 03:13:07AM -0700, Luke Palmer wrote:
: Chip Salzenberg writes:
:  I'm working on enhancing Perl6::Subs[*] to support more parameter
:  traits than just Cis required.  I have some questions about
:  parameters and traits.  (These questions all apply to pure Perl 6,
:  which I know I won't be able to translate completely, but I want to
:  know which target I'm missing.)
:  
:   * Given a parameter CArray @a, it's obvious I'm not allowed to
: Cpush @a,1, because I didn't say Cis rw.  But am I allowed to
: C@a[0]++?  How about C@a[0][0]++?  How deep is read-only-ness?
: 
: I believe that the default constant parameters is so we don't have to
: construct lvalues out of our arguments when we call.  So that probably
: means that it's very shallow.
: 
: On the language level, I've been thinking that it would be good to go
: C's way and not allow any parameter modification whatsoever.  The
: problem is that in the presence of methods, we can't tell whether we
: have to lvaluize anymore, so we're back to the Perl 5 trap of lvaluizing
: everything.  

I think only predeclared simple subs are allowed to have rw parameters.
Methods can have is ref parameters, but those don't require enforced
lvaluehood on the caller end like rw does.

: So if you want things modified, you'd have to pass in a reference.
: Arrays and hashes would not generally have this restriction, since we
: pass references of those guys anyway.

Yes.

:   * Similarly, how deep is the copy implied by Cis copy?
: 
: I think it's exactly as deep as read-only-ness.

And both may be exactly as deep as COW.

:   * Do traits attach syntactically to the variable name, or to the
: declaration as a whole?
:  
:   variable: @a is rw of Array
: Array @a is rw
:  
:   declaration:  @a of Array is rw
: Array @a is rw
: 
: Well, from this example it seems like `of` should be tighter than `is`.

Traits are not allowed on ordinary rvalues, only on declarations.  is
traits always attach to the main declaration.  of types always attach
to the container on their immediate left.

:   * As far as I can tell, the choice of spelling an array parameter
: CArray @a or CArray $a is entirely cosmetic: both @a and
: $a are capable of holding an Array reference.  Is there actually
: a difference, e.g. in how they handle an undefined value?
: 
: Hmmm... well I think all scalars are allowed to be undef.  Arrays
: aren't.  So yeah, if you give @a undef, it probably gives you [] (or
: croaks, but I don't think that's a good idea).  If you give $a undef, it
: gives you undef.

As I mentioned in my other message, I think we should not assume that
Perl 6 works the same in this regard as Perl 5 does.  There needs to be
something we can return that not only means (), but means also means
You're hosed! (And here's why.)  And I think we can make undef mean
that if we make it lazily sensitive to scalar/list context (much like @a
itself can be lazily sensitive to context).

Hmm, maybe it would simpler to just tell everyone undef is a special empty
lazy array that refuses to produce a value no matter how you ask.

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Uri Guttman
 LW == Larry Wall [EMAIL PROTECTED] writes:

  LW That being said, in Perl 5, if you say

  LW @a = undef;

  LW you don't get an undefined array.  I'd like to make undef smart enough
  LW about list contexts that @a actually does end up undefined in Perl 6.
  LW That is, in scalar context, undef is a scalar value as in Perl 5, but
  LW in Perl 6, undef in list context means there isn't anything here if
  LW you try to look for it, so it's more like () in Perl 5, except that
  LW it also undefines the array if it's the only thing in the array.

then how would you assign undef to the only element of the array? would this
be needed:

@a = ( undef ) ;# same as p5?

vs.
@a = undef ;# like undef @a in p5?

i have always railed against undef on aggregates as it leads to using
defined on them which is not the same as checking if an aggregate has
any elements. i see that often in newbie code. in fact i would like to
stop allowing undef as a function with args and have it only return a
scalar undef value. there should be a different op to truly make an
aggregate undefined (and i still don't see a need for that, emptying it
is all that i ever think is needed).

in my world undef is a scalar value and nothing else. how do you see it
in p6?

uri

-- 
Uri Guttman  --  [EMAIL PROTECTED]   http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs    http://jobs.perl.org


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Uri Guttman
 LW == Larry Wall [EMAIL PROTECTED] writes:

  LW As I mentioned in my other message, I think we should not assume that
  LW Perl 6 works the same in this regard as Perl 5 does.  There needs to be
  LW something we can return that not only means (), but means also means
  LW You're hosed! (And here's why.)  And I think we can make undef mean
  LW that if we make it lazily sensitive to scalar/list context (much like @a
  LW itself can be lazily sensitive to context).

  LW Hmm, maybe it would simpler to just tell everyone undef is a special empty
  LW lazy array that refuses to produce a value no matter how you ask.

why use undef for the error code? isn't this what exceptions are for? or
setting $!? i actually use naked return as a postive thing in stem
(string return values are bad and have the error string. it is
consistant so it works). the problem with returning undef (or naked
return) is that it is in-band data. now you could do a naked return but
error thing. and then the called has to check for that property each
time. but what does that mean when you do this (bad p6 code):

sub return_error { return but error }
my @a = return_error() ;

is @a empty or what? how do you see the error in @a?

i just don't like seeing undef used for error handling as it has too
many other uses (even if i did it in stem). just make undef a scalar
value and not a function nor a error marker.

uri

-- 
Uri Guttman  --  [EMAIL PROTECTED]   http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs    http://jobs.perl.org


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Larry Wall
On Sun, Mar 27, 2005 at 12:04:39AM -0500, Uri Guttman wrote:
:  LW == Larry Wall [EMAIL PROTECTED] writes:
: 
:   LW As I mentioned in my other message, I think we should not assume that
:   LW Perl 6 works the same in this regard as Perl 5 does.  There needs to be
:   LW something we can return that not only means (), but means also means
:   LW You're hosed! (And here's why.)  And I think we can make undef mean
:   LW that if we make it lazily sensitive to scalar/list context (much like @a
:   LW itself can be lazily sensitive to context).
: 
:   LW Hmm, maybe it would simpler to just tell everyone undef is a special 
empty
:   LW lazy array that refuses to produce a value no matter how you ask.
: 
: why use undef for the error code?

Because there's usually a reason why the undef was created, and it would
be useful for the user to learn that.

: isn't this what exceptions are for?

Undef is a form of unthrown exception.  Throwing things is often too
violent for fail-soft situation.

: or setting $!?

$! is the current unthrown exception in Perl 6.  (Or actually, it's also
the thrown exception inside a CATCH block.)

: i actually use naked return as a postive thing in stem
: (string return values are bad and have the error string. it is
: consistant so it works).

Okay, so in this case you could hack around the problem because you don't
want to return interesting good values.  But sometimes you have both
interesting good values and interesting bad values.  Interesting values
of undef solves that problem without having to send either the good data
or the bad data out of band.

: the problem with returning undef (or naked
: return) is that it is in-band data. now you could do a naked return but
: error thing. and then the called has to check for that property each
: time.

You should be checking your return values anyway, or useing fatal, which
turns these unthrown exceptions into thrown ones.

: but what does that mean when you do this (bad p6 code):
: 
:   sub return_error { return but error }

That's written:

sub return_error { fail What went wrong }

which has the effect of

sub return_error { return undef but Exception(What went wrong) }

unless the caller uses fatal, in which case it's more like

sub return_error { die(What went wrong) }

:   my @a = return_error() ;
: 
: is @a empty or what? how do you see the error in @a?

I am proposing that assigning a exceptional undef value (such
as that returned by fail() above) to an array causes the array to
become undefined.  If you use that array somewhere else, it's as if
you used the original unthrown exception.  Eventually you get caught
trying to do something defined with the undefined value and you get
a nice message out saying where the original undefined value came from.

: i just don't like seeing undef used for error handling as it has too
: many other uses (even if i did it in stem).

I don't see how the proposed semantics interfere with any other uses of
undef.  A bare scalar undef is still a very simple value.  I don't see
how you can simultaneously argue that it has many uses and yet has only
one simple value.

: just make undef a scalar value and not a function nor a error marker.

fail(Language designer not persuaded);# :-)

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Larry Wall
On Sat, Mar 26, 2005 at 11:57:48PM -0500, Uri Guttman wrote:
:  LW == Larry Wall [EMAIL PROTECTED] writes:
: 
:   LW That being said, in Perl 5, if you say
: 
:   LW @a = undef;
: 
:   LW you don't get an undefined array.  I'd like to make undef smart enough
:   LW about list contexts that @a actually does end up undefined in Perl 6.
:   LW That is, in scalar context, undef is a scalar value as in Perl 5, but
:   LW in Perl 6, undef in list context means there isn't anything here if
:   LW you try to look for it, so it's more like () in Perl 5, except that
:   LW it also undefines the array if it's the only thing in the array.
: 
: then how would you assign undef to the only element of the array? would this
: be needed:
: 
:   @a = ( undef ) ;# same as p5?
: 
: vs.
:   @a = undef ;# like undef @a in p5?

Those would do the same thing under the current proposal, since
they're both in list context.  If you really, really want a scalar
undef value in list context, you could always say

@a = scalar(undef);

: i have always railed against undef on aggregates as it leads to using
: defined on them which is not the same as checking if an aggregate has
: any elements. i see that often in newbie code.

Well, let's not confuse Perl 5's shortcomings with Perl 6's.  I think
we should fix the problem by making undef work a little more like the
newbie expects, which is context dependent.

: in fact i would like to
: stop allowing undef as a function with args and have it only return a
: scalar undef value. there should be a different op to truly make an
: aggregate undefined (and i still don't see a need for that, emptying it
: is all that i ever think is needed).

We could certainly split out a separate undefine() function.  We could
even give it an optional argument that says *why* it's undefined, turning
it into an unthrown exception, basically.  We could use such a function
to create interesting values of undef that are context sensitive.

: in my world undef is a scalar value and nothing else. how do you see it
: in p6?

undef is not a scalar value, it is the explicit *absence* of a value
where you expected one.  In Perl 6, undef is the Bearer of Bad News.

If you merely want undef for a scalar placeholder without negative
connotations, I'd suggest something like

class Empty {}
my $nada = new Empty;

instead.  And $nada is the same length as undef.  $X would be even
shorter.

On the other hand, Perl 6 is consistently returning booleans as
0 and 1 rather than  and 1, so it's likely that constant 0 and 1
can be stored in less than a bit, as it were.  So there might even
be some kind of zero type that's essentially a value that's always 0,
and takes no room to store at all.  That might serve as a pretty good
neutral placeholder.

Larry


Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?

2005-03-26 Thread Uri Guttman
 LW == Larry Wall [EMAIL PROTECTED] writes:

  LW : then how would you assign undef to the only element of the
  LW array? would this : be needed:

  LW : 
  LW : @a = ( undef ) ;# same as p5?
  LW : 
  LW : vs.
  LW : @a = undef ;# like undef @a in p5?

  LW Those would do the same thing under the current proposal, since
  LW they're both in list context.  If you really, really want a scalar
  LW undef value in list context, you could always say

  LW @a = scalar(undef);

that works. i am starting to see what you mean by undef knowing about
context.

  LW : in fact i would like to
  LW : stop allowing undef as a function with args and have it only return a
  LW : scalar undef value. there should be a different op to truly make an
  LW : aggregate undefined (and i still don't see a need for that, emptying it
  LW : is all that i ever think is needed).

  LW We could certainly split out a separate undefine() function.  We could
  LW even give it an optional argument that says *why* it's undefined, turning
  LW it into an unthrown exception, basically.  We could use such a function
  LW to create interesting values of undef that are context sensitive.

that split makes sense as you are now using undef as a special (or as
you say below unexpected) value. so it shouldn't also be overloaded as a
function operating on variables. just doing the split will make me
happier (if you are so benevolent as to care about my happiness :).

  LW : in my world undef is a scalar value and nothing else. how do you see it
  LW : in p6?

  LW undef is not a scalar value, it is the explicit *absence* of a value
  LW where you expected one.  In Perl 6, undef is the Bearer of Bad News.

oy! i feel the pain of the late night phone call. :)

uri

-- 
Uri Guttman  --  [EMAIL PROTECTED]   http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs    http://jobs.perl.org