Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-14 Thread Erik Steven Harrison
 
--

On Fri, 14 Mar 2003 10:08:15  
 Larry Wall wrote:
>On Thu, Mar 13, 2003 at 07:36:00PM -0800, Brent Dax wrote:
>: I think that there should be two types of arg typing[1]: 'strict' and
>: 'loose'.  Strict arg typing doesn't coerce, except to turn subclasses
>: into superclasses; loose arg typing, on the other hand, coerces whenever
>: possible.  The mechanism for choosing between strict and loose arg
>: typing should be under the caller's control, not the callee's.  (The
>: callee decides what types they want, and the caller decides how to
>: create those types.  This seems consistent with Perl's philosophy of
>: being flexible and making B&D optional.)
>
>Precisely.  The parameter types are completely invariant for the
>callee.  They are optionally invariant for the caller depending on some
>kind of stricture.  But I darn well want the naive user to be able to
>pass a Scalar to an Int parameter and have it DWTM without them knowing
>a blessed thing about these mysterious entities called "classes".
>
>We've got to keep the entry ramp low, or Perl is no longer Perl.
>
>The real question is whether this particular stricture is part of the
>default "use strict" that classes and modules assume.  There are
>decent arguments on both sides of that one, but just to mollify Damian
>I'm inclined to come down on the strict side for that.
>

I'll put my vote down on strictness (as in "complain about mismatch 
as soon as possible") by default.


But just as prototypes are ignored when we prepend & in Perl 5 can't 
some similar frobobnitz say "But on this here call, wait till runtime 
and coerce if needed"? After all, it's not the kind of thing a callee 
should dictate, but the caller.


>This week.  :-)

I'm easy.

-Erik
>
>Larry
>



Get 25MB of email storage with Lycos Mail Plus!
Sign up today -- http://www.mail.lycos.com/brandPage.shtml?pageId=plus 


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-14 Thread Larry Wall
On Thu, Mar 13, 2003 at 07:36:00PM -0800, Brent Dax wrote:
: I think that there should be two types of arg typing[1]: 'strict' and
: 'loose'.  Strict arg typing doesn't coerce, except to turn subclasses
: into superclasses; loose arg typing, on the other hand, coerces whenever
: possible.  The mechanism for choosing between strict and loose arg
: typing should be under the caller's control, not the callee's.  (The
: callee decides what types they want, and the caller decides how to
: create those types.  This seems consistent with Perl's philosophy of
: being flexible and making B&D optional.)

Precisely.  The parameter types are completely invariant for the
callee.  They are optionally invariant for the caller depending on some
kind of stricture.  But I darn well want the naive user to be able to
pass a Scalar to an Int parameter and have it DWTM without them knowing
a blessed thing about these mysterious entities called "classes".

We've got to keep the entry ramp low, or Perl is no longer Perl.

The real question is whether this particular stricture is part of the
default "use strict" that classes and modules assume.  There are
decent arguments on both sides of that one, but just to mollify Damian
I'm inclined to come down on the strict side for that.

This week.  :-)

Larry


Re: Huffman coding (Was: Re: A6: Strict signature checking - was: Complex Parameter Types)

2003-03-14 Thread Larry Wall
On Thu, Mar 13, 2003 at 10:52:04PM +0100, Anton Berezin wrote:
: On Thu, Mar 13, 2003 at 10:21:25PM +1100, Damian Conway wrote:
: 
: > By distinguishing a parameter that *requires* a particular type, from
: > a parameter that *ensures* a particular type (by coercion if
: > necessary). I've suggested that using C semantics should
: > indicate "make whatever I'm actually given into one of these, if you
: > can", whereas reference semantics say "this must already be one of
: > these" (by their very nature, since an aliased parameter *is* the
: > argument).
: 
: It looks like a lot of people is going to use "is copy" a lot.  Correct
: me if I am wrong, but I see the default "is constant" trait largely as a
: speed optimization.  Would not it be more correct from the point of view
: of good Huffman coding, that "is copy" is made the default, and let the
: module authors and large project implementors to bother with "is
: constant" when they deem it necessary?  After all, this will be a small
: added burden for folks who go the "type and trait everything" route.  An
: extra bonus of making "is copy" the default would be the ability to
: modify a parameter locally (Huffman coding again here for short program
: writers).

Well, at minimum there could certainly be a "use sig copy" pragma or
some such.  But I don't think "is copy" will be used all that much if
we set up "is constant" with the right semantics in the first place,
which is that it can do a copy of basic types if it feels like it.
It's only "is rw" or "is ref" that really require reference semantics,
and then we're talking proxies if we want any coercion.

Larry


Huffman coding (Was: Re: A6: Strict signature checking - was: Complex Parameter Types)

2003-03-14 Thread Anton Berezin
On Thu, Mar 13, 2003 at 10:21:25PM +1100, Damian Conway wrote:

> By distinguishing a parameter that *requires* a particular type, from
> a parameter that *ensures* a particular type (by coercion if
> necessary). I've suggested that using C semantics should
> indicate "make whatever I'm actually given into one of these, if you
> can", whereas reference semantics say "this must already be one of
> these" (by their very nature, since an aliased parameter *is* the
> argument).

It looks like a lot of people is going to use "is copy" a lot.  Correct
me if I am wrong, but I see the default "is constant" trait largely as a
speed optimization.  Would not it be more correct from the point of view
of good Huffman coding, that "is copy" is made the default, and let the
module authors and large project implementors to bother with "is
constant" when they deem it necessary?  After all, this will be a small
added burden for folks who go the "type and trait everything" route.  An
extra bonus of making "is copy" the default would be the ability to
modify a parameter locally (Huffman coding again here for short program
writers).

=Anton.


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Dave Whipp
Damian Conway wrote:
b) The argument passed here must be something that will definitely
   not cause the program to crash and burn, and we'll verify 
that at
   compile-time.

I'm arguing that the former is well-nigh useless, and that the latter is 
what large systems developers and optimizer writers have been begging 
for. Besides which, the latter gives you the former. If you don't care 
about compile-time type checking, declare the *parameter* as Scalar, and 
let it accept anything.
Module writers should always write their code to high standards of 
safety. Client code, OTOH, should be able to be more sloppy -- 
especially for one-liners. But I agree that (b) should be the goal: I 
agree run-time type checking is "well-nigh useless".

But, the definition of compile-time checking can be broad. Firstly, we 
should distinguish between things that are explicitly typed, and things 
that are not. If a user does not specify the type of a value, then the 
compiler should make a best-effort attempt to infer the type from what 
it does know. e.g.

  sub foo () returns Int { 6 }
  sub bar (Int $a) { print $a+1 }
  ...
  my $a = foo;
  bar($a);
In this case, the user has chosen not to give an explicit type to $a, 
but a trivial dataflow analysis will determine that type. The default 
mode (in non-strict contexts) should be to infer the type.

I just re-read A1, the RFC:16 discussion. Larry seems to say that, 
outside of class definitions, strictness will not be the default. Such 
code is never very large (well, OK, I've seen some bad scripts: but hard 
cases make bad law), so we can afford to let the compiler do some work 
to do all the necessary inference ... and even insert coercion code if 
necessary. If performance becomes an issue, then the script writer will 
clean up the code.

A quick list of the possible cases -- the compiler might determine (via 
type inference) that a binding is:

  definitely not safe: can't even be coerced -- always an error
  definitely safe, no corercion needed -- always OK
  definitely safe if we corerce -- OK in non-strict contexts
  undecidable -- error in strict contexts, else compile-time warning
Which brings us back to the question of what is coercable. I'd say that 
we should only permit implicit coercion where a user has not used 
explicit typing; but there should be a simple prefix operator to enable 
coercion of typed things. Perhaps the "splat" operator could serve here:

  my Str $a = <>;
  my Int $b = $a;# Error -- $a is explicitly typed as Str
  my Int $c = $a.num # OK -- explicit corcion
  my Int $d = *$a;   # OK -- splat permits implicit coercion
Dave.
--
http://dave.whipp.name


RE: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Brent Dax
Damian Conway:
#   a) The argument passed here must be something that 
# could conceivably
# not cause the program to crash and burn, and 
# we'll verify that at
#  run-time if necessary.
# 
# or:
# 
#   b) The argument passed here must be something that will 
# definitely
# not cause the program to crash and burn, and 
# we'll verify that at
#  compile-time.
# 
# I'm arguing that the former is well-nigh useless, and that 
# the latter is what 
# large systems developers and optimizer writers have been 
# begging for. Besides 
# which, the latter gives you the former. If you don't care 
# about compile-time 
# type checking, declare the *parameter* as Scalar, and let it 
# accept anything.

IMO, the semantics should be something like this:

Assume F is the type of the formal parameter and A is the type
of the actual parameter.
If A isa F, we're fine.
If F isa A, defer type checking to runtime.
Else, pitch a fit.

Since the default type is Object and any type isa Object, untyped formal
parameters are "checked" at compile time and untyped actual parameters
are checked at runtime.

That's the semantics for strict typing, anyway...

# But if type-specialized parameters are allowed to take 
# *anything*, then 
# they're nigh on worthless, except as a (third) coercion 
# mechanism (in addition 
# to explicit int($x), +$x, ~$x; and implicit contextual coercions).

What's wrong with that?  It gives us a way to ensure that we have a
suitable object without having to remember to check ourselves.

I think that there should be two types of arg typing[1]: 'strict' and
'loose'.  Strict arg typing doesn't coerce, except to turn subclasses
into superclasses; loose arg typing, on the other hand, coerces whenever
possible.  The mechanism for choosing between strict and loose arg
typing should be under the caller's control, not the callee's.  (The
callee decides what types they want, and the caller decides how to
create those types.  This seems consistent with Perl's philosophy of
being flexible and making B&D optional.)

Strict arg typing should be under the control of the 'strict' pragma,
and should be in strict's default export list.  This would mean that the
B&D would be off by default but easy to turn on.

[1] Perhaps this should be generalized to strict and loose coercion; I'm
not really sure yet.  (Under strict coercion, adding an Int and a Str
would be an error, instead of coercing the Str into an Int.)

--Brent Dax <[EMAIL PROTECTED]>
@roles=map {"Parrot $_"} qw(embedding regexen Configure)

>How do you "test" this 'God' to "prove" it is who it says it is?
"If you're God, you know exactly what it would take to convince me. Do
that."
--Marc Fleury on alt.atheism



Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Damian Conway
Larry Wall wrote:

On Thu, Mar 13, 2003 at 10:21:25PM +1100, Damian Conway wrote:
: But if I say:
: 
: 	sub foo(@a is Array of Int) {...}
: 	...
: 	foo(@x);
: 
: then I'm saying: "within &foo, @a is just another name for @x". So they are 
: (temporarily) the same thing. That can only (be allowed to) happen if the 
: actual type of @x satisfies all the requirements of the declared type of @a.

Which condition holds if @x is an array of Scalar!  Because a Scalar
polymorphically supports the Int, Num, Str, and Ref interfaces.
Err, sorry, no it doesn't.

Either Scalar is the superclass of those four, in which case a Scalar isn't
sufficient to satisfy the requirements of an Int; or Scalar is a disjunction 
of those four, in which case it's still not guaranteed that whatever the 
Scalar is holding will satisfy the requirements of an Int.

As I said before it comes down to whether a parameter type is a specification 
that:

a) The argument passed here must be something that could conceivably
   not cause the program to crash and burn, and we'll verify that at
   run-time if necessary.
or:

b) The argument passed here must be something that will definitely
   not cause the program to crash and burn, and we'll verify that at
   compile-time.
I'm arguing that the former is well-nigh useless, and that the latter is what 
large systems developers and optimizer writers have been begging for. Besides 
which, the latter gives you the former. If you don't care about compile-time 
type checking, declare the *parameter* as Scalar, and let it accept anything.

But if type-specialized parameters are allowed to take *anything*, then 
they're nigh on worthless, except as a (third) coercion mechanism (in addition 
to explicit int($x), +$x, ~$x; and implicit contextual coercions).

Damian



Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Paul
> I don't see a problem.  Scalar == Int|Num|Str|Ref, so
> Scalar.isa("Int").

Scalar.isa("Int") && Int.isa("Scalar") 



__
Do you Yahoo!?
Yahoo! Web Hosting - establish your business online
http://webhosting.yahoo.com


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Larry Wall
On Thu, Mar 13, 2003 at 11:31:30AM -0800, Austin Hastings wrote:
: "Everyone Knows" that an Int is a Scalar, and therefore a sub that has
: a Scalar parameter can safely be passed an Int. This is normal.
: 
: What I want is the ability to do the opposite: Silence the warning that
: occurs when I pass a Scalar to a sub expecting an Int.

I don't see a problem.  Scalar == Int|Num|Str|Ref, so Scalar.isa("Int").

Larry


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Austin Hastings

--- Damian Conway <[EMAIL PROTECTED]> wrote:
> Austin Hastings wrote:
> 
> > But what's the vision for p6? 
> > 
> > My expectation is that the type-checking stuff will be heavily used
> > for:
> > 
> > 1- Large scale projects.
> > 
> > 2- CPAN modules.
> > 
> > I expect that the folks who want to do one-liners will still want
> to be
> > able to say C
> > 
> > So the "strict" bits have to be forgiving of the "non-strict"
> callers.
> 
> To me that's a contradiction in terms. Strictness can't be
> "forgiving". At the risk of stating the obvious, that's the 
> whole point of strictness: to be strict.

Of course strictness can be forgiving. That's why the "Insert Coin"
slots on soda machines have a beveled slot -- they expect the user to
be a little uncoordinated, but once inside it's going to be all
by-the-book.


> 
> What we're suggesting is that if you want to be non-strict, don't use
> types. After all, they're optional.
> 
> "But," (I hear you say), "I may not have a choice! If the Cruel
> Module Author chose to use types, then I'm forced to do so too. 
> That's not Lazy."
> 
> And you're right. The module author gets to determine the interface
> of their module. And if they determine that that interface will
> provide type-safety, then you have to respect that. Just as if 
> they decided that it would have an OO interface, or would set 
> PRE and POST conditions on calls, or would only take named 
> arguments.
> 
> Because the author of the module is *relying* on that interface to
> ensure the correctness of their code; to prevent inappropriate data
> being passed to their subroutines. Typing is yet another way in 
> which they can relax, knowing that the wrong type of data will be
> headed off at the (compiler) pass.
>

But this isn't really true, is it? When you come down to cases, you can
construct a case wherein the wrong type of data gets coerced into the
"round hole" in every language.

sub foo($a is Int);

my $line = "Hello, World";
my Int $i ::= $line;

foo($i);   # Compiles okay, doesn't work.

So the module author is relying on the module user to make sure that
the intent of the interface is satisfied. The type bits are there to
help them communicate, and the let the compiler jab the willing user in
the ribs when he goofs.

> > To me, the way around this is NOT to force interface contracts down
> to
> > some lowest common denominator, but rather to document what is
> > expected, and then allow the developer to accept responsibility for
> > stepping on his crank.
> 
> Yep. And the way for the client of some module to accept that
> responsibility 
> is to put in an explicit conversion.

This statement gives me the heebie-jeebies.

Perl5 ==[*]= Java/C

extern long factorial(int);
char buf [BUFMAX];

while (gets(buf))
{
  if (want_fact())
  {
int i;

i = atoi(buf);
printf("%ld", factorial(i));
  }
}

Versus:

use Math qw(factorial(Int $));
my $line;

while ($line = <>)
{
  if (want_fact())
  {
my Int $i = $line;   # Or do I need C ?
print factorial($i);
  }
}


Say it ain't so, Joe!


> > If you say, "Give me an Array of Hash of (String => Array of
> BigNum)"
> > and I say, "Here's an Array of Scalars. They're OK, I promise" and
> > things "gang agley", it's my fault. I can deal with that.
> 
> But large projects -- where typing will be most important -- *can't*
> deal with that. That's the point of typing: to specify and enforce 
> interface contracts. At compile-time if at all possible.


The large project folks will have the standard C at the top of their files, so no problem.


> > But at the bottom, the C++ problem is a problem of its own making
> > -- people want coercion. Just like me. I want coercion. I want 
> > the ability to take advantage of the really nifty, carefully 
> > written code available from dedicated, rigorous hackers like 
> > this Conway fellow. But I want to do it as a slap-dash hack 
> > with no thought given to type stuff. How?

> By distinguishing a parameter that *requires* a particular type, 
> from a parameter that *ensures* a particular type (by coercion 
> if necessary). I've suggested that using C semantics 
> should indicate "make whatever I'm actually given into one of 
> these, if you can", whereas reference semantics say "this must
> already be one of these" (by their very nature, since an 
> aliased parameter *is* the argument).

Hmm. Granted that references must be basically correct when you use
them, there's really two cases here:

1- I give you something that's just wrong, but convertible. Example:
Array of int/Int.

In this case, I'm not sure that 

2- I give you something that I know is right, but I don't have all the
type fluff attached. Example: Int/Scalar.

In this case, the data is essentially right, and I need a way to tell
the typechecker: Hey, I'm right! Shaddap.

Consider the case of an XML datastore:







When I C, it's going to give me a {Hash of String =>
Array of Scalar} or maybe {

Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Larry Wall
On Thu, Mar 13, 2003 at 06:28:00PM +0100, Angel Faus wrote:
: 
: Damian Conway wrote:
: > But large projects -- where typing will be most important --
: > *can't* deal with that. That's the point of typing: to specify and
: > enforce interface contracts. At compile-time if at all possible.
: 
: One quick question about this. If I write:
: 
:   sub foo (Bar $f) {..}
: 
:   my $x = some_function_that_returns_bar();
:   foo($x);
: 
: Will this fail because the compiler _requires_ that the type be known 
: at compile-time, or will it work because it will the delay the 
: type-checking until run-time?

In the absence of a pragma to the contrary, type checking will be done
at run time when the type can't be determined at compile time.  But
surely the S&M&B&D types will create a pragma that requires the type
to be known at compile time.

larry


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Larry Wall
On Thu, Mar 13, 2003 at 10:21:25PM +1100, Damian Conway wrote:
: But if I say:
: 
:   sub foo(@a is Array of Int) {...}
:   ...
:   foo(@x);
: 
: then I'm saying: "within &foo, @a is just another name for @x". So they are 
: (temporarily) the same thing. That can only (be allowed to) happen if the 
: actual type of @x satisfies all the requirements of the declared type of @a.

Which condition holds if @x is an array of Scalar!  Because a Scalar
polymorphically supports the Int, Num, Str, and Ref interfaces.

Larry


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Angel Faus

Damian Conway wrote:
> But large projects -- where typing will be most important --
> *can't* deal with that. That's the point of typing: to specify and
> enforce interface contracts. At compile-time if at all possible.

One quick question about this. If I write:

  sub foo (Bar $f) {..}

  my $x = some_function_that_returns_bar();
  foo($x);

Will this fail because the compiler _requires_ that the type be known 
at compile-time, or will it work because it will the delay the 
type-checking until run-time?

-angel



Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Larry Wall
On Thu, Mar 13, 2003 at 10:21:25PM +1100, Damian Conway wrote:
: But what we can't allow is a reference parameter to coerce its argument. 
: For example:
: 
:   sub loggedincr (Int $i is rw) {
:   print $log: "Incremented $i.id()\n";
:   $i++ unless $i.constant;
:   }
: 
:   # and later...
: 
:   int $x = 7;
:   loggedincr($x);
: 
: The $i parameter *can't* be bound to $x, because $x doesn't have the 
: necessary features to be an Int (e.g. it doesn't have the capacity to 
: respond to method or property lookups).

But we've already said that an int will try to behave like an Int
as much as it can, including calling methods on it as if it were
an Int.  The "int" is just a hint that you'd like compact storage
and fast loops  And it's probably a stronger hint on an array than
on a solitary scalar.

: Even wrapping $x in a temporary Int 
: wouldn't help, since it would render the logging of an .id meaningless. The 
: whole point of having types is to catch this kind of problem at 
: compile-time.

A proxy Int could certainly calculate its id from the location of the
actual int, if it came down to it, so that different proxy Ints have
the same id.  And if the outer scope establishes the proxy Int at the
same time as it allocates the int, there will only be one of it anyway.

And we'd only need to create the proxy if we know we might be passing it
to an C parameter somewhere.  C parameters on Int, Num, Str
and Ref should be free to implement themselves with copy semantics anyway.
If you want to take a ref to a parameter, you'll have to declare it C
or C, I suspect.

Things get dicier with viewing an Array of int as an Array of Int, but
again, the Array of Int could know that it's a proxy for an Array of int.
It's just an object with an interface, after all.  And it could generate
smart proxy references as the need arises, in cooperation with the Array
of int as necessary to avoid .id bifurcation.

I am not suggesting that we open up the barn doors to allow anything
to be coerced to anything else willy nilly.  I am suggesting that we
maintain the easy integer <-> number <-> string semantics of Perl 5
when the rest of the type system allows it.  Data structures would
still have to be conformant--I'm talking about the leaf semantics,
not the tree semantics.

Larry


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Piers Cawley
Damian Conway <[EMAIL PROTECTED]> writes:

> Austin Hastings wrote:
>
>> But what's the vision for p6? My expectation is that the
>> type-checking stuff will be heavily used
>> for:
>> 1- Large scale projects.
>> 2- CPAN modules.
>> I expect that the folks who want to do one-liners will still want to
>> be
>> able to say C
>> So the "strict" bits have to be forgiving of the "non-strict"
>> callers.
>
> To me that's a contradiction in terms. Strictness can't be "forgiving".
> At the risk of stating the obvious, that's the whole point of strictness:
> to be strict.
>
> What we're suggesting is that if you want to be non-strict, don't use types.
> After all, they're optional.
>
> "But," (I hear you say), "I may not have a choice! If the Cruel Module
> Author chose to use types, then I'm forced to do so too. That's not
> Lazy."
>
> And you're right. The module author gets to determine the interface of
> their module. And if they determine that that interface will provide
> type-safety, then you have to respect that. Just as if they decided
> that it would have an OO interface, or would set PRE and POST
> conditions on calls, or would only take named arguments.
>
> Because the author of the module is *relying* on that interface to
> ensure the correctness of their code; to prevent inappropriate data
> being passed to their subroutines. Typing is yet another way in which
> they can relax, knowing that the wrong type of data will be headed off
> at the (compiler) pass.
>
>
>> To me, the way around this is NOT to force interface contracts down to
>> some lowest common denominator, but rather to document what is
>> expected, and then allow the developer to accept responsibility for
>> stepping on his crank.
>
> Yep. And the way for the client of some module to accept that
> responsibility is to put in an explicit conversion.

Of course, a module author could always layer on a 'non strict'
version of the interface that did the type conversions itself before
passing them into the more stringent internals.

>> But at the bottom, the C++ problem is a problem of its own making --
>> people want coercion. Just like me. I want coercion. I want the ability
>> to take advantage of the really nifty, carefully written code available
>> from dedicated, rigorous hackers like this Conway fellow. But I want to
>> do it as a slap-dash hack with no thought given to type stuff.  How?
>
> By distinguishing a parameter that *requires* a particular type, from
> a parameter that *ensures* a particular type (by coercion if
> necessary). I've suggested that using C semantics should
> indicate "make whatever I'm actually given into one of these, if you
> can", whereas reference semantics say "this must already be one of
> these" (by their very nature, since an aliased parameter *is* the
> argument).
>
> Alternatively, one might imagine a separate and explicit trait that
> specifies that a parameter is allowed to coerce its corresponding
> argument to it's own type.

But this would be better. And implementable relatively easily as a
macro if it weren't availabe in the core I would have
thought. Hm... it might be interesting/useful to implement a set of
macros to allow developers to define and export their own traits:

   trait foo (...) is ParameterTrait {
  COMPILATION_CHECK {...}
  RUNTIME_CHECK {...}
   }

(There's almost certainly a better syntax available mind). 


-- 
Piers


Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-13 Thread Damian Conway
Austin Hastings wrote:

But what's the vision for p6? 

My expectation is that the type-checking stuff will be heavily used
for:
1- Large scale projects.

2- CPAN modules.

I expect that the folks who want to do one-liners will still want to be
able to say C
So the "strict" bits have to be forgiving of the "non-strict" callers.
To me that's a contradiction in terms. Strictness can't be "forgiving".
At the risk of stating the obvious, that's the whole point of strictness:
to be strict.
What we're suggesting is that if you want to be non-strict, don't use types.
After all, they're optional.
"But," (I hear you say), "I may not have a choice! If the Cruel Module Author 
chose to use types, then I'm forced to do so too. That's not Lazy."

And you're right. The module author gets to determine the interface of their 
module. And if they determine that that interface will provide type-safety, 
then you have to respect that. Just as if they decided that it would have an 
OO interface, or would set PRE and POST conditions on calls, or would only 
take named arguments.

Because the author of the module is *relying* on that interface to ensure the 
correctness of their code; to prevent inappropriate data being passed to their 
subroutines. Typing is yet another way in which they can relax, knowing that 
the wrong type of data will be headed off at the (compiler) pass.


To me, the way around this is NOT to force interface contracts down to
some lowest common denominator, but rather to document what is
expected, and then allow the developer to accept responsibility for
stepping on his crank.
Yep. And the way for the client of some module to accept that responsibility 
is to put in an explicit conversion.


If you say, "Give me an Array of Hash of (String => Array of BigNum)"
and I say, "Here's an Array of Scalars. They're OK, I promise" and
things "gang agley", it's my fault. I can deal with that.
But large projects -- where typing will be most important -- *can't* deal with 
that. That's the point of typing: to specify and enforce interface contracts. 
At compile-time if at all possible.


But at the bottom, the C++ problem is a problem of its own making --
people want coercion. Just like me. I want coercion. I want the ability
to take advantage of the really nifty, carefully written code available
from dedicated, rigorous hackers like this Conway fellow. But I want to
do it as a slap-dash hack with no thought given to type stuff.  How?
By distinguishing a parameter that *requires* a particular type, from a 
parameter that *ensures* a particular type (by coercion if necessary). I've 
suggested that using C semantics should indicate "make whatever I'm 
actually given into one of these, if you can", whereas reference semantics 
say "this must already be one of these" (by their very nature, since an 
aliased parameter *is* the argument).

Alternatively, one might imagine a separate and explicit trait that specifies 
that a parameter is allowed to coerce its corresponding argument to it's own type.

But what we can't allow is a reference parameter to coerce its argument. For 
example:

sub loggedincr (Int $i is rw) {
print $log: "Incremented $i.id()\n";
$i++ unless $i.constant;
}
	# and later...

int $x = 7;
loggedincr($x);
The $i parameter *can't* be bound to $x, because $x doesn't have the necessary 
features to be an Int (e.g. it doesn't have the capacity to respond to method 
or property lookups). Even wrapping $x in a temporary Int wouldn't help, since 
it would render the logging of an .id meaningless. The whole point of having 
types is to catch this kind of problem at compile-time.


My own problem with this wrapping notion is that I consider it
incompatible with the reference semantics of normal Perl 6 
parameters. Specifically, I *don't* want the aliasing mechanism to 
be capable of implicit type coercions.
 
Maybe you could expand on that a little?
See above.


On the other hand, I have *no* problem with this:

sub foo(@a is Array of Int is copy) {...}
   ^^^
doing the kind of coercive wrapping you're suggesting.


What's the difference? (Aside from the obvious, that is...)
Suppose I call:

	foo(@x);

The difference is that @a above is a lexically scoped variable into
which the contents of the corresponding argument (@x) are copied (i.e. 
assigned). Now it's perfectly possible that the contents of @x can be assigned 
into @a, even if the argument and the parameter are of wildly different types.

But if I say:

sub foo(@a is Array of Int) {...}
...
foo(@x);
then I'm saying: "within &foo, @a is just another name for @x". So they are 
(temporarily) the same thing. That can only (be allowed to) happen if the 
actual type of @x satisfies all the requirements of the declared type of @a.

Damian



Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-12 Thread Leopold Toetsch
Austin Hastings wrote:

But what's the vision for p6? 

My expectation is that the type-checking stuff will be heavily used
for:
1- Large scale projects.

2- CPAN modules.


3- speed

When you are not on perl one liners, but maybe some inner tight loops of 
some algorithm or whatever, where speed does matter, we (the low level 
PASM folks :) have achieved a speed increase of x100 and more, on a now 
of course hand crafted assembler routine compared to $HLInterpLang.

These are the margins that a good optimizer will be able to hopefully 
reach, which are for plain integers near or beyond gcc -O3 performance 
with the JIT runtime.
When the flexibility of all the lanugage comes in, this is of course not 
possible, and the more of those features (caller, %MY, leave, 
exceptions) are used, the less, optimizations can be used. But for "what 
is the type-checking stuff": for sure for better diagnostic messages and 
for performance, when needed.

=Austin


leo




Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-12 Thread Austin Hastings

--- Damian Conway <[EMAIL PROTECTED]> wrote:
> Austin Hastings wrote:
> 
> > In this case, I rather like the idea of being able to say
> > 
> >sub foo(@a is Array of Int) {...}
> > 
> >my @input = read_a_bunch_o_data();
> >foo(@input);
> > 
> > 
> > Where the compiler will automatically "wrap" the @input array in a
> > make-it-an-int converter. This, to me, is DWIM.
> 
> But to many others it's not DWIS ("Do What I Said"). To them, types
> are about compile-time checking of constraints on the run-time 
> compatibility of data.

No problem so far. And when they run -w, perl should tell them
"subroutine call not provably (in)correct at line 3"

> So they would argue that declaring C like that implies that any
> argument passed to C ought to guarantee that it already 
> contains Ints, rather than specifying a (possibly unsuccessful)
> run-time coercion to ensure that condition. 

But what's the vision for p6? 

My expectation is that the type-checking stuff will be heavily used
for:

1- Large scale projects.

2- CPAN modules.

I expect that the folks who want to do one-liners will still want to be
able to say C

So the "strict" bits have to be forgiving of the "non-strict" callers.

To me, the way around this is NOT to force interface contracts down to
some lowest common denominator, but rather to document what is
expected, and then allow the developer to accept responsibility for
stepping on his crank.

If you say, "Give me an Array of Hash of (String => Array of BigNum)"
and I say, "Here's an Array of Scalars. They're OK, I promise" and
things "gang agley", it's my fault. I can deal with that.

And if you have said "Array of Hash of (String => Array of BigNum)"
then I can theoretically give you a typed array and let the compiler
check it.

However, if you have been forced to say "Give me an Array" in the
interests of avoiding typewhacking one-liners, then (1) you've got to
check and throw the exception, slowing up your code; and (2) there's no
option for me if I *DO* want to conform to the rigid rules.


> And many would argue that implicit coercions on typed
> parameters is one of the major *problems* with C++.

Of course it is. And why is that? Because they've GOT strongly typed
parameters, but sometimes the data doesn't match the signature. This
has been exacerbated by differentiating const from non-const types, and
by that foul fire-hose of code known as the template mechanism.

But at the bottom, the C++ problem is a problem of its own making --
people want coercion. Just like me. I want coercion. I want the ability
to take advantage of the really nifty, carefully written code available
from dedicated, rigorous hackers like this Conway fellow. But I want to
do it as a slap-dash hack with no thought given to type stuff.  How?

> 
> My own problem with this wrapping notion is that I consider it
> incompatible with the reference semantics of normal Perl 6 
> parameters. Specifically, I *don't* want the aliasing mechanism to 
> be capable of implicit type coercions.

Maybe you could expand on that a little?

> On the other hand, I have *no* problem with this:
> 
>   sub foo(@a is Array of Int is copy) {...}
>  ^^^
> doing the kind of coercive wrapping you're suggesting.

What's the difference? (Aside from the obvious, that is...)


> > I think there may be a library of wrapper "helper-functions" used
> by
> > both the compiler and module-writers. Things that do coercive
> behavior
> > rather than try-but-maybe-fail behavior.
> 
> Quite possibly. Though wrapping is probably too "heavy" a mechanism
> for type 
> coercions. When I imagine type coercions in Perl 6, I imagine them as
> compile-time detectable, and explicit.

Ahh, but if you don't want heavy, just comply with the expected type,
or do your own coercion. I certainly imagine them as compile-time
detectable (I don't want all subcalls to be wrapped), but obvious,
implicit coercions should get a configurable warning and a wrapper.

sub foo(@a of Scalar) {...}

foo(1, 2, 3); # OKAY

foo(@a, @b, @c);  # WARNING: foo(List of Array) will be coerced to
foo(Array of Scalar) using &foo.wrap(__flattenArrays)

foo(**(@a, @b, @c)); # OKAY: Fixed it using SuperMario operator.


> > So the "use strict signatures;" wouldn't be a switch invoking type
> > stricture, per se. What it would do is convert from "DWIM
> > stricture" to "Patriot Act stricture".
> 
> I still believe that the default level of type-checking you're
> proposing is the wrong way round.

Hmm. Okay. I'll let you reverse the default levels if you give me a
single-letter command line switch to go back to "slouch-mode"..

=Austin



Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-12 Thread Damian Conway
Austin Hastings wrote:

In this case, I rather like the idea of being able to say

   sub foo(@a is Array of Int) {...}

   my @input = read_a_bunch_o_data();
   foo(@input);
Where the compiler will automatically "wrap" the @input array in a
make-it-an-int converter. This, to me, is DWIM.
But to many others it's not DWIS ("Do What I Said"). To them, types are about 
compile-time checking of constraints on the run-time compatibility of data.
So they would argue that declaring C like that implies that any argument 
passed to C ought to guarantee that it already contains Ints, rather than 
 specifying a (possibly unsuccessful) run-time coercion to ensure that 
condition. And many would argue that implicit coercions on typed parameters is 
one of the major *problems* with C++.

My own problem with this wrapping notion is that I consider it incompatible 
with the reference semantics of normal Perl 6 parameters. Specifically, I 
*don't* want the aliasing mechanism to be capable of implicit type coercions.

On the other hand, I have *no* problem with this:

sub foo(@a is Array of Int is copy) {...}
   ^^^
doing the kind of coercive wrapping you're suggesting.


Connecting this with some thinking/talking about wrappage, it occurs to
me that:
C is just a keyword. Which means that instead of doing 

foo.wrap({ ...; call; ... });
That has to be:

 &foo.wrap({ ...; call; ... });


I could just as easily do:

sub wrapper(...) { ...; call ; ... }
foo.wrap(&wrapper);
Right?
 &foo.wrap(&wrapper);

But, yes.


I think there may be a library of wrapper "helper-functions" used by
both the compiler and module-writers. Things that do coercive behavior
rather than try-but-maybe-fail behavior.
Quite possibly. Though wrapping is probably too "heavy" a mechanism for type 
coercions. When I imagine type coercions in Perl 6, I imagine them as 
compile-time detectable, and explicit.


So the "use strict signatures;" wouldn't be a switch invoking type
stricture, per se. What it would do is convert from "DWIM stricture" to
"Patriot Act stricture".
I still believe that the default level of type-checking you're proposing is 
the wrong way round.

Damian




Re: A6: Strict signature checking - was: Complex Parameter Types

2003-03-12 Thread Austin Hastings

--- Damian Conway <[EMAIL PROTECTED]> wrote:
> Austin Hastings wrote:
> 
> > You're treading dangerously close to the S&M line there... 
> 
> Sure. That's exactly what types are for.
> 

Granted.

> > Does it make sense to say C for this stuff?
> 
> I'd much rather that simply using typed params invoked type
> stricture.

Sure, but there's a difference between "C" (Boy Scout Oath) strictness
and "C++" (FBI will visit your home and do a thorough background check
before we proceed) strictness.

In this case, I rather like the idea of being able to say

   sub foo(@a is Array of Int) {...}

   my @input = read_a_bunch_o_data();
   foo(@input);


Where the compiler will automatically "wrap" the @input array in a
make-it-an-int converter. This, to me, is DWIM.

Connecting this with some thinking/talking about wrappage, it occurs to
me that:

C is just a keyword. Which means that instead of doing 

foo.wrap({ ...; call; ... });

I could just as easily do:

sub wrapper(...) { ...; call ; ... }
foo.wrap(&wrapper);

Right?

I think there may be a library of wrapper "helper-functions" used by
both the compiler and module-writers. Things that do coercive behavior
rather than try-but-maybe-fail behavior.

So the "use strict signatures;" wouldn't be a switch invoking type
stricture, per se. What it would do is convert from "DWIM stricture" to
"Patriot Act stricture".

=Austin