Re: PCC and IMC

2003-10-12 Thread Luke Palmer
Gregor N. Purdy writes:
 Leo --
 
 The Jako compiler spits stuff out from Perl.
 
 I'm writing some new experimental stuff in PIR directly.
 
 I'm curious about other stuff, too. I don't see any
 of the languages/imcc/t/**/*.t files doing anything with
 the ord op, and when I try to use it as
 
   .local int c
   .local str s
 
 and then
 
   c = ord(s)
 
 or
 
   ord(c, s)
 
 in my .imc file, neither works. Do I need to do magic to
 use any old op I want?

Uhh... I may be misunderstanding the question, but you should be able to
use assembler syntax, eg.

ord c, s

That works for me.

Luke

 
 Regards,
 
 -- Gregor
 
 On Sun, 2003-10-12 at 11:42, Leopold Toetsch wrote:
  Gregor N. Purdy [EMAIL PROTECTED] wrote:
   Is there any good reason why prototyped PCC subs
   shouldn't be callable with IMC syntax that looks like
   a macro call, without having to make a macro wrapper
   manually?
  
  Could be done, but for sure unlikely. PASM/PIR are still assembler
  languages. You can stuff features and more into it, but this is not the
  goal. The assembler syntax should be simple and easy to generate from
  HLL compilers. It should of course have support for all the features of
  the underlying CPU (parrot), but not much more.
  You are AFAIK generating PIR files by  perl, so just spit out
  the function call, that's it.
  
  leo
 -- 
 Gregor Purdy[EMAIL PROTECTED]
 Focus Research, Inc.   http://www.focusresearch.com/


Re: PCC and IMC

2003-10-12 Thread Luke Palmer
Gregor N. Purdy writes:
 Luke --
 
 Yeah. That falls into the duh category, I guess.
 
 But, I'm still having some trouble:
 
 
 .pcc_sub _consume_string prototyped
   .param str input

.param string input

Now the error makes sense.

   .local int c
   .local int test
 
   .local Sub __char_is_white_space
   newsub __char_is_white_space, .Sub, _char_is_white_space
 
   .local Sub __char_is_digit
   newsub __char_is_digit, .Sub, _char_is_digit
 
 CONSUME:
   ord c, input
   substr input, input, 1 # error:imcc:op not found 'ord_i_p' (ord2)

And I assume here you mean:

substr input, input, 0, 1

Luke

   
 
 
 (Note that the complaint about ord_i_p is on the substr line,
 and its as if it thinks input is a PMC not a string.
 
 
 Regards,
 
 -- Gregor
 
 On Sun, 2003-10-12 at 12:15, Luke Palmer wrote:
  Gregor N. Purdy writes:
   Leo --
   
   The Jako compiler spits stuff out from Perl.
   
   I'm writing some new experimental stuff in PIR directly.
   
   I'm curious about other stuff, too. I don't see any
   of the languages/imcc/t/**/*.t files doing anything with
   the ord op, and when I try to use it as
   
 .local int c
 .local str s
   
   and then
   
 c = ord(s)
   
   or
   
 ord(c, s)
   
   in my .imc file, neither works. Do I need to do magic to
   use any old op I want?
  
  Uhh... I may be misunderstanding the question, but you should be able to
  use assembler syntax, eg.
  
  ord c, s
  
  That works for me.
  
  Luke
  
   
   Regards,
   
   -- Gregor
   
   On Sun, 2003-10-12 at 11:42, Leopold Toetsch wrote:
Gregor N. Purdy [EMAIL PROTECTED] wrote:
 Is there any good reason why prototyped PCC subs
 shouldn't be callable with IMC syntax that looks like
 a macro call, without having to make a macro wrapper
 manually?

Could be done, but for sure unlikely. PASM/PIR are still assembler
languages. You can stuff features and more into it, but this is not the
goal. The assembler syntax should be simple and easy to generate from
HLL compilers. It should of course have support for all the features of
the underlying CPU (parrot), but not much more.
You are AFAIK generating PIR files by  perl, so just spit out
the function call, that's it.

leo
   -- 
   Gregor Purdy[EMAIL PROTECTED]
   Focus Research, Inc.   http://www.focusresearch.com/
 -- 
 Gregor Purdy[EMAIL PROTECTED]
 Focus Research, Inc.   http://www.focusresearch.com/


Re: How to create a function that returns nothing

2003-10-14 Thread Luke Palmer
Joe Gottman writes:
 How do you declare a function that doesn't return anything? For instance, a
 C++ swap function might be declared
template class X
 void swap(X x, X y);
 
 It would be nice to declare the corresponding Perl6 function as
 sub swap ($x is rw, $y is rw) returns nothing {...}
 or something similar.

Use the Void pseudo-type:

sub swap ($x is rw, $y is rw) returns Void {...}

Or if you're in a more C-ish mood:

our Void sub swap ($x is rw, $y is rw) {...}

 This would be an absolute necessity if you wanted to emulate C++, Java, or
 any other strongly typed language.
 
 Also, it could be useful for causing a compile-time error if someone types
 something like
 $z = swap($x, $y);
 
 Joe Gottman
 
 
 


Re: Instantiating objects

2003-10-15 Thread Luke Palmer
Leopold Toetsch writes:
 I think that for supporting Ruby or such we have to keep fences between
 PMCs and real objects very low. 

Agreed, or have some sort of automagic transformation possible.

 So it should be possible to define an Imaginary Number class that
 inherits from two (Perl?)Nums directly and overloads some operators
 without much overhead, i.e. the 2 attributes (re, im) would be kept in
 the 2 number PMCs.

I don't think that would work.  If I remember correctly, we're going to
make all inheritance 'virtual', correct?  Which means that inheriting
from 2 number PMCs should be precisely the same as inheriting from 1
number PMC.

That's okay, though, because from a design perspective, inheritance
wouldn't be the way to go about that kind of problem anyway :-)

Luke

 
  Dan
 
 leo


Re: Lexical Pads

2003-10-18 Thread Luke Palmer
Will Coleda writes:
 Can someone explain to me the lexical pad stack and static nesting 
 depth?
 
 I'm trying to write global for tcl, and trying to pull out a variable 
 from the outermost pad, and failing to find it. - I'm fairly certain 
 this is because I'm abusing new_pad and store_lex (always using 0 
 as the static nesting depth). Works fine when all I care about is the 
 current pad - but getting to variables elsewhere in the pad stack 
 results in a lexical not found error.
 
 Do I need to manually keep track of my nesting depth? If so, what's the 
 rationale? (why have the stack if you also have the nesting depth?)

Because the stack is dynamic, while the nesting depth is static/lexical.
That is, you keep track of the nesting depth only at compile-time.

If you want globals to just be lexicals at the top level, that's fine.
Just do a Cnew_pad 0 at the beginning of your program, and then 
Cstore_lex 0 for each global.  I don't know TCL, but if you have other
lexical scopes, start at Cnew_pad 1 and use Cfind_lex -1 for all
lexicals.

But to play nice with other languages, you should probably use
Cstore_global and Cfind_global for globals.

Luke

 Heading off to experiment...
 
 --
 Will Coke Coledawill at coleda 
 dot com
 


Alternately named arguments

2003-10-24 Thread Luke Palmer
Presuming you can do:

(who = $name, why = $reason) := (why = $because, who = me);

(from A6)

Does that imply that you can do:

sub routine (name = $nombre, date = $fecha) {...}

Anyway, I just realized that this is finally an elegant way to do
multiple, unordered return values:

(name = $name, id = $id) := getinfo();

(Or, in this precise case:)

(+$name, +$id) := getinfo();

Luke


Re: Alternately named arguments

2003-10-25 Thread Luke Palmer
David Storrs writes:
 On Fri, Oct 24, 2003 at 12:57:18AM -0600, Luke Palmer wrote:
  Presuming you can do:
  
  (who = $name, why = $reason) := (why = $because, who = me);
  
  (from A6)
  
  Does that imply that you can do:
  
  sub routine (name = $nombre, date = $fecha) {...}
  
  Anyway, I just realized that this is finally an elegant way to do
  multiple, unordered return values:
  
  (name = $name, id = $id) := getinfo();
  
  (Or, in this precise case:)
  
  (+$name, +$id) := getinfo();
 
 
 Just confirming something...if you did this:
 
  ($name, $id) := getinfo();
 
 I think you would end up storing an alias to the getinfo() sub in $name, and
 undef in $id.  Is that correct?

Yeah, providing getinfo has an empty sig.

Well, if we take the binding/parameter passing equivalency a little
farther, that can be an error.  Which may turn out to be good:

($name, $id) := getinfo();# I want getinfo to return 2 values

($name, ?$id) := getinfo();   # I realize that it may only return 1

Etc.

 What would happen if you did this?
 
  (+$name, +$id) := getinfo();
 
 I would expect a compile time error, because you can't bind a sub
 alias to a scalar that is being forced into numeric context.

Nu...meric context?  I meant that as named parameters, that is,
expecting getinfo to return a list of pairs.  So I think that will be an
error, just for a different reason.

Luke


Re: Alternately named arguments

2003-10-26 Thread Luke Palmer

Hi Damian, welcome back!

Damian Conway writes:
 Luke Palmer asked:
 
 Presuming you can do:
 
 (who = $name, why = $reason) := (why = $because, who = me);
 
 (from A6)
 
 Does that imply that you can do:
 
 sub routine (name = $nombre, date = $fecha) {...}
 
 If we're consistent about lvalues of binds being the same as argument lists,
 it probably does.

Neat.

 
 Anyway, I just realized that this is finally an elegant way to do
 multiple, unordered return values:
 
 (name = $name, id = $id) := getinfo();
 
 Yep.
 
 
 (Or, in this precise case:)
 
 (+$name, +$id) := getinfo();
 
 Err, no. Or at least: Please, No!. ;-)

Good.  That made my stomach hurt.

Luke

 That would certainly be a way cool abbreviation, but I suspect it would be 
 a Very Bad Idea for unary plus to have two unrelated meanings out in the 
 actual code. I suspect that the named-only markers are only available 
 within actual parameter lists.
 
 Damian
 


Garbage-collecting classes [was: This week's Summary]

2003-10-28 Thread Luke Palmer
   Object Instantiation
 Dan had a moment of clarity and declared that the Parrot Way to
 instantiate an object in class Foo will be:
 
   new P5, .Foo
 
 All we need now is a working implementation. And, apparently, knowing
 what class a class is a member of might be handy, but Dan's punting on
 (ignoring the heck out of) that one.

(Yeah, I read the thread, but just thought of this now)

So classes will be integers?  Fair enough, as there's just as many of
those as there are memory locations.

I do worry about some long-running daemon that uses anonymous classes
heavily.  It's possible that after quite some time, we'd run out of
integers, even when there are far fewer than 4 billion classes in
current existence.

So, shouldn't classes instead be objects that can be garbage-collected?
I know that violates that nice equivalency between PMCs and classes, but
I'm sure there's a way to finesse the convenience of that equivalence
somehow...

Luke


Re: Some questions about currying

2003-10-29 Thread Luke Palmer
Joe Gottman writes:
I just reread the section of A6 about currying, and I have several
 questions about it.
 
1)  Suppose I have a function like the following:
sub foo($param, @param) {...}
 where the parameter names differ only by their sigils.  Is it legal
 for me to type
 foo.assuming('$param' = 1)
 in order to disambiguate the parameter names?

Yeah, but I think the scalar would get it anyway.  This is the same way
$0 works.  So 'foo' and '$foo' refer to the same thing, and '@foo' and
'%foo' disambiguate.  Though, if $param weren't there, 'param' = [1]
would assign to @param... which is not, IIRC, how $0 works.  I think
it'd be a good idea to unify the two behaviors, probably in favor of the
named parameter style  (where it will pick the defined one, and the
scalar only if it's ambiguous). 

2)  Often, if you are working with a code reference instead of an actual
 sub, you might not know the names of all the parameters.  In this case,
 would it be legal to curry by parameter position instead of parameter name?
 
 sub setFirstToOne(block) {
 block.assuming( 0 = 1); #I am assuming 0-based parameter lists
 }

That would definitely be a nice feature.  

 Another advantage of currying by position is that it might allow you to set
 the first few elements of a slurpy array.
 
 sub foo(* @params) {...}
 my $bar = foo.assuming(0 = hello);
 $bar.(world); # Calls foo(hello, world)

That would require a bit more under-the-hood work, but I think that's
okay.

 3)  Currying binds a function parameter to a value?  Is there any way to
 bind a function parameter to a variable?  Consider the following code:
 
 sub printNum(int $x) {print $x\n;}
 my $foo = 0;
 my $vindaloo = printNum(int).assuming(x = $foo); #currying
 ++$foo;
 $vindaloo.();
 
This code prints 0, not 1, because the currying binds the parameter to
 the value $foo had when the currying occurred, not the value it had when the
 curried function was called.  It would be nice if there were some way to
 curry so that a parameter is bound to a variable reference.

There is.  Best not to worry .assuming with details of references.  Do
it with a scratchpad:

   sub printNum($x) { print $x\n }
   my $foo = 0;
   my $vindaloo = { printNum($foo) };
   ++$foo;
   $vindaloo();   # Prints 1

There's still those issues of getting $vindaloo's signature exactly
right for complex cases.  In any case, I don't think .bind would be hard
to write.

Luke

 This would probably have to be a different method than assuming.
 Maybe something like printNum(int).bind(x = \$foo)
 
 
 Joe Gottman
 
 
 


Nested modules

2003-11-02 Thread Luke Palmer
So, we can have :: in names, but that doesn't represent any inherent
relationship between the module before the :: and the one after.  I
think this is an important thing to keep.

However, will it be possible to, for example, do:

module Foo;

module Bar { ... }

And refer to the inner module as, say, Foo.Bar.  A more interesting
concept, can one use variables as modules, like:

::($foo)::somefunc();

Or some awful thing like that?

And of course this would imply the existance of anonymous modules.  Yay.

Luke


Re: Vector dot Vectoria

2003-11-05 Thread Luke Palmer
Hi Doug,

Doug McNutt writes:
 The first source of discussion was around whether there is any
 consistent meaning to array operations. The source of this was that
 some felt that other people may want C* to mean something other
 than element-wise multiplication by default (e.g. matrix inner
 product). However no-one actually said that Ithey wanted it to work
 this way, only that Iothers may prefer it, particularly
 mathematicians.
 
 This physicist wants it that way. In scalar context $dotproduct = @A
 * @B; ought to return the scalar (dot, inner) product of vectors @A
 and @B by which I mean the sum of the products of like components. In
 array context it is quite reasonable to return the element by element
 products but it will be for accounting rather than for electrical
 engineering, mapmaking, and 3D rendering.
 
 @C = @A + @B; returning the vector sum is mathematically correct.
 
 An intrinsic ability to figure the dot product is useful for matrix
 multiplication. 

I was sincerely pissed when PDL, the Perl language _for_ mathematicians,
was not capable of easily doing a tensor inner product.  The threading
system was too advanced, and you needed to jump through hoops to get it
to do the simple thing.

While Perl 6 is not being designed as a language for mathematicians,
it's not being designed as a language against mathematicians.  I want an
inner product.

One can generally do a dot product as such:

$prod = @a * @b == sum;

Where:

sub sum([EMAIL PROTECTED]) { reduce { $^a + $^b } 0, @data }

But

$prod = @a * @b;

Won't get you the dot product without some kind of module.  It'll get
you a reference to the array of @a[$i] multiplied by @b[$i].  And
putting a numeric context on that won't do it either; that will give you
the length of the resulting array.

PDL has a lot of liberty in Perl 6, though.  They can easily go far
enough to overload piddle operations to do the Right Thing.  If they so
desire (don't know whether I would be for or against this), they could
make up a whole new piddle sigil, so you could go:

@pid = (1,2,3,4,5);

And have the scalar operations work right automatically.  That might
actually be the way to go, because when I'm programming these sorts of
things, I have arrays and I have vectors, and I rarely interchange them.

 RFC 82 offers a mathematically abhorrent example of
 element by element matrix multiplication:
 
  my int @mat1 = ([1,2],  [3,4]);
  my int @mat2 = ([2,2],  [1,1]);
  my @mat3 = @mat1 * @mat2;   # ([2,4],[3,4])
  
 Perhaps the designations mat1, 2, 3 are not intended to be
 abbreviations for the word matrix but it is dangerous indeed to
 provide a syntax that will surely be confused with true matrix
 multiplication. @matC = @matA * @matB should produce elements in
 the result which are the dot products of the row vectors of the left
 matrix with the column vectors of the right. Note that one or the
 other of the input matrices needs to be transposed and some
 standardized notation is required. Matrix multiplication is not
 commutative.
 
 The apocalypse at http://dev.perl.org/perl6/apocalypse/A03.html has
 this to say about confusing people.
 
 Anyway, in essence, I'm rejecting the underlying premise of this RFC
 (82), that we'll have strong enough typing to intuit the right
 behavior without confusing people. Nevertheless, we'll still have
 easy-to-use (and more importantly, easy-to-recognize)
 hyper-operators.
 
 And then it goes on about other vector-like things:.
 
 This RFC also asks about how return values for functions like abs( )
 might be specified. I expect sub declarations to (optionally) include
 a return type, so this would be sufficient to figure out which
 functions would know how to map a scalar to a scalar.
 
 There is the norm of a vector, actually the length if we're talking
 about 3 dimensional geometry, which can be considered the abs(@A) as a
 scalar. It would be the positive square root of the sum of the squares
 of the components.  = sqrt ( @A * @A ).
 
 It would also be possible to include a scalar norm of a matrix which
 would be its determinant but that's probably fodder for a module
 dedicated to solution of linear equations.

And abs() really doesn't seem the place to put the norm.  That feels
more like norm() to me.

 An element by element concatenation of two arrays of text is certainly
 reasonable. As a multiplication I'm not sure what it would mean but
 it's a bit like the @mat1 * @mat2 in the quote above. Not very
 interesting or useful.
 
 Whatever be the final result for perl 6 syntax it ought either to use
 the terms matrix and vector as employed by the likes of Maxwell and
 Heisenberg and provide mathematically correct operators or it should
 avoid those terms when documenting hyper-operators that do something
 else.

So, I guess it won't be concerting to you to hear that we're calling
hyper-operators vector-operators.  I personally think it's not the
operators that are misleading, though.  They have 

Re: How to run typeless languages fast on parrot?

2003-11-05 Thread Luke Palmer
Thies C. Arntzen writes:
   hi,
 
   we've started a project (will have a web-page soon) that aims to
   port the php-language (www.php.net) to run on top of parrot.

Cool!

   we've written some initial code and i'm kinda stuck while
   writing the codegen (i target imc) 
 
   my problem is that php is typeless. i am writing code to to some
   basic type-recognition in my ast to be able to leverage the much
   speedier I S and N types in parrot, but for obvious reasons i
   have to make the php basic type an PMC. problem now is that
   using pmc for everything will make execution much much slower
   that it could be.

Could be?  How?  The only way it could be faster from the codegen level
is if you have a really good data flow analyzer that can tell that
something is *only* going to be doing a certain kind of operation.  That
is a hard, and in general impossible, problem.

   my compiler currently translates:
 
 ?php
 for ($i = 0; $i  100; $i = $i + 5.5) {
 echo hallo;
 }
 ?
 
   to:
 
 [buncha pir code]
 
   (i know it can be made better - working on it)

Actually that was pretty good for an early version.  You could help IMCC
out by not creating those PerlUndefs until you're going to assign to
them.

 - but the basic dilemma is obvious: $i starts as an INT and becomes a
 FLOAT at runtime. so my compiler made it a PMC. (i know that i'll at
 one point have to write my own PMC for the PHP base-type, but for now
 PerlUndef works for me).
 
   because pmc as so much slower that native types i loose most of
   parrots brilliant speed due to the fact that i don't know the
   types at compile-time.

Yep, you do.  That is the caveat of dynamic languages.

   i believe you'll face the same problem once perl6 becomes a reality on
   parrot 

We know about this, too.  And that's one of the reasons Perl 6 is
introducing an optional type system:  so the programmer can tell the
compiler when it's allowed to use the [ISN] types instead of PMCs, when
they need to be fast (tight loops and such).  Without any user guidance,
everything would have to be a PMC (save a few special cases).

 so here's my question (i've only been on perl6-internals for some
 week, so sorry if this has been discussed in depth before):
 
   would't it make sense to introduce one additional new type into
   parrot that can morph between the normal types (I, S, N, P)?

Yeah, it would!  We call those PMCs. 

Most of the reason [ISN]s are so fast is because of the Just-In-Time
compiler.  I don't know whether there are plans to make the JIT dynamic,
in that it could detect that we have a JITtable PMC on our hands and JIT
the following section of code with respect to that.  My guess is that
there are no such plans, or that it's impossible to do well.

Your morphing type doesn't make any sense, when you look at how things
are compiled into byte code.  You're asking it to be compiled
differently based on the run time type, which is somewhat of a temporal
paradox.

 
   something like (i call the type VAL):
 
   typedef enum { INT, NUMBER, STRING, ... PMC } ValType;
 
   typedef struct {
   ValType type;
   union {
   INTVAL i;
   NUMBER n;
   STRING s;
   ...
   PMC p;
   } u;
   } VAL;
 
   and add support for this in the executor in the most efficient way.

Which would be about as efficient as PMCs currently are.

 
   if you think this is unneeded could you explain how you are
   planning to make untyped languages run really fast on parrot and
   what direction i have to take to use that technique? (PMC will
   always carry the vtable jump overhead, so they will be slower
   than what perl or php use currently in the inner execution loop)

Vtable jump isn't really that much overhead in a language like C.
Parrot's already running pretty fast.  We're making things fast by
keeping it in mind while implementing it, including a rich opcode
and vtable so the number of said slow dispatches are small, among other
various things that I don't know.  Maybe Dan will chime in here :-)

It's great that you're doing PHP for Parrot.

Luke



 
   i'd also like to add that eg PHP has different semantics when you do binary
   operations on strings that perl has so this VAL type would have to be
   as flexible as a PMC. (PHP would have to use a different implementation
   than Perl6 or Python)
 
   thies
 -- 
 Thies C. Arntzen   -   Looking for all sorts of freelance work  -   just ask..
 http://www.amazon.de/exec/obidos/wishlist/AB9DY62QWDSZ


Re: syntax: multi vs. method

2003-11-18 Thread Luke Palmer
Jonathan Lang writes:
 My apologies for the break in the chain of responses; I lost your reply
 before I could reply to it, and had to retrieve it from the list archives.
  
 
 Luke Palmer wrote:
  Well, multi is no longer a declarator in its own right, but rather a
  modifier.  Synopsis  Exegesis 6 show this.  
 
 I don't know about Exegesis 6, 

Then you should probably read it.  It is the most recent of the
documents, so what it says is closest to the current thinking. Plus,
it's a fun read.

 but Synopsis 6 (http://dev.perl.org/perl6/synopsis/S06.html) is still
 showing multi to be a declarator on par with sub, method, rule, and
 macro.  

Now that I look, yes, that's true.  It's wrong.

  I think this makes things even clearer, and has a fine-grained but
  elegant control over the scope of the routine.
 
 Agreed; I'd like something like this to be implemented.  
 
  This easily allows for multisubmethods and even multimacros
  (provided you have yourself a polymorphic object at compile time).
 
 For the record, subs never have invocants as currently described - so you
 could easily say that any sub that has an invocant is actually a
 submethod:
 
sub touch ($a: $b) {...}
 
 would be synonymous with:
 
submethod touch ($a: $b) {...}

Hmm.  Well, that depends on whether calling works like it does in Perl
5.  That is, given:

multi sub touch (Foo $a: $b) {...}

Is this legal:

my $x = new Foo;
$x.touch;

I haven't been able to deduce this.

  I also think it's important to say multi explicitly every time you
  mean it.  It allows the compiler to warn you when you're just being
  stupid about scoping as opposed to actually wanting to overload the
  routine.  From a design perspective, it makes it clear that this method
  introduces logical control-flow in addition to performing a task.
 
 That's probably good programming advice; but it should remain advice
 rather than being a requirement.  

Spoken like a true Perl programmer :-)

I don't see the win in losing the Cmulti keyword though.  Sure, there
are 5 fewer characters, but declarations aren't a place where concise
and terse are synonymous.  IMO, a colon is too small a character for
such a large distinction.  Misunderstanding the rule slightly can lead
to overriding instead of overloading...  reminds me of C++ [1].

 If you allow the distinction between a method and a multimethod to be
 determined implicitly, you can, if you choose, ignore the submethod and
 multi keywords altogether with minimal loss of capabilities: 
 
submethod touch ($a) {...}
multi watch ($a, $b) {...}
 
 would be equivelent to
 
sub touch ($_: $a) {...}
method watch ($a, $b:) {...}

Luke

[1]  While I haven't the hatred for C++ that quite a few people on this
list do, I definitely consider it an advanced language, by which I
mean there are subtle variants in the rules that cause wildy different
behaviors.  Beginners (and intermediates) still struggle with this one:

class Base { 
public:  
virtual int num() const { return 10; } 
}

class Derived : public Base {
public: 
int num() { return 20; }
}

int main() {
Base* b = new Base;  Base* d = new Derived;
cout  b-num()  endl;  // 10
cout  d-num()  endl;  // 10 !!
}

Now why the heck did the call to d-num() return 10??!!!  Because they
missed a Cconst in the overriding of num(), hiding it instead.  This
is precisely what would happen if you missed a colon in adding a
multimethod.  Sorry, I don't want to inflict this kind of pain on Perl
programmers.



Control flow variables

2003-11-18 Thread Luke Palmer
I was reading the most recent article on perl.com, and a code segment
reminded me of something I see rather often in code that I don't like.
Here's the code, Perl6ized:

... ;
my $is_ok = 1;
for 0..6 - $t {
if abs(@new[$t] - @new[$t+1])  3 {
$is_ok = 0;
last;
}
}
if $is_ok {
push @moves: [$i, $j];
}
...

I see this idiom a lot in code.  You loop through some values on a
condition, and do something only if the condition was never true.
$is_ok is a control flow variable, something I like to minimize.  Now,
there are other ways to do this:

if (0..6 == grep - $t { abs(@new[$t] - @new[$t+1]) })
{ ... }

But one would say that's not the cleanest thing in the world.

Python pulled this idiom out in to the syntax (yay them), with Celse
on loops.  The else block on a python loop executes only if you never
broke out of the loop.  That's a great idea.

So, in Perl's postmodern tradition, I think we should steal that idea.
I'm a little uneasy about calling it Celse, though.  Maybe CFINISH
would do, making the example:

for 0..6 - $t {
if abs(@new[$t] - @new[$t+1])  3 {
last;
}
FINISH { 
push @moves: [$i, $j];
}
}

I'd also like to say that while converting the rest of this sub to Perl
6, I realized how much I love the ..^ and ^.. operators.  I was
wondering whether people had forgotten about them :-). 

Luke


Re: Control flow variables

2003-11-18 Thread Luke Palmer
Simon Cozens writes:
 [EMAIL PROTECTED] (Luke Palmer) writes:
  I was reading the most recent article on perl.com, and a code segment
  reminded me of something I see rather often in code that I don't like.
 
 The code in question got me thinking too; I wanted to find a cleaner
 way to write it, but didn't see one.
 
  So, in Perl's postmodern tradition, I think we should steal that idea.
 
 I agree, but (as usual) would like to consider whether there's a way
 to solve a general problem rather than solving a specific problem by
 throwing additional syntax at it. (which sadly seems to be fast becoming
 the Perl 6 way)

Well... it is and isn't.  At first sight, it makes the language look
huge, the parser complex, a lot of syntax to master, etc.  It also seems
to me that there is little discrimination when adding new syntax. 

But I've come to look at it another way.  Perl 6 is doing something
(many things, really) that no other language has done before: making it
very easy to add new syntax to the language.

So modules that introduce new concepts into the language can add new
syntax for them without working with (ugh) a source filter.  And some of
these new syntaxes in the core language will actually be in standard
modules, if they're not commonly used.  Just like traits.

But even when they're not, Perl is a generic, multiparadigm language.
It covers and supports many concepts, and new concepts grafted onto an
existing but unfit syntax make things harder.  Humans are pretty good at
syntax.  Many times mathematicians make up new syntax when they
introduce a new concept: making it easier to think about, and easier to
recognize.

I'll also point out that FINISH isn't really extra syntax, just extra
vocabulary.

 Given that we've introduced the concept of if having a return status:
 
   my $result = if ($a) { $a } else { $b };

Ack!  We have?  It does make sense if we want to be able to implement
Cif as a regular sub... I guess.  Yuck.

 Then why not extend this concept and have a return status from other
 control structures?
 
   for 0..6 - $t { 
 last if abs(@new[$t] - @new[$t+1])  3;
   } or push @moves: [$i, $j];
 
 Of course, these things have consequences; I'm not sure whether we really
 want people saying
 
   push @moves:[$i, $j] unless last if abs(@[EMAIL PROTECTED])3 for 0..6;

That's illegal anyway.  Can't chain statement modifiers :-)

But a close relative would be possible:

push @moves: [$i, $j] unless for 0..6 { last if abs(@[EMAIL PROTECTED])  3 }

Yeah, how about no.  :-)

Luke



Re: Control flow variables

2003-11-18 Thread Luke Palmer
Austin Hastings writes:
 Luke Palmer wrote: 
  I was reading the most recent article on perl.com, and a code segment
  reminded me of something I see rather often in code that I don't like.
  Here's the code, Perl6ized:
  
  ... ;
  my $is_ok = 1;
  for 0..6 - $t {
  if abs(@new[$t] - @new[$t+1])  3 {
  $is_ok = 0;
  last;
  }
  }
  if $is_ok {
  push @moves: [$i, $j];
  }
  ...
 
 This is what I was talking about when I mentioned being able to do:
 
   cleanup .= { push @moves: [$i, $j]; }
 
 a few weeks ago. Treat code vars like code, not like sub-refs.

I'm not sure I know what you mean with regard to this example.
Exemplify further, please?

Luke

 =Austin
 


Re: Control flow variables

2003-11-18 Thread Luke Palmer
Austin Hastings writes:
 
 
  -Original Message-
  From: Michael Lazzaro [mailto:[EMAIL PROTECTED]
  Sent: Tuesday, November 18, 2003 2:06 PM
  To: [EMAIL PROTECTED]
  Subject: Re: Control flow variables
 
 
 
  On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
   Given that we've introduced the concept of if having a return status:
  
 my $result = if ($a) { $a } else { $b };
  
 
  Would that then imply that
 
   sub blah {
 ...  # 1
 return if $a;# 2
 ...  # 3
   }
 
  ...would return $a if $a was true, and fall through to (3) if it was
  false?
 
 
 It sure should, provided there were a correct context waiting, which would
 quite nicely address another WIBNI thread a couple of months back about a
 quick return under those conditions.

I don't think so.  I say that all the time to mean precisely:

if $a { return }

And I don't think people are ready to give that up. 

In particular, if we kept our bottom-up parser around, this particular
construct would cause an infinite-lookahead problem.  So for ambiguity's
sake, Cif $a should not be a valid term without a block following.

Luke


Re: Control flow variables

2003-11-18 Thread Luke Palmer
Austin Hastings writes:
 
 
  -Original Message-
  From: Michael Lazzaro [mailto:[EMAIL PROTECTED]
  Sent: Tuesday, November 18, 2003 2:06 PM
  To: [EMAIL PROTECTED]
  Subject: Re: Control flow variables
 
 
 
  On Tuesday, November 18, 2003, at 06:38 AM, Simon Cozens wrote:
   Given that we've introduced the concept of if having a return status:
  
 my $result = if ($a) { $a } else { $b };
  
 
  Would that then imply that
 
   sub blah {
 ...  # 1
 return if $a;# 2
 ...  # 3
   }
 
  ...would return $a if $a was true, and fall through to (3) if it was
  false?
 
 
 It sure should, provided there were a correct context waiting, which would
 quite nicely address another WIBNI thread a couple of months back about a
 quick return under those conditions.

Oh, and if you really want to do that return thing without using a
Cgiven, you can just:

sub blah {
return $a || goto CONT;
CONT:
...
}

I don't see what's wrong with that. :-p

Luke


Re: Control flow variables

2003-11-18 Thread Luke Palmer
Damian Conway writes:
 Luke Palmer started a discussion:
 
 
 I see this idiom a lot in code.  You loop through some values on a
 condition, and do something only if the condition was never true.
 $is_ok is a control flow variable, something I like to minimize.  Now,
 there are other ways to do this:
 
 if (0..6 == grep - $t { abs(@new[$t] - @new[$t+1]) })
 { ... }
 
 But one would say that's not the cleanest thing in the world.
 
 Only because you overdid the sugar. :
 
 if grep {abs(@new[$^t] - @new[$^t+1])  3} 0..6
 { ... }
 
 is pretty clean.

Right, but I messed it up, which isn't that important until later:

unless grep {abs(@new[$^t] - @new[$^t+1])  3} 0..6
{ ... }

Yeah, it is cleaner (I really like to put the list up in the front seat,
but in this case it doesn't help), but it's not really *clearer*, IMO.
Still a bit too poetic to read easily, IMO.

 But, in any case, handling exceptional cases are what exceptions are for:
 
 try {
 for 0..6 - $t {
 die if abs(@new[$t] - @new[$t+1])  3;
 }
   CATCH {
 push @moves: [$i, $j];
 }
 }

And that's exactly equivalent to:

for 0..6 - $t {
if abs(@new[$t] - @new[$t+1])  3 {
push @moves: [$i, $j];
last;
}
}

Which also eliminates the control variable.  My Cif/Cunless typo may
have misled you, but the original example pushed only if *none* of them
passed the condition.

[snip]
 So we might also write:
 
 for 0..6 - $t {
last if abs(@new[$t] - @new[$t+1])  3;
 }
  7 and push @moves: [$i, $j];

Providing the semicolon rule doesn't bite us in the curly brace.

Hmm, you inspired a fine ambiguity:

if $something { 
... 
} 
 7 and $foo  if $something_else { ... }

Maybe control structures shouldn't return values after all :-p

(I honestly don't know what I have against that, other than fear that
someone might actually use it)

Luke


Re: Control flow variables

2003-11-18 Thread Luke Palmer
Austin Hastings writes:
  From: Luke Palmer [mailto:[EMAIL PROTECTED]
 
  Austin Hastings writes:
From: Michael Lazzaro [mailto:[EMAIL PROTECTED]
   
Would that then imply that
   
 sub blah {
   ...  # 1
   return if $a;# 2
   ...  # 3
 }
   
...would return $a if $a was true, and fall through to (3) if it was
false?
   
   
  In particular, if we kept our bottom-up parser around, this particular
  construct would cause an infinite-lookahead problem.  So for ambiguity's
  sake, Cif $a should not be a valid term without a block following.
  
 
 How on earth are you going to have an infinite lookahead problem when a semicolon is 
 the next character?

Sorry, s/\$a/some-hideously-long-condition/

Luke

 =Austin
 


Re: syntax: multi vs. method

2003-11-18 Thread Luke Palmer
Larry Wall writes:
 If you write:
 
 multi method add( $self: Foo $foo, Bar $bar );
 
 then there are multiple add methods in the current class.  Note the
 invocant is not optional in this case.  Also, there's an implied
 second colon after $bar, indicating the end of the arguments to be
 considered for multi dispatch.  (You can put as many colons as you
 want in any multi declaration--each subsequent colon indicates that
 the preceding additional argument or arguments are to be used as
 tie breakers, just as Foo and Bar are being used for tie-breaking
 in the method above.)  

So what is the, ahem, submethod for determining the dispatch within the
tie-breaking cascades?  A simple sum of differences?  Cartesian
distance? 

Luke

 Larry


Re: Control flow variables

2003-11-19 Thread Luke Palmer
Jonathan Scott Duff writes:
 On Tue, Nov 18, 2003 at 11:37:22PM +0100, Seiler Thomas wrote:
  So... lets call a function instead:
  
  my $is_ok = 1;
  for 0..6 - $t {
  if abs(@new[$t] - @new[$t+1])  3 {
  $is_ok = 0;
  last;
  }
  }
  if $is_ok {
  yada()  # has sideeffects...
  }
 
 my $t = 0..6;
 yada() if none(abs(@new[$t] ^- @new[$t+1]))  3;
 
 :-P

Ghod I love junctions.  :-)

Luke

 -Scott
 -- 
 Jonathan Scott Duff
 [EMAIL PROTECTED]


Re: Control flow variables

2003-11-19 Thread Luke Palmer
Piers Cawley writes:
 All of which means you can wrap it up in a macro and prove Simon's
 point about what's syntax and what's CP6AN:
 
macro unless_all( Block test is parsed /perl.expression/,
  Block consequence, [EMAIL PROTECTED] ) 
  { my $guard = Object.new;
for [EMAIL PROTECTED], $guard 
  - { when $guard { consequence() ; last }
   when test { last } } }
 
 But I've probably got the signature slightly wrong. 

I think the only thing that's wrong with your signature is that you said
macro instead of sub.  Well, and test has to be finessed into an
executable block somehow, but we're not supposed to know how yet.

 Higher Order Functions/Methods/Macros are great aren't they? 

What a modern thinker!  Use a *function* to do a common task?  *What*
are you talking about!?  :-)

Luke


Re: Control flow variables

2003-11-19 Thread Luke Palmer
Gordon Henriksen writes:
 Larry Wall wrote:
 
  On Tue, Nov 18, 2003 at 06:28:59PM -0500, Gordon Henriksen wrote:
  
   my @b = for @a - $_ {
   ...
   }
  
  That will be a syntax error. Generators are too mind-stretching to
  inflict on novices [...]
 
 I making the point that within the context of this we-wish-loops-were-
 expressions discussion, the for expression was simply another way
 to spell map, at least when autoiterating an array.
 
 I certainly wasn't thinking in terms of coroutines--they absolutely
 deserve a large syntactic barrier.

I don't think generate{} and yield() were supposed to indicate
coroutines.  Instead, it's more like Mathematica's Sow[] and Reap[],
which would work (Perl6-ized) as follows:

@a = reap { 
sow 1;
some-other-statement;
sow 2;
}  # @a is (1,2)

It's a nice concept; it simplifies certain kinds of list processing
greatly.  It would easily be implemented with coroutines, which might
also explain the yield().

Luke



Re: Parsing macros (was: Control flow variables)

2003-11-20 Thread Luke Palmer
Jonathan Lang writes:
 Larry Wall wrote:
  So far we've only allowed is parsed on the macro itself, not on
  individual arguments.  Still, that's an interesting idea.
 
 Forgive me if this has already been addressed, but this could have some
 useful applications:
 
 So far, everything I've read about macro parsing concentrates on parsing
 the positional arguments; I haven't seen anything about how to go about
 defining a custom parse rule for the list arguments.  In particular, I'm
 thinking about something along the lines of: 
 
   macro element(name, [EMAIL PROTECTED] is parsed /\s+/) 
 is parsed / \ /? (QName) \s* (.*?) /? \ /
 {...}
 
 where the is parsed trait of the list parameter defines a rule used to
 split the string fed into it into a list of arguments.  

You can only split what is passed in as much as you can split a parse
tree.  The best one can do here is grab text, split, and reparse each of
the segments.  That's not hard to do manually, and I think it best be
done manually.  There's only so much complexity you can pack into a
signature and still make it thinkable.

 I could see something similar being done for named parameters, but you'd
 need to define both a split rule and a name-vs-value parse rule, and
 you'd have to address if (and if so, how) a named parameter can be
 inserted between positional and/or list parameters.  

Again, too much complexity for the payoff.  Code it manually.  (Which
might mean using a proxy sub to do the parsing, which forwards the call
along to the content, so you can get Perl's semantics with your
syntax).

As much as I do like adding useful features to the language, I do think
we have to solve our own problems *sometimes*. 

Luke



Re: Control flow variables

2003-11-20 Thread Luke Palmer
Jonathan Scott Duff writes:
 On Wed, Nov 19, 2003 at 12:49:21PM -0800, Larry Wall wrote:
  Sorry, I wasn't being very clear.  It wouldn't be logically attached to
  the outside of the for, but to the inside of the confer, or whatever:
  
  @foo = gather {
  for @a - $x { pick $x if mumble($x) }
  DEFAULT { @results }
  }
 
 So ... the only way to get Damians semantics ...
 
 On Wed, Nov 19, 2003 at 08:01:40AM +1100, Damian Conway wrote:
  * vector control structures like Cloop, Cwhile, and Cfor in
a list context return a list of the values of the last statement
each iteration evaluated;
 
  * vector control structures like Cloop, Cwhile, and Cfor in
a scalar context return an integer indicating the number of
times their block was iterated.
 
 ... is to surround the control structure with a gather { ... }  ??

No.  gather{} is a generator (assuming nothing about its name or
existance whatsoever).  It runs some code, gathering up each pick()
(same assumption) into a list, and returning that.

If I interpret Larry correctly, Damian's semantics won't be going in.
The way you get each of those is:

my @list = gather {
while $cond {
pick do {...}
}
}

And similarly for each of the other constructs.

But Damian's semantics will work for simple conditionals, it seems.

One wonders what the return value of a loop will be:

my $what = do {
while $cond {...}
}

Luke

 It seems like gather or whatever should be some sort of modifier to
 for/loop/while/until
 
   @foo = for : gather @a - $x { ... }
   if for : gather @a - $x { ... }  3 { ... }# ick!
   if : gather for : gather @a - $x { ... }  3 { ... }   # ick!**2
   for : gather @a - $x { ... } or @results;
   for : gather @a - $x { ... } or do { ... }
 
 Okay, so the syntax isn't great.  I'm just brainstorming.
 
 Having a gather block just feels wrong to me. It's weird to say that
 control structure X only has a result when placed inside of a special
 block. But maybe it *needs* to be weird.
 
  On the other hand, putting the default up front is clearer if the
  block is long.  Could even be something like:
  
  @foo = gather is default(@results) {
  for @a - $x { pick $x if mumble($x) }
  }
 
 Hmm.
 
   @foo = for :gather,default(@results) @a - $x { ... }
 
 -Scott
 -- 
 Jonathan Scott Duff
 [EMAIL PROTECTED]


Re: s/// in string context should return the string

2003-11-22 Thread Luke Palmer
David Chan writes:
 Hmmm.  When doing multiple substitutions, it would be nice to avoid a
 hard-to-read nested function call which reads backwards, a la python:
 
   return re.sub('','gt;',re.sub('','lt;',re.sub('','amp;',text)))
 
 ... but to also avoid multiple statements like this:
 
   my $tmp = $_;
   $tmp =~ s//amp;/g;
   $tmp =~ s//lt;/g;
   $tmp =~ s//gt;/g;
   return $tmp;

Well, assuming we have:

method Str::s(Pair $sub) returns Str {...}

We can write:

.s(//  = 'amp;')
.s(/\/ = 'lt;')
.s(/\/ = 'gt;');

But that's not great (not bad, though).  But it's been recognized for
awhile that substitutions like these need behavior more like a
generalized tr:

.s(//  = 'amp;',
   /\/ = 'lt;',
   /\/ = 'gt;');

Both of these, of course, poses a problem with the scope of $1 et al.,
which can be fixed by:

.s(/ \ (\w+) \ / = { do_stuff(.{1}) })

But that's starting to look pretty convoluted, and pretty unperlish.



 But maybe it'd be useful to have more visual weight than 's' carries:
 
   return $_.s:e//amp;/.s:e//lt;/.s:e//gt;/;   # line noise?

Only if you write it that way.  Most of perl can be line noise if you
want it to.

return .s:e/   /amp;/
   .s:e/ \ /lt;/
   .s:e/ \ /gt;/;

Not so different from my first example above, except slightly more
traditional.  The fact that it's a method call means we don't have to
use ~~, which is a big win :-)

This still doesn't quite seem right...

   return $_.sub:e(,amp;).sub:e(,lt;).sub:e(,gt;) # awkward
   return $_.sub:e()(amp;).sub:e()(lt;).sub:e()(gt;) # hmmm
 
 But I forget whether we're allowed space by the dot, which could help.
 
   return $_ . s:e//amp;/ . s:e//lt;/ . s:e//gt;/;   # readabler

Whitespace is allowed before the dot, but not after it.  At least that's
the case when you're subscripting; method calls might be a different
story.

Luke

 -- 
 $_=.--- ..- ... -  .- -. --- -  . .-.  .--. . .-. .-..   .- -.-..
  -.- . .-.\n;s!([.-]+) ?!$_=$1;y/-./10/;$_=chr(-1+ord packB*,01.0 x(5
 -length).1$_);y/DWYKAQMOCVLSFENU\\IGBHPJXZ[~nfb`_ow{}/a-z0-9/;$_!ge;print
 


'catch' statement modifier

2003-11-23 Thread Luke Palmer
I was reading over some code that used the MIDI module, and saw the
Cwrite_to_file method.  I began wondering, how does one report the
error if he feels like it, but let the module report the error if not,
in a concise way.

What about something along the lines of a Ccatch statement modifier,
like:

$opus.write_to_file($file) catch die Couldn't write to $file: $!\n;

Which would be equivalent to:

try {
$opus.write_to_file($file);
CATCH {
die Couldn't write to $file: $!
}
}

It doesn't read quite as nicely as I'd like, but I think it could be a
very useful notation.  After all, if I have to type a lot when I'm
handling errors, I'll prefer not to handle them at all.

Which reminds me, if you throw an exception inside a CATCH block, does
it propogate outside to be caught by other CATCHes in the same block
that are lexically lower, or does it propogate outside of the enclosing
scope.  That might be a little confusing... for example:

try {
try {
do_something();  # Throws
CATCH { die Foo }
CATCH { die Bar }
}
CATCH { print $! }
}

Does that print Foo or Bar?

Luke


Re: 'catch' statement modifier

2003-11-24 Thread Luke Palmer
Damian Conway writes:
 Hmm. I think I may have missed Luke's point. Which was (presumably):
 what if C$opus.write_to_file($file); validly returns Cundef?
 
 In which case I think we just fall back to:
 
 try{$opus.write_to_file($file); CATCH {die Couldn't write to $file: 
 $!}}
 
 which is, after all, only 5 characters longer than:
 
 $opus.write_to_file($file) catch die Couldn't write to $file: $!\n;
 
 ;-)

Fair enough :-)

No, I wasn't implying that Cwrite_to_file could validly return undef.  
I just failed to realize how short the long version was.  

But you have to admit, the latter version makes the important part of
the expression stand out, and is more natural to write (IMHO, as
always).

But it's moduleable, so I won't worry about it.

Luke

 Damian
 
 


The C Comma

2003-11-24 Thread Luke Palmer
Honestly you guys, I'm not trolling.  I'm just getting a lot of ideas
recently. :-)

The C comma has always bugged me, but its function is indeed useful
(many times I use Cand in its place, if I know the left side will
always be true). I don't know whether it's staying or not (I've heard
rumors of both), but I'd suggest that it leave and allow itself to be
replaced by a word, alongside Cand, Cor, and Cerr.

This word:  Cthen.  

So, from a recent script of mine:

my $n;
while $n++ then @accum  $total {
...
}

(Where I got in trouble for using Cand and never executing anything :-)

To me, it's very clear what's going on, and eliminates the mystery of
the comma in scalar context for a syntax error.

Luke


Re: Control flow variables

2003-11-25 Thread Luke Palmer
Piers Cawley writes:
 Simon Cozens [EMAIL PROTECTED] writes:
  But it isn't, and I don't know why it isn't, and so we end up
  spending loads of time discussing things that can be punted out to
  modules. Designing Perl 6 is hard enough; let's not try to fill
  CP6AN at the same time.
 
 But the vast majority of us *aren't* designing Perl 6, that's Larry
 and his team's job. We're in the position of taking the work that's
 been done on the language so far and working out how we'd use it (and
 yes, we're in the business of thinking about the sort of thing
 that will go in CP6AN). Considered in that light, Luke's question is a
 really good one, it points up an ugly idiom and considers how one
 would generate a better idiom in Perl 6. Where he falls down is in
 proposing new syntax to solve the problem rather than in proposing the
 new syntax and then offering a sketch of its implementation as a macro
 in Perl 6. After all, problems with 'implemented' solutions are simply
 demonstrations that the design is sound, and that's good feedback to
 Larry and his team. These things only become real design issues if
 there appears to be no good way to solve such problems. 

Ok, back to the concrete side of things then.  How *would* one implement
a new loop hook?

Let's look at Cwhile.  It might be implemented as such:

my sub while_impl(cond, block) {
my cc := Continuation.new;
try {
block.PRE.() if block.PRE;
if cond() {
block();
throw X::Next;
}
else {
throw X::Last;
}
CATCH { 
when X::Next { block.NEXT.() if block.NEXT; cc() }
when X::Last { block.POST.() if block.POST; }
}
}   
}

macro while($cond, $block) {
my (cond, block) := ($cond, $block).parse;
return - { while_impl(cond, block) }
}

Neglecting things like Credo.  And so to implement FINISH, you'd need
to stick a Cblock.FINISH.() if block.FINISH right before Cthrow
X::Last.

But it would be really nice if you could do this without rewriting
Cwhile.  One way is to wrap cond:

wrap cond: {
call or _.FINISH.()
};

But then you need to associate FINISH with the condition instead of the
execution block.  Or just wrap it when you can see the FINISH block.
Like:

macro FINISH($code) {
# When it's a macro/rule, caller naturally returns the parse stack
CallerContext $c = caller Perl6::Grammar::while;

my code := $code.parse;
$c[-1].MY.{'cond'}.wrap({
call or code()
});
return - {};
}

Okay, that's pretty evil.  Pretty really evil.  I took a currently
executing sub, extracted, and Ichanged one of its lexicals.  Evil
enough to make the optimizer very unhappy, in any case.

But such is the life of the Aspect-Oriented programmer.

Can anyone think of a cleaner way?

Luke




Re: The C Comma

2003-11-25 Thread Luke Palmer
Austin Hastings writes:
 
 
  -Original Message-
  From: Adam Turoff [mailto:[EMAIL PROTECTED]
  On Tue, Nov 25, 2003 at 01:03:19PM +1100, Damian Conway wrote:
   Schwern observed:
 
   Perhaps this is yet another argument for insisting on:
  
 while do {$n++; $foo  $bar}
  
   instead.
 
  That looks like syntactic sugar for
 
  while (do) {$n++; $foo  $bar}
 
  and could be interpreted as either:
 
  while do {...}  ## perl5 bareword
  while do() {...}
 
  Luke's then feels like the best fit on the one hand, and the worst fit
  on the other.  Everything else feels worse, though.
 
 Hmm. Why not just explicitly allow semicolon when surrounded by parens?
 
   while ($n++; $foo  $bar) {...}

Well, because the intent of the original proposal was to fatten up the
C comma to make it explicit, easy to see, and clearly unambiguous.  A
semicolon does none of these things.  It also, as you mention, prevents
the compiler from catching a rather common syntax error.

But other than that, uh, sure.  Providing we spell parens C do{} .  :-)

 Removing the parens changes the results, which is just what you'd expect
 mathematically.
 
   $f = (0, 1, 2, $n++, $foo  $bar);# List
 
   $f = (0; 1; 2; $n++; $foo  $bar);# Sequence of statements, three
 useless.
 
 C style Cfor loops then look like:
 
   for (($a = 0; $b = $num_elts); $a  @arry; ($a++; $b -= $offset)) {...}

By which you mean

loop ($a = 0; $b = $num_elts); $a  @arry; ($a++; $b -= $offset)
{...}

right? 

Perhaps my favorite syntactic thing Perl 6 has done so far is gotten rid
of those dastardly parens on control constructs!  Yay!

Luke

 
 Which is on the one hand yucky, but on the other hand very explicit.
 
 (I suppose I could propose using semicolon for the list separator, but that
 would drive the syntax-highlighters insane, and I like syntax-highlighting.)
 
 =Austin
 
 PS: An immediate drawback that occurs to me is that of catching unbalanced
 parens -- when the statement terminator is a valid sequence delimiter, all
 the rest of the code looks like a sequence. But the first nesting closing
 brace would probably catch that.
 


Properties

2003-11-27 Thread Luke Palmer
Here's a series of questions/confirmation requests about how properties
work (but specifically run-time properties, not traits):

Use Cbut to assign a property to a Ivalue:

$a = $b but foo;   # $a has property foo, $b does not

Properties are just out-of-band methods:

if $x.foo { print $x has property foo }
$x.bar = 1;   # Or $x = $x but bar

Which makes meta-properties (eg. Cnothing) easy to fathom.

(That one seems a little dangerous from an error checking point of view.
Is there such thing as a 'method not found' error?)

To get a hash of out-of-band properties, use either the Cbtw or the
Cprops method, depending on whether our language designers are feeling
cute.

Luke


Re: Properties

2003-11-29 Thread Luke Palmer
Paul Hodges writes:
 Larry Wall writes:
  Perl 5 didn't allow exportation of lexicals because typeglobs only
  dealt with package variables, not lexical variables.  In Perl 6
  we'll be able to alias both lexicals and package variables.  That
  implies that a lexically scoped name can be exported, whether it
  refers to a variable or something else like a property.
 
 So a role defined in one module can be scoped lexically so as not to
 trample another module's namespace, and the use()'er of that module can
 elect whether ot not to export that role into his own space for
 implicit use on other objects. Accordingly, if Foo implements a zippy
 property, and Bar does as well, and both are polite enough about it to
 make then the equivelent of EXPORT_OK, then I can say
 
   use Foo 'zippy';
   use Bar;
   use Baz;
 
   my Baz @ray = ( Baz.new() );
   $ray[0] but= zippy;
 
 But just for the sake of clear understanding, suppose I pushed onto
 @ray a whole passle of Foos and Bars and Bazzes. All the Foos and
 Bazzes could use Foo's zippy. If I say
 
   push @ray, Bar.new();
   $ray[-1].zippy = woohoo!;
 
 then Bar's zippy would be used by default, right?

I think so.  If Bar has a zippy method, then that zippy method is called
instead of setting the property.  Which are really the same thing.  So,
um, yes.

 Now the hard question.
 
   my $tst = Baz.new();
 
 How do I set a zippy property on $tst explicitly using Bar's zippy?

Probably just

$tst but= Bar::zippy;

I imagine that properties work just like other names, so they can be
stuck in package symbol tables, too.

 Is that possible? Baz has no zippy, so I'd have to use but, right?
 How about
 
   $tst but= Bar.zippy;  # is zippy a class property?  
   $tst but= Bar::zippy; # is zippy a class method? do I need a  ??

Yeah, the latter one.  Note that class methods are called like:

Bar.zippy;

now, so there's no ambiguity.  Hooray.

 Or is this even possible?  

Please, we're talking about Perl... :-)

Luke


Re: Properties

2003-12-01 Thread Luke Palmer
Hodges, Paul writes:
 I assume you're setting the the value, so I think I understand it, but
 how about
 
   sub setvals ($o, [EMAIL PROTECTED]) { 
   $o but= $_; 
   $o.$_ = true; 
   }
 
 Though I'm still iffy about that $o.$_ business.  I think
 $_(true) is better. I'm just fumbling for perspective.

Y'all seem to be missing a Cfor somewhere :-)

sub setvals ($o, [EMAIL PROTECTED]) {
$o but= $_ for @t;
}

I think that should work, as the right side of Cbut should always be a
property, so a property reference ought be interpreted correctly.

 One thing, though could I do this? =o}
 
   my property (foo,bar,baz) ^is true;
   $thingy ^but= (foo,baz);

No, but you might be able to if you used proper vectorizing syntax ;-)

my property (foo,bar,baz) is sometrait;  # is automatically distributes
$thingy but= (foo,baz);

Ctrue doesn't seem like a trait you would put on a property.  Ctrue
is a run-time property, and I think it would be awfully confusing to
make it a trait as well.  If you're talking about some kind of
initialization, you might use:

my property (foo,bar,baz) is first(1);

Or Cis might be correct if you're -- somehow -- deriving these
properties from the Ctrue property.  But I don't think that was the
intent.

 I'm pretty sure that syntax is way wonky -- would is be a
 vectorizable operator?  Does it even qualify as an operator at all?

Cis is definitely an operator, much in the same way Cmy is an
operator.  Whether it's vectorizable is questionable, because in all
cases I've seen the vectorization is implicit.  That is, if it has a
non-vector meaning, the meaning of:

my ($a,$b,$c) is foo;

is a little fuzzy.  What's Cis applying to if it's not applying to all
of $a, $b, and $c?

   then write allow() to build roles for each value passed in, 
   maybe taking an arg to say whether they should be truly global,
   or built in  the caller's namespace 
  
  Isn't that what my, our, Exporter, and the globalifying * are 
  all about?
 
 Probably, though I haven't seen anything yet about how the P6 version
 of the Exporter is going to handle things like specifying exportation
 of my() vars co.

I'm pretty sure that the interface to Exporter can be cleaned up quite a
bit in Perl 6.  For now, though, I think it's fine to assume it works
exactly like Perl 5's.

Luke



Re: OP [was: Re: Properties]

2003-12-02 Thread Luke Palmer
Michael Lazzaro writes:
 
 On Monday, December 1, 2003, at 01:05 PM, Hodges, Paul wrote:
 Didn't know is would do that. Good to know!
 And in my meager defense, I did reference MikeL's operator synopsis as 
 of
 3/25/03, which said ^[op] might be a synonym for  or  (Sorry, 
 no
 fancy chars here. :)
 
 Hey, that was *March*!  ;-)  The fossil records from that time are 
 fragmentary, at best.
 
 I don't think I ever saw any further reference to the ^[op] syntax 
 staying alive; I assume that means it's dead.  Last I heard, which was 
 admittedly around the same time frame, we'd have the non-Unicode-using 
 op, and a Unicode synonym op, and that's it.
 
 There were also vaguely threatening proposals to have op and op 
 do slightly different things.  I assume that is also dead, and that 
 op is (typically) a syntax error.

Ack.  No, slightly different things would be a very bad idea.

At the moment, as most of you probably know, they do *very* different
things.   op vectorizes the operator, and some stuff is
equivalent to qw{some stuff}. 

And as far as I know,  and  are exactly equivalent to  and  in all
cases.

Luke

 If anyone in the know knows otherwise, plz verify for Piers' summary 
 and the future fossil record.
 
 MikeL
 


Re: OP [was: Re: Properties]

2003-12-02 Thread Luke Palmer
Luke Palmer writes:
 And as far as I know,  and  are exactly equivalent to  and  in all
 cases.

By which I mean  and , of course.  :-/

(mutt is kind of a pain in this area)

Luke



Re: Properties -- distributive, predeclared, post-applied....??

2003-12-04 Thread Luke Palmer
Hodges, Paul writes:
 How about
 
   use Baz; # assume object type
   my property foo;
   my @bar of Baz is false but foo; # maybe not what you meant?

Definitely not what you meant.  Fortunately, the compiler will teach you
a thing or two about it:  Cfalse is not a trait.  

But indeed foo would apply to @bar itself, rather then to any element
that goes into @bar later.

 If you apply a trait like false to an array, I expect it to apply to the
 array instance object itself and not the content, so that 
   push @bar, Baz.new();
   if @bar{ print stuff; } else { print empty; } # oops! false!
   if @bar[0] { print  oops; } else { print  ok;   } # oops! not false!
 would print empty oops instead of stuff ok. 

 I'd *like* to be able to predeclare a trait or property to be distributed
 across any values placed in this array, but only this array. For example, it
 would be nice if I could have the default aspects of false and foo be
 applied to any Baz that gets stuck into @bar, but obviously this isn't the
 syntax to do it. I could make Baz's new() do it, but I don't want *ALL* Baz
 objects to be false and foo...just the ones in @bar. So, what I need is
 something more like
 
   my @bar of Baz;
   @bar.STORE.wrap { my $r = call; return $r but= (false,foo); }

Something likely more like:

my role property_wrap[Property [EMAIL PROTECTED] {
method STORE($newval) { SUPER::STORE($newval but [EMAIL PROTECTED]) }
}
@bar but= property_wrap[false, foo];

With emphasis on something.  (Extrapolating wildly the little bit I
know about roles and making up some semantics, such as Cbut [EMAIL PROTECTED]).

As for just declaring it, um... why would you want to do that?  I could
see making the array default to some value with a trait, which is
trivially:

my @bar is default(undef but foo);

But automatically marking every value that ever goes into the array... I
don't see the utility.

 But I'm not sure C$r but= (false,foo) works, and I really wanted to
 figure out a way to do it all in the declaration. Maybe it could be
 
   my @bar of Baz will do STORE.wrap { call but= (false,foo); }

Yeah, that's definitely not right.  Cwill works as follows:

:w declaration will identifier block

It's really just a shorthand for Cis, so you don't have to put parens
around the block.

 but I'm not sure call will behave as an lvalue and still set up the
 appropriate return, I don't expect @bar to accept will do, and I don't
 think will do is where the wrap should go. I'm just trying to wrap my
 brain around this brick and I can't find all the references that tell me all
 the little pieces so that I can compare them for a closer approximation,
 lol

Luke



Re: Properties -- distributive, predeclared, post-applied....??

2003-12-04 Thread Luke Palmer
Paul Hodges writes:
 Luke Palmer:
  Something likely more like:
  
  my role property_wrap[Property [EMAIL PROTECTED] {
  method STORE($newval) { SUPER::STORE($newval but [EMAIL PROTECTED]) }
  }
  @bar but= property_wrap[false, foo];
 
 ...square brackets?
 ...roles can have methods? duh, they'd have took
 ...but, *square* brackets???

Yeah.  Classes use square brackets when they're parametric, so I could
only assume roles do, too.  That is, if you haven't seen this before:

class RingBuffer[$size, Class ?$of = Any] {
has @.buffer of $of is dim($size);
has ($.front, $.back, $.fill);

method push($elem of $of) returns Void {
@.buffer[$.back++] = $elem;
$.back %= $size;
$.fill++;
}

method shift() returns $of {
if $.fill = 0 { throw X::BufferEmpty }  # predeclared
return @.buffer[$.front++];
LAST { $.front %= $size }
}
}

I do have one question for the almighty gods, however.  Can you
explicitly use the :: sigil to make a lexical parametric class, as in:

class RingBuffer[$size, ?::of = Any] {
has of @.buffer;
}

Well, modulo the possible ambiguity of the keyword of.  Perhaps ::of
would have to be there, too...?

 And C but [EMAIL PROTECTED]  looks like but is distributive.
 I think that's good, but not what I inferred from your last note on the
 topic.

I didn't say anything about Cbut not distributing over its Iright
argument :-)   It does, after all, make sense, as you'd probably not be
allowed to mark a property with the @ sigil.

  As for just declaring it, um... why would you want to do that?
  I could see making the array default to some value with a trait,
  which is trivially:
  
  my @bar is default(undef but foo);
  
  But automatically marking every value that ever goes into the
  array... I don't see the utility.

[snip]

 Usually I end up keeping track of some feature by putting all things
 with this feature into THIS array and all things like that into THAT
 array or some such parallel silliness. It works, and is faster than
 practically any object code on our poor old nag of a workhorse server,
 but then if I have to know which stack something came from when I send
 it to a sub I have to include another argument. There are LOTS of
 alternate ways to mark things, but I like this one.

Oh, okay.

And declarative is usually much nicer to read than procedural, so that
makes sense.

As far as I can tell, it's not possible without building some machinery
yourself, like we did above.  That's okay though: we should be expected
to program generic solutions every once in awhile.

   But I'm not sure C$r but= (false,foo) works, and I really
   wanted to figure out a way to do it all in the declaration. Maybe
   it could be
   
 my @bar of Baz will do STORE.wrap { call but= (false,foo); }
  
  Yeah, that's definitely not right.  Cwill works as follows:
  
  :w declaration will identifier block
  
  It's really just a shorthand for Cis, so you don't have to put
  parens around the block.
 
 But subs in A6 have a will do, though I presume the do is optional?

You can leave out the Cdo if you like, but you also have to leave out
the Cwill in that case.  For instance:

sub foo() { ... }

Is short for:

sub foo() will do { ... }

Which is in turn short for:

sub foo() is do({ ... })

Er, for some definition of 'short' :-)

 Hmmstill aware that this isn't a sub declaration,
 
   my @bar of Baz will init { 
  .STORE.wrap { call but= (false,foo); }
   }
 
 I still like the idea that call could set itself up as an lvalue.
 ~smirk~
 
 So is it possible that this is a valid way to declare a container with
 modified methods all at once?

It would seem so.  It's not a particularly clean one (even though it may
be clean *looking*).  You might be able to do some jazz like this:

my Baz @bar but property {
method STORE($elem) { call($elem but (false, foo)) }
}

Where you're applying an anonymous property.

Luke



Re: Properties -- distributive, predeclared, post-applied....??

2003-12-05 Thread Luke Palmer
Jonathan Scott Duff writes:
 On Thu, Dec 04, 2003 at 05:57:52PM -0700, Luke Palmer wrote:
  Hodges, Paul writes:
   I'd *like* to be able to predeclare a trait or property to be distributed
   across any values placed in this array, but only this array. For example, it
   would be nice if I could have the default aspects of false and foo be
   applied to any Baz that gets stuck into @bar, but obviously this isn't the
   syntax to do it. I could make Baz's new() do it, but I don't want *ALL* Baz
   objects to be false and foo...just the ones in @bar. So, what I need is
   something more like
   
 my @bar of Baz;
 @bar.STORE.wrap { my $r = call; return $r but= (false,foo); }
  
  Something likely more like:
  
  my role property_wrap[Property [EMAIL PROTECTED] {
  method STORE($newval) { SUPER::STORE($newval but [EMAIL PROTECTED]) }
  }
  @bar but= property_wrap[false, foo];
  
  With emphasis on something.  (Extrapolating wildly the little bit I
  know about roles and making up some semantics, such as Cbut [EMAIL PROTECTED]).
 
 What's the difference between what you have above and this:
 
   my property property_wrap (Property [EMAIL PROTECTED]) {
  method STORE($newval) { SUPER::STORE($newval but [EMAIL PROTECTED]) }
   }
   @bar but= property_wrap(false, foo);
 
 ? The examples I remember from the As and Es all have round brackets
 around trait parameters (Hmm. And I can only remember is-trait examples
 too). Granted, the universe could have shifted under my feet without my
 knowledge.

No, it was just a braino on my part.  I forgot that I've already seen
parametric properties in a lot of places... :-/

 I discovered after reading this email that I've been assuming that
 square-bracket parameterization happened at compile-time while
 round-bracket parameterization was, of course, run-time.  I don't know
 if that's even partially true though.  If that isn't the distinction,
 then what is?  Why the two bracket styles?

It's a manifestation of different things should look different.  If
classes look too much like subroutines, things would get confusing and
hard to read.  I don't think it's necessarily a compile-time thing, as
one would expect this to work:

class Foo[Int $param] {...}
sub make_foo(Int $param) {
Foo[$param].new;
}

I wonder if we'll have C++-like template specialization... I'd like
that, especially since Perl would keep from inventing a new language in
the process.

multi class PrintBasic[Class $of] {
method go() { print Non-basic; }
}
multi class PrintBasic[Int|Num|Str] {  #  Can I do that?
method go() { print Basic; }
}

Hmm.

Luke

 -Scott
 -- 
 Jonathan Scott Duff
 [EMAIL PROTECTED]


Re: Missing branch instructions?

2003-12-08 Thread Luke Palmer
Pete Lomax writes:
 I'm not convinced at all here. PMC comparison ops, afaict, are based
 solely on the pmc instance/address
 
 Here's a snippet to play with:
 
   $P1 = new Array
   $P1 = 2
   $P1[0] = 1
   $P1[1] = 1
   $P2 = new Array
   $P2 = 2
   $P2[0] = 1
   $P2[1] = 1
 # eq $P1, $P2, _L3
   eq fred, fred, _L3
   print error \fred\!=\fred\
 _L3:
 
 
 Is $P1=$P2?

Nope.  Mostly because classes/array.pmc says:

/* == operation */
INTVAL is_equal (PMC* value) {
/* XXX */
return 0;
}

:-)

Luke



Re: Incorrect scoping of constants in IMCC

2003-12-09 Thread Luke Palmer
Pete Lomax writes:
 There's no file level locals yet either ;-)
 
 Can I ask a stupid question? Guess I'm going to anyway...
 
 Is there much benefit to .const, over sticking a value in a register
 and not modifying it? (which is what I've done to get round this)

Yes.  First, if you want more than 8 constants of some type, this isn't
the way to go, as you'll starve your registers, and things will get
quite a bit slower.  And in general, registers are for things that
change.  The constant table is for constants.

 How much benefit for a heavily used 0/1 flag?

If it never changes?  None.  It'll load it up from the constant table
just as fast as it'll load it up from a register.  This may be different
in the presence of JIT and caching, two things which I know nothing
about. But in the general case, no benefit at all.

 What about a lightly used string?

Same deal.  Except here I'm pretty sure there's no JIT benefit.

Luke


Re: [CVS ci] object stuff

2003-12-10 Thread Luke Palmer
Dan Sugalski writes:
 At 05:14 PM 12/5/2003 +0100, Leopold Toetsch wrote:
  set I2, P1[Foo\x00i]   # I1 == I2
 
 gets currently the attribute idx (0) of $Foo::i.
 Q: Should the assembler mangle the Foo::i to Foo\0i

 I don't like it either, but the alternative is to impose an external 
 hierarchic structure. Which we certainly could do, though it may make 
 some things more difficult.
 
 I'm more than willing to entertain arguments for and against the 
 hierarchic structure, but we're closing in on the point where we fix 
 the scheme and don't change it any more.

I'm not sure mangling is a good idea: think about anonymous classes.  If
we assign a name to each lexical class, then there are problems when one
instance of a class inherits from another instance of the same class.
That is:

sub make_class(Class $parent) {
return class is $parent {
has $.stuff;
}
}

my $class1 = make_class(Object);
my $class2 = make_class($class1);

So, if you name that lexical class _class_0001 or something,
_class_0001\0$.stuff refers to both attributes.

If you generate a name for each instance of a lexical class, you're
setting yourself up for some major runtime cost -- concatenating the
class name to the attribute on each access (or memory cost if you want
to cache).

I think a heirarchy is a good idea for namespacing in general.  I've
always wanted to be able to tie namespaces in Perl 5.  It would only
make sense that if I tie Foo::, that Foo::anything:: would also go
through that tie to get the anything:: stash.

There are, of course, disadvantages.  It would be slower for cases where
$something::or::other are acessed a lot, as it's three lookups in the
absence of cache.  Also, it's not as easy to tell where a symbol table
entry came from.  I don't think either of these are major concerns, but
it depends on our ultimate goals.

I definitely want to tie namespaces though.

Luke


Re: enums and bitenums

2003-12-11 Thread Luke Palmer
Larry Wall writes:
 Anyway, this all implies that use of a role as a method name defaults to
 returning whether the type in question matches the subtype.  That is,
 when you say
 
 $foo.true
 
 it's asking whether the Boolean property fulfills the true constraint.
 When you say
 
 $bar.red

So are you saying that, eg.

class Something does Color {...}
my Something $flib;

if $flib.red  { print Flib is red }
if $flib.true { print Should be an error before now }

Since Something doesn't Boolean, true would be a method not found
error? 

If that's the case, how do we attach out-of-band properties on objects
that don't expect them, but only some of them (as was the original
intent for properties, IIRC):

my role onlyonced;
sub onlyonce($arg is rw) {
die onlyonce called twice on the same value if $arg.onlyonced;
$arg but= onlyonced;
}

Either that doesn't work at all, because you get an onlyonced not
found error, or it works because onlyonced is a declared role.  But
in the latter case I worry about namespace pollution.

It's clear that I don't entirely understand all of this yet (er, as much
as there is to understand... yet).

Luke


Vocabulary

2003-12-12 Thread Luke Palmer
So I'm seeing a lot of inconsistent OO-vocabulary around here, and it
makes things pretty hard to understand.

So here's how Perl 6 is using said inconsistent terms, AFAIK:

- attribute
  A concrete data member of a class.  Used with Chas.

- property
  An out-of-band sticky note to be placed on a single object.
Used with Cbut.

- trait
  A compile time sticky note to be placed on a wide variety of things. 
Used with Cis.

- role
  A collection of methods to be incorporated into a class sans
inheritance (and maybe some other stuff, too).  Used with Cdoes.

So for example:

class Dog
does Boolean# role
is extended # trait
is Mammal   # [1]
{
has $.tail; # attribute
has @.legs; # attribute
}

my $fido = Dog.new
but false;  # property

Hope that clears things up.

Luke

[1] This is a base class, which is an overloaded use of Cis.  Though,
upon A12 release, we'll probably find out that it's not overloaded but
instead, elegantly unified, somehow. 


Re: Roles and Mix-ins?

2003-12-13 Thread Luke Palmer
Chris Shawmail (E-mail) writes:
 I'm still digesting the vocabulary thread, but while I do, let me ask a
 question that's probably crystal clear to everyone else.
 
 Do roles act as a form of mix-in, as Ruby modules may, and Objective-C
 protocols do?
 
 Would the following two snippets be at all equivalent?

Probably, depending on what's in the eventual definition of Foo.

Roles are quite similar to mixins (as the Traits paper said that they
were inspired by mixins), but they're distinctly not the same. 

For one, one role's methods don't silently override another's.  Instead,
you get, er, role conflict and you have to disambiguate yourself.  For
two, you can attach new roles to an object at runtime (I don't know if
you can do this with mixins, actually).

 # Perl6
 role Talk {
method say_hello {
   print Hello world!\n
}
 }
 
 class Foo does Talk { ... }
 
 Foo.new.say_hello;
 
 # Ruby
 module Talk
def say_hello
   puts Hello world!
end
 end
 
 class Foo
include Talk
 end
 
 Foo.new.say_hello

Luke



Re: enums and bitenums

2003-12-13 Thread Luke Palmer
Andy Wardley writes:
 Larry Wall wrote:
  Well, we can't use - because we're using that for something else.
  But it's certainly true that we'll have to have some mechanism for
  disambiguating Color.green from Blackberry.green.  After all,
  
  Blackberry.green == Color.red
  
  Or maybe it's
  
  Blackberry::green == Color::red
 
 [...]
 
  I don't know the syntax for
  disambiguating on the green end yet.  Maybe one of
  
  $foo ~~ Color::green
  $foo ~~ Color.green
  $foo ~~ Color[green]
  
  Or maybe something else.
 
 How about a single colon?
 
  Color:green 

 This is the same syntax employed in XML namespaces and URIs, for example:
 
 xml xmlns:color=http://example.com/xml/color.xsd;
   color:green/
 /xml
 
 Don't tell me, we can't use : because we're using that for something
 else.  :-)

Well, yes.  It's used in the operator position already for the indirect
object syntax, so I don't think that'll fly.

Keeping with the color example, let's think about what this is doing:

$foo ~~ green

That ought to work even if you set green by saying:

$foo.Color = (0,1,0);

So it seems more that green is doubling as a predicate and a value.
Indeed, you could think of setting something to green as setting it to
pure green (0,1,0), but testing green as anything that looks
greenish - $r,$g,$b { $g  $r + $b }.

Maybe it's a subtype[1] of the property with a default value?

That gets me thinking about how to declare that.  If a subtype is like a
parameter to the class that the class didn't really declare, I could
imagine a syntax like this:

constraint Color[green] { $.g  $.r + $.b }

That makes me woosy, though.  Maybe digging up the adverbial modifier
Cwhere should stir some ideas.

constraint green is Color { $.g  $.r + $.b }

my Color where green $spinach;

Maybe we'd better leave that one buried.

For some reason, subtypes don't feel like roles to me.  They're not so
much behaviors are they are constraints... on behavior.  Like the
opposite of roles, actually. 

Oh, we were talking about enums, right?  Um.  Yeah. 

Luke

[1] There's a term to add to the vocab sheet.  AFAIK, a subtype is a
variation on a normal type that has some constraint applied to it.
Think vague.


Re: This week's summary

2003-12-16 Thread Luke Palmer
Piers Cawley writes:
 The Perl 6 Summarizer [EMAIL PROTECTED] writes:
Vocabulary
  If you're even vaguely interested in the workings of Perl 6's object
  system, you need to read the referenced post.
 
  Luke Palmer, worrying about people using Object related vocabulary in
  subtly inconsistent ways, posted a glossary explaining how OO
  terminology is used in a Perl 6 context. Casey West wrapped it up in a
  POD, which will, I hope, end up on dev.perl.org soon.
 
  Of course, there were a few corrections for subtleties, a few rethinks
  of the design so far, and general gratitude for at least having a
  baseline document that people could refer to.
 
  http://groups.google.com/[EMAIL PROTECTED]
 
 This should, of course, read:
 
 http://groups.google.com/[EMAIL PROTECTED]

Or even:

http://groups.google.com/[EMAIL PROTECTED]

:-p

Luke



Re: Vocabulary

2003-12-16 Thread Luke Palmer
Michael Lazzaro writes:
 
 On Sunday, December 14, 2003, at 06:14 PM, Larry Wall wrote:
 But the agreement could be implied by silence.  If, by the time the
 entire program is parsed, nobody has said they want to extend an
 interface, then the interface can be considered closed.  In other
 words, if you think you *might* want to extend an interface at run
 time, you'd better say so at compile time somehow.  I think that's
 about as far as we can push it in the final direction.
 
 That seems a very fair rule, especially if it adds a smidge more speed. 
  Runtime extension will likely be very unusual 

Unless you're me.  Or Damian.  Or a fair number of other programmers who
like to dive into the Perl Dark Side on a regular basis.

 -- requiring it to be explicit seems reasonable.

It seems so.  Knowing Larry, I'm sure this is an ungrounded fear, but I
definitely want to be able to declare in a module I'm going to be
screwing with stuff; keep out of my way, so that I don't impose any
awkward declarations on my module users.  If that request can be made
more explicit in the cases where that's possible, great, but the general
declaration should be available.

Luke

 
 I'm probably spouting nonsense.  I just hope it's good-sounding 
 nonsense...
 
 It's beyond good-sounding, it's frickin' awesome.
 
 MikeL
 


Re: Vocabulary

2003-12-16 Thread Luke Palmer
Chip Salzenberg writes:
 According to Jonathan Scott Duff:
  Those classes that are closed can be opened at run-time and the
  user pays the penalty then when they try to modify the class [...]
 
 The optimization that can be reversed is not the true optimization.

While poetic and concise, I think that statement needs to be driven into
the ground a bit more.

Over on p6i, I think we're basically in agreement that the ability to
undo optimizations is nothing we can count on.  Unless there is a
breakthrough in computer science any time soon, this while loop:

sub one() { 1 };
sub go() {
my $x = 0;
while $x++  one {  # loop optimized away
%main::{'one'} = sub { 10 };
print Boing!\n;
}
}

Is not something that can can be re-inserted when we find out one() has
changed.  While it's possible to make it so go() is unoptimized on the
next call, that's not good enough.  We expect changes to act instantly.

But if you separate parsing and code-generation time, you can make
optimizations earlier based on declarations later, which is just fine.
It allows you to say:

use PresumptuousModule  SomeClass ;
class SomeClass is extensible { };

Then even if the writer of PresumptuousModule thinks you'll be better
off with the optimization, you can tell him otherwise.  But you have to
do it before the code is generated.

Luke


Re: Vocabulary

2003-12-16 Thread Luke Palmer
Larry Wall writes:
 On Tue, Dec 16, 2003 at 07:05:19AM -0700, Luke Palmer wrote:
 : Michael Lazzaro writes:
 :  
 :  On Sunday, December 14, 2003, at 06:14 PM, Larry Wall wrote:
 :  But the agreement could be implied by silence.  If, by the time the
 :  entire program is parsed, nobody has said they want to extend an
 :  interface, then the interface can be considered closed.  In other
 :  words, if you think you *might* want to extend an interface at run
 :  time, you'd better say so at compile time somehow.  I think that's
 :  about as far as we can push it in the final direction.
 :  
 :  That seems a very fair rule, especially if it adds a smidge more speed. 
 :   Runtime extension will likely be very unusual 
 : 
 : Unless you're me.  Or Damian.  Or a fair number of other programmers who
 : like to dive into the Perl Dark Side on a regular basis.
 : 
 :  -- requiring it to be explicit seems reasonable.
 : 
 : It seems so.  Knowing Larry, I'm sure this is an ungrounded fear, but I
 : definitely want to be able to declare in a module I'm going to be
 : screwing with stuff; keep out of my way, so that I don't impose any
 : awkward declarations on my module users.  If that request can be made
 : more explicit in the cases where that's possible, great, but the general
 : declaration should be available.
 
 Okay, we'll call the general declaration:
 
 use $
 
 or some such.  :-)
 
 Seriously, I hope we can provide a framework in which you can screw
 around to your heart's content while modules are being compiled,
 and to a lesser extent after compilation.  But we'll never get to a
 programming-in-the-large model if we can't limit most of the screwing
 around to the lexical scope currently being compiled, or at least
 to a known subset of the code.  Modules that turn off optimization
 for all other modules are going to be about as popular as $.  So
 the general declaration should probably be something easy to see like:
 
 use STRANGE_SEMANTICS_THAT_SLOW_EVERYONE_DOWN;

Hmm, I guess that's true.  A module author shouldn't have the the
freedom to say that his classes are completely untouchable, because he
doesn't know what you're going to be doing with them.  But
correspondingly, I guess, a module author shouldn't have the freedom to
slow everybody down because he was lazy about figuring out what needed
to be declared open.

But Perl hinges on laziness, doesn't it?  Eh, I trust that Perl 6 will
make it easy to figure that out in most cases.  I was coming from the
perspective that 90% of my projects don't need speed; but I can say no
such thing on account of my users.  And what about that un-accounted-for
10%?

Perhaps the real detterent to using such a thing would be making it
generate a warning when -w is on.   You get the peer pressure thing;
people frown upon you when you use the pragma unwisely.

So, yeah, I agree with you now.

Luke



Re: Vocabulary

2003-12-16 Thread Luke Palmer
Michael Lazzaro writes:
 I agree, it is frequently the case that the question of speed is made 
 critical by people who most assuredly do not need it.  But they still 
 decide that way, and I have found that asserting to them that speed is 
 not important has been... well, less than effective.  I do not doubt 
 that P6 will be much more competitive, speed-wise, than P5 -- but if it 
 could actually _win_ a few benchmarks, it would turn my company's use 
 of Perl from a PR problem to a PR advantage.

In the presence of parrot's JIT, competing should be no problem.  I'm
not entirely sure Perl 6 will be faster than Perl 5 on the average.  But
the difference is that Perl 6 will allow you to make fast code where you
need it.  For instance (and the main one, probably), using native
(lowercase) types allows you to JIT, and using JIT is just...  well, you
have to see it for yourself.  Amazing.  But since, as I've said, I don't
do speed-critical work, I won't be usually using lowercase types.  And
that trades me flexibility for speed.

And from what I've seen of Java, if you need speed, hand-optimizing your
inner loop to parrot assembly should blow Java out of the water.
Without needing a C compiler (I despise XS).

Luke

 your usage patterns may be irrelevant to Perl in the big picture.
 
 The thought has crossed my mind repeatedly, believe me.
 
 MikeL
 


Re: but true

2003-12-19 Thread Luke Palmer
Abhijit A. Mahabal writes:
 On Fri, 19 Dec 2003, Larry Wall wrote:
 
  On Fri, Dec 19, 2003 at 10:23:45AM -0800, Austin Hastings wrote:
  : Of course, when I do:
  :
  :   my $x = 0 but (true|false);
  :
  : then what happens?
 
  That's the problem with making them methods.  Any such operational
  definition is going to get you in trouble.  I think I like them better
  as enums, because then you can have junctions of them functioning as
  a kind of subtype.
 
 Is that thought about just traits, or also about roles? 

Neither.  It's just about roles.  We're having another vocabulary
conflict; refer to the vocabulary doc.

 Sometime earlier Larry mentioned that roles could add multimethods,
 and my worry about that is this:
   If you simultaneously have a multi method with a signature and
 another without, given a particular call to this multimethod how do you
 choose which of the two happens if the signature matches? 

Probably the same way you disambiguate when normal multimethods abound.
The more specific signature wins, if it matches.

Though I do see how this might introduce subtle bugs.  I'm a big fan of
method name-only equivalence, so I would argue that it overrides (or
subsides if it isn't being slathered on), but then I don't have
experience with large-scale projects.

 Disallowing such clashes seems problematic because it may mean that if
 the class writer used types and signatures these get forced onto the
 user of the class.

Everybody's going to be using signatures, though!  (Types are a
different story)  Yeah, the typeless one would win, I think, unless the
type happens to be Any.

Luke


Re: Object Order of Precedence (Was: Vocabulary)

2003-12-19 Thread Luke Palmer
Larry Wall writes:
 But if you say something like:
 
 class DangerousPet does Pet does Predator {
   multi method feed ($x) {...}
 }
 
 then DangerousPet::feed is called only when multimethod dispatch
 would have thrown an exception.  Alternately, multi's will probably have
 some way of identifying the default method in any case, so maybe you
 have to write it something like this: 
 
 class DangerousPet does Pet does Predator {
   multi method feed ($x) is default {...}
 }
 
 that leaves the door open for real multi's within the class working
 in parallel to the roles' methods:
 
 class DangerousPet does Pet does Predator {
   multi method feed ($x) is default {...}
   multi method feed (DangerousPetFood $x) {...}
 }
 
 Arguably, the role's might be required to declare their methods multi
 if they want to participate in this, but that's one of those things
 that feel like they ought to be declared by the user rather than the
 definer.  On the other hand, maybe a role would feel that its method
 *must* be unique, and leaving out the multi is the way to do that.
 But I hate to get into the trap of culturally requiring every method
 in every role to specify multi.  It's a little too much like the C++
 ubiquitous-const problem.

I'd like that roles don't have control over whether their methods are
unique, but the class does.  That is, multi dispatch would be one of the
several disambiguation possibilities for role conflicts.  But without
specification, name conflicts always result in error.

 [...]
 
 My hope for unifying traits and superclasses is that, if you call an
 ordinary class using is, the wicked thing that it does is insert
 itself into the ISA property of the class.  Where that may cause
 problems if you want to inherit from an existing trait that does
 something else wicked.  But then, traits aren't often going to be
 inherited anyway, since their purpose is to break the rules.  We can
 maybe inherit from classof(trait) to get around any difficulties.
 So I'm still thinking we do inheritance with is rather than isa.
 We just have to keep our names straight.  Generally, traits will
 be lowercase, and true class or role names start with an uppercase
 letter.

I like that.  That allows for nice things like letting a class keep
track of its subclasses, or in general doing other tricky things to its
subclasses.

Inheritance is a logical association, not a functional one, so when
your classes are doing nonstandard things, you'd like to modify what
inheritance does.  Definitely good.

Luke


Re: [perl] Re: Object Order of Precedence (Was: Vocabulary)

2003-12-20 Thread Luke Palmer
Joe Gottman writes:
 
 - Original Message - 
 From: Jonathan Lang [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Sent: Saturday, December 20, 2003 3:41 PM
 Subject: [perl] Re: Object Order of Precedence (Was: Vocabulary)
 
 
  Larry Wall wrote:
   If DangerousPet doesn't define a feed method at all, then we might
   dispatch to Pet and Predator as if their methods had an implicit
   multi.
 
  And the Cdefault trait is the tie-breaker when several options are
  equally likely candidates (in terms of type information); OK.
 
I'm a little leery about calling this trait default. The problem is
 that we are already using default as a keyword (see the switch statement),
 and having a trait with the same name as a keyword might confuse users
 and/or the compiler.

Perl's using a top-down compiler now, so it won't be looking for the
keyword variant of Cdefault after is.  default is sufficiently
overloaded in English, and by context in Perl, that I don't think anyone
will get confused.

Not to say that other names for this trait aren't welcome.

Luke


Re: Nature of traits

2003-12-21 Thread Luke Palmer
Jonathan Lang writes:
 I've just been rereading the recent discussions, and I noticed something
 that I missed the first time: 
 
 Larry Wall wrote:
  Traits are not definitional but rather operationally defined in the 
  worst way.  That's why traits are renegade roles.  They don't play by 
  the rules.
 
 In other words, a trait effectively has an installer routine which
 gets run whenever you apply it to a particular object (that is, is
 const calls const::INSTALL or something of the sort).  
 
 I've been trying to puzzle out what the distinction between roles and
 traits is so that I can understand why traits need to be handled
 differently than roles are - in particular, I was thinking in terms of
 why traits don't fit into the order of precedence for method calls
 (that is, class || role || superclass).  If I'm right about the
 installer, the answer would seem to be that the trait gets to choose
 (by means of the installer) where it fits into said chain, if at all -
 it could insert itself into the class's ISA list, tell the class to
 treat it as a role, or maybe even wrest control from the class,
 effectively treating the class definition as a role or superclass of
 its own and then masquerading as the class to outsiders (effectively
 putting itself ahead of the class in the order of precedence chain).
 Or it could do none of the above, thus requiring its namespace to be
 explicitly referenced if you want access to any of its methods or
 attributes.  
 
 The point is that - if I'm understanding the current thoughts on the
 subject - the difference between a trait and a role is that a trait's
 interaction with a class is programmable.  How am I faring?  

That seems to be it.  A trait, from the user's perspective, is something
declarative that happens other than inheritance or role composition.  If
you're wondering why roles aren't unified with traits, it looks like a
linguistic thing.  We only have so many naming conventions.

Traits are the catch-all of encapsulated behavior.  You put something
that happens behind a name, and it does what it needs to in order to
fulfill its duty.  For the things more specific, there are concepts more
specific.

I think traits are a brilliant idea though.  If you're going to hack,
it's nice to have a standard way to encapsulate the hack.

Luke


Re: When is enough too much?

2003-12-23 Thread Luke Palmer
Uri Guttman writes:
 good point. but we definitely would want arrays supported
 with all three scalar types and in both directions. in fact, if we just
 look at what swig (and other similar projects) is able to do we can make
 that stuff easier as well. i recall a minor nightmare when we tried to
 wrap this lib in a perl module. if the nci interface can handle
 describing arguments with their direction (in/out/in-out), sizes, types,
 etc. and do all the needed work it will make this so much easier.

Not just easier.  The fact that it's possible to interface with
libraries without a C compiler has some profound ramifications regarding
portability.  It means that normal Windows platforms (the ones without
make and a compiler) will be able to use a lot more of the modules that
are written.

I'm all for a very rich NCI.

Luke

 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: ParrotIO array

2003-12-24 Thread Luke Palmer
Leopold Toetsch writes:
 Pete Lomax wrote:
 
 My question is: What can I do to P4 entries to mark them as available
 for re-use?
 
 close:
 P0=P4[I1]
 close P0
 # mark slot as free
 null P5
 P4[I1]=P5# set to NULL
 ret
 
 you can test the entry by:
 
set P0, P4[I1]
isnull P0, is_close
#
 is_close:

When writing one of my pet languages, I found a need (or a want) to
replace the contents of a PMC with a different PMC.  To accomplish this,
I wrote an op that memcpied the header of the source into the header of
the destination.  It worked.  (Maybe a simple struct assignment would
work, too)

Is this a safe thing to do?  If so, I think it deserves core ophood.

Luke

 Regards,
 Pete
 
 leo
 


[PATCH] internal_exception newlines

2003-12-24 Thread Luke Palmer
Here's a big patch that adds newlines to all internal_exception calls
for which they were missing.

Luke


Index: classes/delegate.pmc
===
RCS file: /cvs/public/parrot/classes/delegate.pmc,v
retrieving revision 1.8
diff -u -r1.8 delegate.pmc
--- classes/delegate.pmc15 Dec 2003 17:17:58 -  1.8
+++ classes/delegate.pmc24 Dec 2003 19:35:17 -
@@ -37,7 +37,7 @@
 struct regsave *save;
 save = mem_sys_allocate(sizeof(struct regsave));
 if (!save) {
-   internal_exception(ALLOCATION_ERROR, No memory for save struct);
+   internal_exception(ALLOCATION_ERROR, No memory for save struct\n);
 }
 mem_sys_memcopy(save, interp, sizeof(struct regsave));
 return save;
@@ -62,7 +62,7 @@
 PMC *returnPMC = find_meth(interp, pmc, name);
 if (PMC_IS_NULL(returnPMC)) {
internal_exception(METH_NOT_FOUND,
-   Can't find method '%s' for object, name);
+   Can't find method '%s' for object\n, name);
 }
 return returnPMC;
 }
Index: classes/key.pmc
===
RCS file: /cvs/public/parrot/classes/key.pmc,v
retrieving revision 1.15
diff -u -r1.15 key.pmc
--- classes/key.pmc 19 Dec 2003 10:01:36 -  1.15
+++ classes/key.pmc 24 Dec 2003 19:35:17 -
@@ -121,7 +121,7 @@
ret-cache.int_val = -1;
break;
default:
-   internal_exception(1, Key can't iterate backwards);
+   internal_exception(1, Key can't iterate backwards\n);
break;
}
return ret;
Index: classes/parrotobject.pmc
===
RCS file: /cvs/public/parrot/classes/parrotobject.pmc,v
retrieving revision 1.14
diff -u -r1.14 parrotobject.pmc
--- classes/parrotobject.pmc5 Dec 2003 16:40:55 -   1.14
+++ classes/parrotobject.pmc24 Dec 2003 19:35:17 -
@@ -82,7 +82,7 @@
POD_CLASS);
INTVAL idx = VTABLE_get_integer_keyed_str(interpreter, class, attr);
if (idx  0)
-   internal_exception(1, No such attribute);
+   internal_exception(1, No such attribute\n);
return SELF.get_integer_keyed_int(idx);
 }
 
@@ -102,7 +102,7 @@
POD_CLASS);
INTVAL idx = VTABLE_get_integer_keyed_str(interpreter, class, attr);
if (idx  0)
-   internal_exception(1, No such attribute);
+   internal_exception(1, No such attribute\n);
SELF.set_integer_keyed_int(idx, value);
 }
 
Index: classes/scratchpad.pmc
===
RCS file: /cvs/public/parrot/classes/scratchpad.pmc,v
retrieving revision 1.15
diff -u -r1.15 scratchpad.pmc
--- classes/scratchpad.pmc  19 Dec 2003 10:01:36 -  1.15
+++ classes/scratchpad.pmc  24 Dec 2003 19:35:17 -
@@ -76,7 +76,7 @@
 name = key_string(INTERP, name_key);
 }
 else {
-internal_exception(-1, Invalid key);
+internal_exception(-1, Invalid key\n);
 }
 
 if (key2) {
@@ -84,7 +84,7 @@
 pad_index = key_integer(INTERP, key);
 }
 else {
-internal_exception(-1, Invalid key);
+internal_exception(-1, Invalid key\n);
 }
 ret = scratchpad_get_index(INTERP, SELF, pad_index,
name, position);
@@ -113,7 +113,7 @@
 name = key_string(INTERP, name_key);
 }
 else {
-internal_exception(-1, Invalid key);
+internal_exception(-1, Invalid key\n);
 }
 
 if (key2) {
@@ -121,7 +121,7 @@
 pad_index = key_integer(INTERP, key);
 }
 else {
-internal_exception(-1, Invalid key);
+internal_exception(-1, Invalid key\n);
 }
 scratchpad_store_index(INTERP, SELF, pad_index, name,
position, value);
Index: classes/unmanagedstruct.pmc
===
RCS file: /cvs/public/parrot/classes/unmanagedstruct.pmc,v
retrieving revision 1.22
diff -u -r1.22 unmanagedstruct.pmc
--- classes/unmanagedstruct.pmc 4 Nov 2003 18:35:05 -   1.22
+++ classes/unmanagedstruct.pmc 24 Dec 2003 19:35:18 -
@@ -26,7 +26,7 @@
 ix *= 3;
 n = (size_t)VTABLE_elements(interpreter, PMC_ptr2p(pmc));
 if ((size_t)ix = n)
-   internal_exception(1, Non existent elements in struct);
+   internal_exception(1, Non existent elements in struct\n);
 /* use structure init */
 *type = (int) VTABLE_get_integer_keyed_int(interpreter, PMC_ptr2p(pmc), ix);
 offs = (size_t) VTABLE_get_integer_keyed_int(interpreter, PMC_ptr2p(pmc), ix + 2);
@@ -49,7 +49,7 @@
 count = (size_t) 

[PATCH] supplant op

2003-12-24 Thread Luke Palmer
Here's that op that replaces the header of one PMC with another's, if
people are interested.

Luke


Index: ops/ops.num
===
RCS file: /cvs/public/parrot/ops/ops.num,v
retrieving revision 1.15
diff -u -r1.15 ops.num
--- ops/ops.num 10 Dec 2003 11:44:07 -  1.15
+++ ops/ops.num 24 Dec 2003 20:09:54 -
@@ -1341,4 +1341,4 @@
 ne_addr_sc_sc_ic1314
 ne_addr_p_p_ic  1315
 isnull_p_ic 1316
-
+supplant_p_p1317
Index: ops/set.ops
===
RCS file: /cvs/public/parrot/ops/set.ops,v
retrieving revision 1.9
diff -u -r1.9 set.ops
--- ops/set.ops 19 Dec 2003 10:01:40 -  1.9
+++ ops/set.ops 24 Dec 2003 20:09:54 -
@@ -80,6 +80,20 @@
 
 
 
+=item Bsupplant(in PMC, in PMC)
+
+Replace $1's header with $2's.  Essentially makes all references to $1 now
+point to $2.
+
+=cut
+
+inline op supplant(in PMC, in PMC) {
+*$1 = *$2;
+goto NEXT();
+}
+
+
+
 =item Bset(out INT, in INT)
 
 =item Bset(out INT, in NUM)
Index: t/op/hacks.t
===
RCS file: /cvs/public/parrot/t/op/hacks.t,v
retrieving revision 1.17
diff -u -r1.17 hacks.t
--- t/op/hacks.t23 Dec 2003 09:57:40 -  1.17
+++ t/op/hacks.t24 Dec 2003 20:09:55 -
@@ -1,6 +1,6 @@
 #! perl -w
 
-use Parrot::Test tests = 2;
+use Parrot::Test tests = 3;
 use Test::More;
 use Parrot::Config;
 use Config;
@@ -60,5 +60,27 @@
 ok
 OUT
 }
+
+output_is('CODE', OUT, supplant op);
+new P0, .PerlString
+set P0, Hello!\n
+set P1, P0
+
+print P0
+print P1
+
+new P2, .PerlString
+set P2, Usurped!\n
+supplant P0, P2
+
+print P0
+print P1
+end
+CODE
+Hello!
+Hello!
+Usurped!
+Usurped!
+OUT
 
 1; # HONK



Re: [PATCH] supplant op

2003-12-24 Thread Luke Palmer
Leopold Toetsch writes:
 Luke Palmer [EMAIL PROTECTED] wrote:
  Here's that op that replaces the header of one PMC with another's, if
  people are interested.
 
  +inline op supplant(in PMC, in PMC) {
  +*$1 = *$2;
 
 Brrr. I'm not willing to contemplate now on the nasty side effects
 that might have,

Yeah, I was wondering if there were any problems with double destruction
or anything.  Maybe it can be made to work if $2 is destroyed when the
operation is performed.  I think this could indeed be a useful op if we
can verify there are no side effects, or make it such that there
aren't...

 but what for are you using that?

For doing precisely the assign thing for PMCs that don't have assign in
their vtable.  That and allowing a level of hacking about in my language
otherwise unavailable.

This was awhile ago.  Perhaps there's another solution looming, for
instance that PerlArray trick you showed earlier.  I think a Ref would
work, but Ref delegates set_pmc to what it's referencing, so it's never
possible to change the referent!  Is it?

Luke

 leo


Re: [PATCH] supplant op

2003-12-25 Thread Luke Palmer
Leopold Toetsch writes:
 Luke Palmer [EMAIL PROTECTED] wrote:
  ...  I think a Ref would
  work, but Ref delegates set_pmc to what it's referencing, so it's never
  possible to change the referent!  Is it?
 
 Some time ago I proposed additional opcodes dealing with Ref PMCs. You
 mention it, yep - they need deref and setref or such. Would the
 latter solve your problem?

Yeah.  I think deref is all we need, though.  Assign on a ref would
change what the reference points to, and deref and then assign would
assign to the reference.

Luke

  Luke
 
 leo


Re: Very large runtime overhead for prototyped functions

2003-12-27 Thread Luke Palmer
Joe Wilson writes:
 Using a recursive version of the fibonacci function (with
 the integer 32 as an argument) to test function call overhead 
 I get these timings for various languages and configurations:
 
 perl 5.6.1fib.pl   10.93 seconds
 python 2.2.2  fib.py6.76 seconds
 parrotf.pasm2.74 seconds
 parrot -j f.pasm1.53 seconds
 parrotfib.imc (*)  22.07 seconds
 parrot -j fib.imc (*)  18.04 seconds
 
 Prototyped functions in Parrot have a huge runtime overhead
 as compared to normal subroutines. Is this to be expected?

The overhead you're seeing comes from many things.  First, using
prototyped (or unprototyped) functions from in imcc follows the parrot
calling conventions.  That is, it uses continuation-passing instead of
bsr, sets a few int registers on the run, and does a savetop/restoretop.
None of these things were in your pasm file.  The largest account of
this overhead likely comes from the savetop/restoretop.

Not to mention, the imcc version is much less clever as far as getting
speed out of things.

But nonetheless I feel it's worth putting some serious effort
into making sub calls very fast on parrot.  That might involve some
minor tweaking of the calling conventions.

Luke


 fib.imc is basically like parrot/examples/benchmarks/fib.imc
 except for 32 instead or 24 and s/var/pmc/g
 The changes were made because fib.imc in CVS did not compile.
 
 CVS parrot from yesterday running on Cygwin.
 Full source code and timings below.
 
 
 $ cat fib.pl
 #!/usr/bin/perl -w
 use strict;
 sub fib {
 my $n = shift;
 return 1 if ($n  2);
 return fib($n-1) + fib($n-2);
 }
 my $N = 32;
 print fib($N), \n;
 
 $ time perl fib.pl
 3524578
 
 real0m10.934s
 user0m10.936s
 sys 0m0.015s
 
 
 $ cat fib.py
 import sys
 
 def fib(n):
 if (n  2):
 return 1
 return fib(n-2) + fib(n-1)
 
 def main():
 N = 32;
 print fib(N)
 
 main()
 
 $ time python fib.py
 3524578
 
 real0m6.765s
 user0m6.749s
 sys 0m0.046s
 
 
 $ cat f.pasm
 _main:
 set I1, 32
 bsr _fibo
 print I0
 print \n
 end
 _fibo:
 ge I1, 2, FIB2 
 set I0, 1
 ret
 FIB2:
 save I1
 dec I1
 bsr _fibo
 dec I1
 save I0
 bsr _fibo
 restore I3
 add I0, I0, I3
 restore I1
 ret
 
 
 $ time ../../parrot f.pasm 
 3524578
 
 real0m2.743s
 user0m2.749s
 sys 0m0.015s
 
 
 $ time ../../parrot -j f.pasm 
 3524578
 
 real0m1.530s
 user0m1.546s
 sys 0m0.000s
 
 
 $ cat fib.imc 
 .pcc_sub _main prototyped
 .param pmc argv
 .sym int argc
 argc = argv
 .sym int N
 N = 32
 if argc = 1 goto noarg
 $S0 = argv[1]
 N = $S0
 noarg:
 .sym float start
 .sym pmc fib
 fib = newsub _fib
 time start
 .pcc_begin prototyped
 .arg N
 .pcc_call fib
 .sym int r
 .result r
 .pcc_end
 .sym float fin
 time fin
 print fib(
 print N
 print ) = 
 print r
 print  
 sub fin, start
 print fin
 print s\n
 end
 .end
 
 .pcc_sub _fib prototyped
 .param int n
 if n = 2 goto rec
 n = 1
 .pcc_begin_return
 .return n
 .pcc_end_return
 rec:
 .sym int n1
 .sym int n2
 .sym int r1
 .sym int r2
 .sym pmc fib
 fib = P0
 n1 = n - 1
 n2 = n - 2
 .pcc_begin prototyped
 .arg n1
 .pcc_call fib
 .result r1
 .pcc_end
 .pcc_begin prototyped
 .arg n2
 .pcc_call fib
 .result r2
 .pcc_end
 n = r1 + r2
 .pcc_begin_return
 .return n
 .pcc_end_return
 .end
 
 
 $ time ../../parrot fib.imc
 fib(32) = 3524578 22.044000s
 
 real0m22.078s
 user0m22.077s
 sys 0m0.030s
 
 
 $ time ../../parrot -j fib.imc
 fib(32) = 3524578 18.017000s
 
 real0m18.048s
 user0m17.796s
 sys 0m0.030s
 
 
 __
 Do you Yahoo!?
 New Yahoo! Photos - easier uploading and sharing.
 http://photos.yahoo.com/


Re: Slow vararg subroutines in Parrot, jit bug found as well.

2003-12-27 Thread Luke Palmer
Joe Wilson writes:
 Dan Sugalski:
  2) Parrot's Array and SArray values all accept mixed-type data, which 
  perl's arrays do *not* do, and as such have some extra speed hits 
  that perl arrays don't.
 
 What do you mean?
 Perl's arrays do indeed accept mixed data types (see example below).

No, they don't.  They are arrays of PerlScalars only.

For this:

set P1, P0[35]

The current Array and SArray have to sift through the sparse table to
find the 35th index (that's pretty efficient, but it still needs to
check whether it needs to do that).  It then checks whether the 35th
element is indeed a PMC (it could be an int, num, or str), and then sets
P1 to that element.  

Perl's array doesn't have sparse handling (the timing of 
perl -le '$x[1000] = 1' should convince you of this), and it doesn't
need to check whether the 35th element is a scalar, because the only
thing it holds are scalars.

Luke

 $ cat addit2.pl
 #!/usr/bin/perl
 #
 # addit2.pl
 #
 use strict;
 sub varargs_adder {
 my $sum = 0;
 for (my $a = $#_; $a = 0; --$a) {
 $sum += $_[$a];
 }
 return $sum
 }
 my $result = 0;
 my @args;
 $args[0] = 1000;
 $args[1] = 7.100;
 $args[2] = 87;
 $args[3] = 3.87;
 $args[4] = 2100;
 for (my $x = 50; $x = 0; --$x) {
 $result = varargs_adder(@args);
 }
 print $result\n;
 
 $ time perl addit2.pl
 21001097.97
 
 real0m2.825s
 user0m2.843s
 sys 0m0.015s
 
 $ cat f6.pasm 
 #
 # f6.pasm
 #
 # array element arguments are created before the loop
 #
 _main:
 new P5, .SArray
 set P5, 5
 push P5, 1000
 push P5, 7.100
 push P5, 87
 push P5, 3.87
 push P5, 2100
 set I9, 50
 AGAIN:
 dec I9
 lt I9, 0, FIN
 bsr _varargs_adder
 branch AGAIN
 FIN:
 print N0
 print \n
 end
 _varargs_adder:
 new P2, .PerlNum
 assign P2, 0
 set I1, P5
 LOOP:
 dec I1
 lt I1, 0, DONE
 set P1, P5[I1]
 add P2, P2, P1
 branch LOOP
 DONE:
 set N0, P2
 ret
 
 
 $ time parrot f6.pasm
 21001097.97
 
 real0m3.925s
 user0m3.936s
 sys 0m0.015s
 
 
 $ time parrot -j f6.pasm
 21001094.10 (note: wrong result and slower with jit)
 
 real0m11.999s
 user0m12.015s
 sys 0m0.000s
 
 
 
 __
 Do you Yahoo!?
 New Yahoo! Photos - easier uploading and sharing.
 http://photos.yahoo.com/


IMCC bug: newclass optimized away

2003-12-31 Thread Luke Palmer
Both newclass and addattrib are optimized away by the 'used_once'
optimization under -O2.  This is obviously incorrect, since they have
side-effects.

Luke


Object system

2003-12-31 Thread Luke Palmer
Since I'm working on a compiler that requires objects, and seeing as how
we have a python compiler now hanging over our heads, what work is
necessary to finish up the object system?

I notice that ParrotObject only has [get|set]_integer_keyed.  I assume
we intend to make those for the rest of the data types.

Also, in order to support anonymous classes, I'd like the method table
to be in the class object itself, as opposed to in mangled globals.  Is
this also something I could tackle?

What else could I do?

Thanks,
Luke


Re: Threads Design. A Win32 perspective.

2004-01-03 Thread Luke Palmer
Nigel Sandever writes:
 Maybe it would be possible (for me + others) to write the core of a win32 specific,
 threaded VM interpreter that would take parrot byte code and run it. Thereby,
 utilising all the good stuff that preceeds the VM interpreter, plus probably large 
 chunks of the parrot VM, but provides it with a more native compatible target. 

You want to write a parrot?  Um, good luck.

One thing Uri mentioned was writing platform specific macro code, and he
dismissed it with that it's also a pain.  While I agree that it's a
pain, and it's about as maintainence-friendly as JIT, I don't think it
has to be ruled out.

Parrot is platform-independent, but that doesn't mean we can't take
advantage of platform-specific instructions to make it faster on certain
machines.  Indeed, this is precisely what JIT is.  

But a lock on every PMC is still pretty heavy for those non-x86
platforms out there, and we should avoid it if we can.

Luke

 
 That's something that obviously not a simple project and is beyond the scope of 
 this list. 
 
 Thanks for taking the time to review this.
 
 Nigel Sandever.
 
 


newclass bug, or something

2004-01-05 Thread Luke Palmer
The following program segfaults after 510 iterations:

.sub _main
$I0 = 0
again:
$S1 = anon
$S0 = $I0
inc $I0
concat $S1, $S0
newclass $P0, $S1
find_type $I2, $S1
print $I2
print \n
if $I0  1000 goto again
end
.end

It runs fine if I Csweepoff at the beginning, and indeed, it dies
during DOD, since bucket points to an invalid memory location.  I
haven't the slightest clue what's wrong beyond that.

Here's the gdb backtrace:

#0  0x080809d2 in mark_hash (interpreter=0x826f9b0, hash=0x8dfb38) at src/hash.c:297
297 (hash-mark_key)(interpreter, (PObj *)bucket-key);
(gdb) bt
#0  0x080809d2 in mark_hash (interpreter=0x826f9b0, hash=0x8dfb38) at src/hash.c:297
#1  0x081cfabb in Parrot_PerlHash_mark (interpreter=0x826f9b0, pmc=0x8dfb50) at 
perlhash.c:62
#2  0x081fefcf in Parrot_OrderedHash_mark (interpreter=0x826f9b0, pmc=0x8dfb50) at 
orderedhash.c:57
#3  0x080b764c in trace_children (interpreter=0x826f9b0, current=0x8dfb50) at 
src/dod.c:251
#4  0x080b74ea in trace_active_PMCs (interpreter=0x826f9b0, trace_stack=1) at 
src/dod.c:201
#5  0x080b7cad in Parrot_do_dod_run (interpreter=0x826f9b0, trace_stack=1) at 
src/dod.c:744
#6  0x081f0ba7 in more_traceable_objects (interpreter=0x826f9b0, pool=0x8277170) at 
src/smallobject.c:71
#7  0x081f0cbc in get_free_object (interpreter=0x826f9b0, pool=0x8277170) at 
src/smallobject.c:134
#8  0x080b66a7 in get_free_buffer (interpreter=0x826f9b0, pool=0x8277170) at 
src/headers.c:55
#9  0x080b6be6 in new_bufferlike_header (interpreter=0x826f9b0, size=60) at 
src/headers.c:250
#10 0x08080f46 in new_hash_x (interpreter=0x826f9b0, hptr=0x8dfb50, 
val_type=enum_type_PMC, val_size=0,
hkey_type=Hash_key_type_ascii, compare=0x8080565 STRING_compare, 
keyhash=0x8080518 key_hash_STRING,
mark=0x80b71d8 pobject_lives) at src/hash.c:516
#11 0x08080f05 in new_hash (interpreter=0x826f9b0, hptr=0x8dfb50) at src/hash.c:477
#12 0x081cfa92 in Parrot_PerlHash_init (interpreter=0x826f9b0, pmc=0x8dfb50) at 
perlhash.c:55
#13 0x081fefa5 in Parrot_OrderedHash_init (interpreter=0x826f9b0, pmc=0x8dfb50) at 
orderedhash.c:50
#14 0x0807ed8a in pmc_new (interpreter=0x826f9b0, base_type=23) at src/pmc.c:51
#15 0x081ecfd0 in Parrot_new_class (interpreter=0x826f9b0, class=0x8dfbb0, 
class_name=0x9a7e70) at src/objects.c:131
#16 0x080cefda in Parrot_newclass_p_s (cur_opcode=0x8291608, interpreter=0x826f9b0) at 
object.ops:123
#17 0x0807e1c5 in runops_slow_core (interpreter=0x826f9b0, pc=0x8291608) at 
src/runops_cores.c:115
#18 0x080753b3 in runops_int (interpreter=0x826f9b0, offset=0) at src/interpreter.c:628
#19 0x08075455 in runops_ex (interpreter=0x826f9b0, offset=0) at src/interpreter.c:650
#20 0x08075606 in runops (interpreter=0x826f9b0, offset=0) at src/interpreter.c:701
#21 0x080b0ad5 in Parrot_runcode (interpreter=0x826f9b0, argc=1, argv=0xb8dcf16c) at 
src/embed.c:513
#22 0x08074611 in main (argc=1, argv=0xb8dcf16c) at imcc/main.c:548
#23 0x00232ba7 in __libc_start_main () from /lib/libc.so.6

gcc version 3.2.3 20030422 (Gentoo Linux 1.4 3.2.3-r1, propolice)

Luke


[PATCH] The Return of the Priority DOD

2004-01-05 Thread Luke Palmer
After many months of lying dormant, I figured I'd get my act together
and adapt this patch to the few recent modifications.  And this time,
I'm posting a benchmark!

My results get about 5% slowdown in the eager case, and the usual
10,000% speedup in the lazy case.

Luke

First, the benchmark (examples/benchmarks/dod_priority.imc):

#! /usr/bin/env parrot
# Call this program with an argument of 0 (or no arguments at all)
# to see the priority dod behavior.  Call with an argument of 1 to
# see the full sweep.

.pcc_sub _main non_prototyped
.param pmc argv

.const int ntimes = 1
.const int nestlevel = 1000

.sym int sweep_arg
$I0 = argv
if $I0 = 1 goto set_zero
$P0 = argv[1]
sweep_arg = $P0
goto continue
set_zero:
sweep_arg = 0
continue:

$I0 = nestlevel
$P0 = new PerlString
$P0 = Foo!
needs_destroy $P0
makenest:
unless $I0 goto last
dec $I0
$P1 = new PerlArray
$P1[0] = $P0
$P0 = $P1
goto makenest
last:

# That concludes making the data structure, now let's run
# DOD a bunch of times (we're still in the root set in $P0)
$I0 = ntimes
again:
unless $I0 goto last2
dec $I0
if sweep_arg goto sweep_one
sweep 0
goto again
sweep_one:
sweep 1
goto again
last2:
end
.end

---
And the patch:

? vtable.dump
? examples/benchmarks/dod_priority.imc
Index: classes/timer.pmc
===
RCS file: /cvs/public/parrot/classes/timer.pmc,v
retrieving revision 1.7
diff -u -r1.7 timer.pmc
--- classes/timer.pmc   25 Aug 2003 09:46:23 -  1.7
+++ classes/timer.pmc   5 Jan 2004 13:30:45 -
@@ -253,7 +253,7 @@
t-self = SELF;
SELF-cache.struct_val = t;
 PObj_active_destroy_SET(SELF);
-   interpreter-has_early_DOD_PMCs = 1;
+   ++interpreter-num_early_DOD_PMCs;
 }
 
 void init_pmc(PMC *init) {
Index: include/parrot/dod.h
===
RCS file: /cvs/public/parrot/include/parrot/dod.h,v
retrieving revision 1.11
diff -u -r1.11 dod.h
--- include/parrot/dod.h28 Jul 2003 13:38:00 -  1.11
+++ include/parrot/dod.h5 Jan 2004 13:30:46 -
@@ -40,7 +40,12 @@
 #define Parrot_is_blocked_GC(interpreter) \
 ((interpreter)-GC_block_level)
 
-void Parrot_do_dod_run(struct Parrot_Interp *, int trace_stack);
+enum {
+DOD_trace_stack_FLAG = 1  0,
+DOD_lazy_FLAG= 1  1
+};
+
+void Parrot_do_dod_run(struct Parrot_Interp *, UINTVAL flags);
 void trace_system_areas(struct Parrot_Interp *);
 void trace_mem_block(struct Parrot_Interp *, size_t, size_t);
 
Index: include/parrot/interpreter.h
===
RCS file: /cvs/public/parrot/include/parrot/interpreter.h,v
retrieving revision 1.114
diff -u -r1.114 interpreter.h
--- include/parrot/interpreter.h2 Jan 2004 14:09:32 -   1.114
+++ include/parrot/interpreter.h5 Jan 2004 13:30:46 -
@@ -247,7 +247,6 @@
 
 /* per interpreter global vars */
 INTVAL world_inited;/* Parrot_init is done */
-PMC *mark_ptr; /* last PMC marked used in DOD runs */
 PMC *iglobals;  /* SArray of PMCs, containing: */
 /* 0:   PMC *Parrot_base_classname_hash; hash containing name-base_type */
 /* 1:   PMC *Parrot_compreg_hash;hash containing assembler/compilers */
@@ -255,7 +254,12 @@
 /* 3:   PMC *Env;hash_like Env PMC */
 /* 4:   PMC *ParrotInterpreter   that's me */
 /* 5:   PMC *Dyn_libs   Array of dynamically loaded ParrotLibrary  */
-int has_early_DOD_PMCs;   /* Flag that some want immediate destruction */
+UINTVAL num_early_DOD_PMCs; /* how many PMCs want immediate destruction */
+UINTVAL num_early_PMCs_seen;/* how many such PMCs has DOD seen */
+PMC* dod_mark_ptr;  /* last PMC marked during a DOD run */
+PMC* dod_trace_ptr; /* last PMC trace_children was called on */
+int lazy_dod;   /* flag that indicates whether we should stop
+   when we've seen all impatient PMCs */
 PMC* DOD_registry;  /* registered PMCs added to the root set */
 struct MMD_table *binop_mmd_funcs; /* Table of MMD function pointers */
 PMC** nci_method_table;   /* Method table PMC for NCI stubs per class */
Index: include/parrot/pobj.h
===
RCS file: /cvs/public/parrot/include/parrot/pobj.h,v
retrieving revision 1.31
diff -u -r1.31 pobj.h
--- include/parrot/pobj.h   24 Dec 2003 10:43:08 -  1.31
+++ include/parrot/pobj.h   5 Jan 2004 13:30:46 -
@@ -224,12 +224,14 @@
  */
 b_PObj_is_special_PMC_FLAG = 1  26,
 
-b_PObj_needs_early_DOD_FLAG = 1  27,
+/* true if this is connected by some route to a 

Re: [PATCH] The Return of the Priority DOD

2004-01-05 Thread Luke Palmer
Jeff Clites writes:
 On Jan 5, 2004, at 5:47 AM, Luke Palmer wrote:
 
 After many months of lying dormant, I figured I'd get my act together
 and adapt this patch to the few recent modifications.  And this time,
 I'm posting a benchmark!
 
 My results get about 5% slowdown in the eager case, and the usual
 10,000% speedup in the lazy case.
 
 Sounds cool; do you have a quick high-level description of what it's 
 all about? (I had seen that needs_early_DOD flag in the source, and 
 didn't know what it was intended to do.)
 
 Thanks!

Okay, here I go, just before I get some sleep and then wake up to tie up
the rather insidious bugs in the patch. 

We have a problem with several common constructs that Perl will likely
require of us.  For instance, this one:

{
my $fh = open ' foo';
print $fh: Hello!\n;
}
{
my $fh = open ' foo';
print $fh;
}

In Perl 5, this prints Hello! without the blink of an eye (well, if it
were valid Perl 5 syntax ;-).  But now on Parrot with a opportunistic
DOD, this guarantee doesn't hold.  If $fh isn't closed before it's
opened, the results here are undefined. 

Performing a full sweep at every scope exit is not practical: there's
enough sub-call overhead as it is.  So a new variant of Csweep was
added: Csweep 0 would only sweep if there were no PMCs that had been
marked as neededing early (or impatient for) DOD.  

I and several others quickly saw this as a makeshift solution.  There
will commonly be at least one such object that will last the entire
lifetime of a program.  So Csweep 0, in practice, was exactly
equivalent to Csweep 1.

Enter the scheme that this patch implements.  It was batted around and
refined several times before I implemented it a few months ago.  Here's
how it goes:

The common case is that none of the impatient objects go out of program
view, and moreover that the various paths to find them remain the same.
The algorithm takes heavy advantage of this, keeping state across
multiple DOD runs.

Each PMC has associated with it a high priority flag.  First, only the
impatient objects have this flag set.  But on each DOD run, it's
possible to efficiently tell all objects that hold a reference to this
high priority object.  Those objects also get their high priority flag
set.  And so on down the chain.

Then during the DOD main loop, if such a high priority object comes
along, it is prepended to the queue, temporarily switching the DOD to
depth first.  This allows it to quickly navigate its way to the
impatient objects, and once they are all found, the lazy DOD is
terminated.  And the more the lazy DOD is run, the faster it becomes.

When one of the impatient objects can't be found, the run is equivalent
to a Csweep 1, but that happens rarely.  Also in this case, all high
priority flags are cleared, so that a wide-spreading circular data
structure doesn't end up making Ieverything high priority, thereby
nullifying the algorithm.  This is one of those things I forgot to
implement ;-)

Hope this clarified things.

Luke

 JEff
 


Re: Roles and Mix-ins?

2004-01-06 Thread Luke Palmer
David Storrs writes:
 
 On Sat, Dec 13, 2003 at 11:12:31AM -0800, Larry Wall wrote:
  On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote:
 
  : For one, one role's methods don't silently override another's.  Instead,
  : you get, er, role conflict and you have to disambiguate yourself.  
 
 How do you disambiguate?

Let's see...

role Dog {
method bark() { print Ruff! }
}
role Tree {
method bark() { print Rough! }
}
class Trog 
  does Dog does Tree {
method bark() { .Dog::bark() }
  }
}

Perhaps something like that.  In any case, you do it by putting the
offending method directly in the aggregating class.

 After reading this several times, I _think_ I understand.  Let me
 check: imagine that the original class is a text buffer going from
 0-99.  We have two roles (A and B), each of length 100.  Objects of
 various types can then see different segments of the buffer (i.e.,
 different methods/properties/whatever), as follows:
 
   TypeCan see 
   ---
   Class   1-100   
   A   101-199
   B   200-299
   Class+A 1-100,101-199
   Class+B 1-100,200-299
   Class+A+B   1-100,101-199,200-299
 
 Is that right?

Umm... I'm not sure that's what I'd use roles for.  And I'm not sure how
roles with associated data are supposed to work yet.  But I think you
have the general idea.

Luke


Minor IMCC bug with -v

2004-01-06 Thread Luke Palmer
Looks like when I run parrot -v, the statistics report on each sub, but
it calls all the subs the same thing, in particular, the last sub
compiled.

Luke


Continuations don't close over register stacks

2004-01-06 Thread Luke Palmer
Aren't continuations supposed to close over the register stacks?  In
this code:

.sub _main
I17 = 42
savetop
newsub P0, .Continuation, second
restoretop
invoke P0
second:
restoretop
print I17
print \n
end
.end

I should hope to get 42, but instead I get no more I frames to pop.
They're not very good continuations if you have to treat them just like
an address stack!

Note that if they do, the code generated by the PCC constructs will have
to change to:

savetop
newsub P1, .RetContinuation, @retlabel
invoke
restoretop

Rather than saving right before the invoke.  This makes a lot more sense
to me, anyway.

Luke


Re: References to hash elements?

2004-01-06 Thread Luke Palmer
Simon Cozens writes:
  $a = $hash{bar};
 
 Here you used the copy constructor before taking the reference. It might look
 like an assignment operator, but it isn't. You're better off thinking that
 assignment doesn't exist. It's a copy constructor. It makes the PMC referred
 to by $a a copy of the PMC in $hash{bar}. Their values may be equal but
 they're two different PMCs.

  $b = \$hash{bar};
 
 Here you didn't make a copy before taking the reference. No copy, only one
 PMC. It all works.

Indeed, and this separate PMC is probably the best way to think about
it, since we have in Perl 6:

$a := %hash{bar};

The operator C:= is just like a PMC Cset as opposed to an Cassign.
If, after this statement, one says:

$a = baz;

One should expect that C%hash{bar} would turn into baz;

Luke



Re: References to hash elements?

2004-01-06 Thread Luke Palmer
Arthur Bergman writes:
 
 On 6 Jan 2004, at 17:05, Simon Cozens wrote:
 
 
 I would have thought that a hash element would itself be a PMC rather
 than an immediate value, so a reference to that should be treated just
 like any other reference to a PMC.
 

 But this does not hold true if the hash element is in fact conjured up 
 by a call to STORE

Ahh, touch.  Well, it wouldn't be so hard to write a Proxy pmc which is
constructed with an aggregate and a key, and delegates its assignments
and fetches to the aggregate itself. 

Luke




Re: Continuations don't close over register stacks

2004-01-06 Thread Luke Palmer
Jeff Clites writes:
 On Jan 6, 2004, at 3:41 PM, Luke Palmer wrote:
 
 Leopold Toetsch writes:
 
 Good. Pass it over to me :) COW copy of stacks and of other 
 buffer-based
 items is still broken. These need distinct headers so that they work
 like COWed strings.
 
 Alright, I've got a pretty big incomplete patch here (see, when one has
 a deadline on a compiler written with the assumption of working
 continuations, one can be pretty determined :-).
 
 It makes each chunk into a subclass of Buffer like so:
 
 struct RegisterChunkBuf {
 size_t used;
 PObj* next;
 };
 
 To do that properly, I think you need a pobj_t as the first struct 
 member, like string has:
 
 struct parrot_string_t {
 pobj_t obj;
 UINTVAL bufused;
 void *strstart;
 UINTVAL strlen;
 const ENCODING *encoding;
 const CHARTYPE *type;
 INTVAL language;
 };

Ah, no.  That's how you create a new type of header.  I need nothing
more than the simple buffer header.  So I make a PObj and stick this
struct in its bufstart.

 so maybe something like:
 
 struct RegisterChunkBuf {
 pobj_t obj;
 UINTVAL bufused;
 RegisterChunkBuf* next;
 };
 
 But also take a look at list.h and see if it's already doing what you 
 want to do; you may be able to do it directly.
 
 And then, for example:
 
 struct PRegChunkBuf {
 struct RegisterChunkBuf buf;
 struct PRegFrame PRegFrame[FRAMES_PER_CHUNK];
 };
 
 I want these things to be garbage collected, but DOD doesn't trace the
 buffer.  I can't seem to find a way to mark the frames without making
 the chunks into PMCs (yuck).   Is there a way to do this?
 
 I think you'll need to add something to the root set tracing code 
 (probably trace_active_buffers() in src/dod.c). I'm not sure what all 
 of you stuff hangs off of, though.

Did that.  That works for the main part, but continuations and
who-knows-what-else are going to be holding references to parts of
these, so I'd like to mark these automatically.

Unless... hey!  You just gave me an idea.  I'll make a mark_regstack
that anything that holds on to one of these has to call as part of its
mark routine.  I know, it seems like a no-brainer.  Mustn't have had a
brain earlier :-)

 Just some thoughts--I'm a little fuzzy on where these items are rooted.

That's fine, and thanks.  I learned most of these concepts earlier today
hacking on this patch...

Luke


Re: Roles and Mix-ins?

2004-01-06 Thread Luke Palmer
Joe Gottman writes:
 
 - Original Message - 
 From: Luke Palmer [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Sent: Tuesday, January 06, 2004 4:51 AM
 Subject: [perl] Re: Roles and Mix-ins?
 
 
  David Storrs writes:
  
   On Sat, Dec 13, 2003 at 11:12:31AM -0800, Larry Wall wrote:
On Sat, Dec 13, 2003 at 04:57:17AM -0700, Luke Palmer wrote:
  
: For one, one role's methods don't silently override another's.
 Instead,
: you get, er, role conflict and you have to disambiguate yourself.
  
   How do you disambiguate?
 
  Let's see...
 
  role Dog {
  method bark() { print Ruff! }
  }
  role Tree {
  method bark() { print Rough! }
  }
  class Trog
does Dog does Tree {
  method bark() { .Dog::bark() }
}
  }
 
  Perhaps something like that.  In any case, you do it by putting the
  offending method directly in the aggregating class.
 
 
How about something like
 class Trog
does Dog {bark=dogBark} does Tree {bark=treeBark}
{...}
 
 Then we could have code like
   my Trog $foo = Trog.new();
   my Dog $spot :=  $foo;
   my Tree $willow := $foo;
   $spot.bark(); # calls dogBark()
   $willow.bark(); #calls treeBark()
 
This works better when Dog::bark and Tree::bark are both needed but they
 do different things.

Renaming methods defeats the purpose of roles.  Roles are like
interfaces inside-out.  They guarantee a set of methods -- an interface
-- except they provide the implementation to (in terms of other,
required methods).  Renaming the method destroys the interface
compatibility.

Your renaming can be done easily enough, and more clearly (IMO) with:

class Trog 
  does Dog does Tree {
method bark() { ... }   # Explicitly remove the provided method
method dogBark()  { .Dog::bark() }
method treeBark() { .Tree::bark() }
}

Luke



Re: how do I instantiate? -- was: Objects!

2004-01-07 Thread Luke Palmer
Michal Wallace writes:
 On Tue, 2 Dec 2003, Dan Sugalski wrote:
 
  *) Creating new objects involves calling the -init vtable entry *on
  the class*. Because of this each class gets a custom vtable where the
  init method has been swapped out for one (from objects.c) that
  creates a new object instead.
 
 Well, cool! How do I this from parrot?
 
 I've been trying things along the lines of:
 
 .sub _main
.local object Cat
.local object felix
newclass Cat, Cat
P2 = Cat
S0 = init
callmeth
felix = P0
#...
end
 .end

Should go something like this:

.sub _main
.local object Cat
.local object felix
newclass Cat, Cat
find_type $I0, Cat
felix = new $I0
# ...
.end

But note that objects are unfinished.  I ran into a certain problem when
I assumed that attributes could be any type of data; not so -- they can
only be integers (at the moment).  I needed object support right away,
so I simulated using a hash.  The hash has a CLASS key which holds the
class to which it belongs.  I then use this to get the methods.

Luke

 ... But haven't figured out the magic formula yet
 That code above gives:
 
Method 'init' not found
in file '(unknown file)' near line -1
 
 
 (If anyone can post a working example of the code
 above I'd really appreciate it!)
 
 
 Sincerely,
 
 Michal J Wallace
 Sabren Enterprises, Inc.
 -
 contact: [EMAIL PROTECTED]
 hosting: http://www.cornerhost.com/
 my site: http://www.withoutane.com/
 --
 


Re: Continuations don't close over register stacks

2004-01-07 Thread Luke Palmer
Leopold Toetsch writes:
 Jeff Clites [EMAIL PROTECTED] wrote:
  On Jan 7, 2004, at 1:46 AM, Leopold Toetsch wrote:
  That part is already answered: create a buffer_like structure.
  *But* again register backing stacks are *not* in the interpreter
  context.
 
  I don't understand what you are getting at. They are not physically
  part of Parrot_Interp.ctx, but it holds pointers to them, right?
 
 No, they were in the context but aren't any more.
 
  ... So,
  they need to be copied when the context is being duplicated. Is that
  your point, or are you trying to say that they are not _logically_ part
  of the context, or are not supposed to be?
 
 Exactly the latter:
 That was AFAIK a design decision, when Dan did introduce CPS. At this
 time register backing stacks went out of the continuation or whatelse
 context - IIRC did Dan commit that to CVS himself.

In which case I feel obliged to contest that decision.  The register
backing stacks are as much a part of the current state as the program
counter is.

I'm writing a compiler that makes heavy use of continuations for the
purpose of backtracking.  If the register backing stacks aren't closed
over, and I am thus required to keep the state consistent myself, it is
impossible to use continuations for that purpose.  Indeed, it becomes
impossible to use continuations for anything but simulating a control
stack, which is precisely what they are designed to get around.

Luke

 So register stacks are *not* included in any context swapping, being it
 a Continuation or some other context switch. That's it.
 
  JEff
 
 leo


Re: how do I instantiate? -- was: Objects!

2004-01-07 Thread Luke Palmer
Michal Wallace writes:
 On Wed, 7 Jan 2004, Luke Palmer wrote:
 
  Should go something like this:
 
  .sub _main
  .local object Cat
  .local object felix
  newclass Cat, Cat
  find_type $I0, Cat
  felix = new $I0
  # ...
  .end
 
 
 Thanks, but that doesn't work either. :/
 The new op expects an identifier. It won't
 take a VAR, IREG, or REG.

Er, sorry, that's IMCC's fault.  This works:

new felix, $I0

 
  But note that objects are unfinished.  I ran into a certain problem
  when I assumed that attributes could be any type of data; not so --
  they can only be integers (at the moment).  I needed object support
  right away, so I simulated using a hash.  The hash has a CLASS key
  which holds the class to which it belongs.  I then use this to get
  the methods.
 
 I'm not even trying to get objects working yet. I just
 need something that'll let me run setprop on it so my
 generators can make iterator things with a .next()
 attached to them... I was using ParrotObjects and
 ParrotClasss for a while but now you can't make a
 new ParrotObject directly either. :/

I know PerlArray accepts and stores properties: my compiler uses them.
PerlHash probably does too.

And thanks again for all the work you're doing on Python :-)

Luke

 Incidentally, anyone know why not? In python or
 javascript it's easy to just create an object of
 no particular class just to have a place to stick
 things.
 
   foo = object()
   foo.x = 1
 
 It was working fine in parrot too, but then it
 went away. :/
 
 Sincerely,
 
 Michal J Wallace
 Sabren Enterprises, Inc.
 -
 contact: [EMAIL PROTECTED]
 hosting: http://www.cornerhost.com/
 my site: http://www.withoutane.com/
 --
 


Re: Continuations don't close over register stacks

2004-01-07 Thread Luke Palmer
Melvin Smith writes:
 The downside to our implementation is in the return continuation case.
 The common case is to create the continuation that you plan to
 return with, and you already know there will be no need for
 copy-on-write in most cases because typically the execution
 path will return using that continuation, and that will then become
 the main execution context. The original interpreter context and
 all its associated stacks that existed at the time of the snapshot
 will usually immediately be readonly orphans as soon as you activate the
 return continuation (unless you saved the initial main context first).
 It'd be more optimal to skip marking COW altogether in certain cases.

That's what the RetContinuation class does if I'm not mistaken.  But
RetContinuation is a bit presumptuous about what is going to be done
above it.  It must be guaranteed that nobody will try to use the
RetContinuation as a regular continuation without first promoting it
(I can see a way to make such promotion possible, described below).

There are three ways I see to reduce this overhead.

The first is to make the register stacks a linked list of single frames
-- no chunks.  We could make object pools for each of the register frame
types to keep allocation quick.  This would avoid copying altogether in
the common case, but it wouldn't get by marking everything COW.  Plus,
the copying would still happen eventually (I can't think of a way to
safely unmark things COW without copying), just not as much.  In
particular, the asymptotic complexity stays the same.

The second is to move the used counter out of the chunk and into the
stack structure.  This way RetContinuations can be promoted into real
Continuations as long as the stack frame associated with the
RetContinuation has not yet exited.

The last way is to keep a set of 16 flags in each chunk that mark
whether a return continuation has been taken at that point, and if you
try to pop beyond that point, the stack is marked COW and copied.  This
is effectively lazily promoting RetContinuations into real
continuations.

None of these seem optimal at this point, although #2 is definitely
something that could be useful.

Luke


Re: [PATCH] The Return of the Priority DOD

2004-01-07 Thread Luke Palmer
Leopold Toetsch writes:
 Luke Palmer [EMAIL PROTECTED] wrote:
  After many months of lying dormant, I figured I'd get my act together
  and adapt this patch to the few recent modifications.  And this time,
  I'm posting a benchmark!
 
 Wow, thanks.
 
 Some comments:
 
  -b_PObj_needs_early_DOD_FLAG = 1  27,
  +/* true if this is connected by some route to a needs_early_DOD object */
  +PObj_high_priority_DOD_FLAG = 1  27,
  +PObj_needs_early_DOD_FLAG = (1  27 | 1  28),
 
 Moving the needs_early_DOD_FLAG out of the arena_flags is suboptimal
 (and probably the reason for the 5% slowdown for the eager case). Now the
 relevant flags is the high_priority_DOD_FLAG. If I get the patch right,
 it gets set on the PMC itself and all its parents.

Hmm.  Interesting that I did that, as I don't understand arena DOD flags :-)
I would appreciate a short explanation, thanks.

Just as a note, you can expect even more delays to the maintainence of
this patch.  My job just picked up its pace, and I've got to have this
compiler cracking at full-featuredness in the next week.  I'm not
against somebody else maintaining the patch in the meantime :-)

(But rest assured, I will get back to it)

Sorry,
Luke


 
 So it would be fine, if the high_priority_DOD_FLAG would be in the
 arena_flags nibble. The tests in the fast path of pobject_lives can then
 go away - PMCs that can contain other PMCs can't be the parent of PMCs
 that need timely destruction, so that should work. And all PMCs, that
 can contain other PMCs must have a PMC_EXT attached with the next_for_GC
 pointer.
 
 And if that helps, we can just say: If an object needs timely
 destruction it must have the PMC_EXT struct attached, so that marking
 is out of the fast path.
 
 @@ -45,21 +45,45 @@
   UINTVAL *dod_flags = arena-dod_flags + ns;
   if (*dod_flags  ((PObj_on_free_list_FLAG | PObj_live_FLAG)  nm))
   return;
  +if (*dod_flags  PObj_on_free_list_FLAG  nm)
  +return;
 
 This seems bogus, if the flag is set, the first test has succeeded.
 
  +if (PObj_high_priority_DOD_TEST(obj)  interpreter-dod_trace_ptr)
  +/* set obj's parent to high priority */
  +PObj_high_priority_DOD_SET(interpreter-dod_trace_ptr);
 
 That could go probably below, if the special_PMC_FLAG is set.
 
 @@ -84,23 +108,38 @@
 
  -if (PObj_is_special_PMC_TEST(obj)) {
  +if (*dod_flags  (PObj_is_special_PMC_FLAG  nm)) {
 
 This seems to be the non-ARENA_DOD_FLAGS case, so above doesn't work.
 
 leo


Re: Archive tarball?

2004-01-08 Thread Luke Palmer
michael.firestone writes:
 Is there somewhere I can get the entire perl6-language archive in a 
 tarball? 

I personally don't know, but there could be somewhere.

 I am trying to work on turning the Apocalypses into story cards at 
 http://p6stories.kwiki.org.  It would be helpful to me if I could search 
 the mailing list archives to make sure I incorporate any decisions made 
 after each Apocalypse was written.  As there is no search engine at this 
 moment ( that is not a whine or a complaint, merely a statement ), the next 
 best thing for me would be a tarball I could grep. 

Well, most of the decisions you'll find in the official documents: the
apocalypses, exegeses, and synopses.  perl6-language has a lot of
brainstorming, and a lot of Larry saying something interesting in the
form of maybe ..., but those could hardly be considered decisions.

If worse comes to worst, you can always ask me.  I manage to keep the
largest amount of the language in my head with the most time available
to answer questions :-)

Oh, and thanks for the p6stories work.

Luke



Re: [PATCH] Continuations now close over register stacks

2004-01-08 Thread Luke Palmer
Michal Wallace writes:
 Luke Palmer wrote:
 
  This patch re-implements the register backing stacks as PObjs (so
  they can be garbage-collected), honors their COW flags, and adds
  them to the interpreter context (where they should be, honest!).
 
  As a healthy side-effect, it encapsulates their behavior nicely into
  register.c, when before their guts were splattered all over the
  source.
 
 Hey Luke,
 
 I applied this patch, ran make realclean and rebuilt parrot.
 All the parrot tests pass (except the two about numbers, and I
 think they were failing before) but it doesn't like the code
 that pirate's generating. I boiled the problem down to this:
 
 ###
 .sub __main__
 newsub $P0, .Closure, _func
 newsub $P1, .Continuation, done
 .pcc_begin non_prototyped
 .pcc_call $P0, $P1
 done:
 .local object result
 .result result
 .pcc_end
 print result
 print \n
 end
 .end
 
 .pcc_sub _func non_prototyped
 .local object res
 res = new PerlString
 res = hello!
 .pcc_begin_return
 .return res
 .pcc_end_return
 .end
 
 
 When I run this, parrot says:
 
 No more I register frames to pop!
 
 I think the problem is coming from the .pcc_begin_return
 line. This code works fine if I change the .Continuation to
 a .Closure or .Coroutine... It also worked before the patch.
 Do I have my calling conventions screwed up or is this a bug?

Your calling conventions are screwed up.  I'm glad this failed, as I was
anticipating this failure and it didn't come up anywhere in the tests!  

If you unroll what .pcc_call is doing, you might see the problem:

.pcc_begin non_prototyped
.pcc_call $P0, $P1
done:
.local object result
.result result
.pcc_end


Turns into:

@pcc_sub_call_4:
set P0, P17
set P1, P16
set I0, 0
set I1, 0
set I2, 0
set I3, -2
updatecc
savetop
invoke
done:
restoretop
set P16, P5

When the continuation is invoked, that savetop it just did is completely
nullified, and you're back to the state before you created the
continuation.  So, in order to get this to work properly, your first
four lines must be:

.sub __main__
newsub $P0, .Closure, _func
savetop
newsub $P0, .Continuation, done

So the restoretop after the invoke has something to pop (and so your
register state isn't screwed up when you get back).

Or you could do as PCC does and use a .RetContinuation, which doesn't
close over the stacks, when you don't actually need a full continuation.

Hope this helped,

Luke



Re: [PATCH] Continuations now close over register stacks

2004-01-09 Thread Luke Palmer
Michal Wallace writes:
 On Thu, 8 Jan 2004, Luke Palmer wrote:
  .sub __main__
  newsub $P0, .Closure, _func
  savetop
  newsub $P0, .Continuation, done
 
  So the restoretop after the invoke has something to pop (and so your
  register state isn't screwed up when you get back).
 
 
 Thanks Luke.
 
 I changed my compiler to call savetop before every function
 call, and that passes my tests but I'm having trouble
 visualizing why. Would I ever NOT want to call savetop
 before creating a continuation?

Very rarely would you not savetop before creating a *real* continuation.
But again, very rarely would you actually create a *real* continuation
(depending on your language).  RetContinuations are almost always a
better choice for traditional languages, and languages like Python with
no support for continuations.

You won't get in trouble mixing RetContinuations with real ones, as long
as you don't try to use RetContinuations like Continuations, and only
use them to return downward.

Luke


Re: BUG: coroutine + exception = stack_height segfault

2004-01-09 Thread Luke Palmer
Jeff Clites writes:
 On Jan 9, 2004, at 12:24 AM, Leopold Toetsch wrote:
 
 Michal Wallace [EMAIL PROTECTED] wrote:
 #!/bin/env parrot
 #
 # yieldbug.imc
 #
 # This program should print dots forever.
 # Instead it prints a few dots and then segfaults.
 
 It does print dots forever here.
 
 It does for me too. But based on a previous email, I assume you are 
 getting the crash after applying Luke's continuations patch? (I haven't 
 tried your script with that applied.)

Ahh, that could make sense.  I didn't do any work on the Coroutine PMC,
so it's probably not doing what it should with the new register stack
semantics.

Luke


Re: [PATCH] The Return of the Priority DOD

2004-01-09 Thread Luke Palmer
Leopold Toetsch writes:
 Luke Palmer [EMAIL PROTECTED] wrote:
  ...  I'm not
  against somebody else maintaining the patch in the meantime :-)
 
 I went again through the patch and the original one from Sept, 5th. But
 it seems that one thing is missing in both:
 
 *If* all PMCs which needs_early_DOD are seen live, the DOD run is
 aborted. But completing the DOD run also resets live bits of non-dead
 objects, which is missing now.
 
 It seems, that in that case we still need to walk the PMC arenas and
 reset all live bits. OTOH when ARENA_DOD_FLAGS is on, this isn't too
 expensive because it can be done my masking a full word worth of 8 PMCs
 at once. So its still a lot faster then the eager case - hopefully.
 
 Or am I missing something?

I don't think you are.  I would have thought that GC be the one to reset
the live bits, but there was a lot of DOD that I didn't completely
understand.  I don't remember explicitly taking such a thing out, but I
could have inadvertently.

Thanks for looking through the patch.

Luke


[PATCH] bug in clear_live_bits

2004-01-10 Thread Luke Palmer
sweep 0 was making parrot segfault for me.  The patch explains why.

Luke


Index: src/dod.c
===
RCS file: /cvs/public/parrot/src/dod.c,v
retrieving revision 1.81
diff -u -r1.81 dod.c
--- src/dod.c   10 Jan 2004 19:43:06 -  1.81
+++ src/dod.c   11 Jan 2004 06:17:18 -
@@ -735,12 +735,11 @@
 static void
 clear_live_bits(Parrot_Interp interpreter)
 {
-struct Small_Object_Pool *pool;
+struct Small_Object_Pool *pool = interpreter-arena_base-pmc_pool;
 struct Small_Object_Arena *arena;
 UINTVAL i;
 UINTVAL object_size = pool-object_size;
 
-pool = interpreter-arena_base-pmc_pool;
 /* Run through all the buffer header pools and mark */
 for (arena = pool-last_Arena; arena; arena = arena-prev) {
 #if ARENA_DOD_FLAGS


Contextual calls

2004-01-11 Thread Luke Palmer
I was uneasy when the Cnum_eq and Cstr_eq vtable entries were first
proposed.  Sure, they get the job done for Perl 5, but Perl 6 is
expanding its notion of context beyond those compiled in.  You're
supposed to be able to add, say, nontransitive ring context if you
want.

There needs to be a way to pass context into not only sub calls, but
vtable methods, and maybe even certain non-vtable ops.  Rather than add
an extra op parameter for each of these, I propose we make it stateful,
like:

num_eq $P0, $P1, foo
str_eq $P0, $P1, bar

Becomes

context .NUMERIC
eq $P0, $P1, foo
context .STRING
eq $P0, $P1, bar

This works efficiently since context often propigates inward, as in:

if   $x + $y  $z  {...}
 ---
   num
 
num
   ---
bool

And that, like classes, contexts would be specified by integer
descriptor, or at worst, constant PMC.

This might also be modified to fit in nicely with the proposed key
registers idea.

Luke


Re: PMC template generator. Perl 5 task

2004-01-12 Thread Luke Palmer
Dan Sugalski writes:
 Okay, here's a task for the perl 5 proficient. I may have mentioned 
 this before, but maybe not.
 
 What we need, or at least could really use, is a script that 
 automatically generates missing vtable methods for PMCs. Not 
 defaulting, the way we have now, but actual real working entries.
 
 For example, if we have a (non-hypothetical) Integer class which has 
 get/set integer as real working vtable entries, the template 
 generator should be able to construct get/set string, number, and PMC 
 functions, a String class should be able to have get/set integer, 
 number, and pmc functions, and so on. The binary vtable ops are also 
 constructable this way in part, as are the keyed variants. (If 
 there's a _keyed variant, the _keyed_int variant is constructable, 
 and vice versa)

If there are no takers by Friday, I'll take this on.  This is right up
my alley :-)

Luke


[PATCH] Small register stack fix

2004-01-12 Thread Luke Palmer
This fixes a rather obvious and silly oversight in my patch.

Luke


Index: src/register.c
===
RCS file: /cvs/public/parrot/src/register.c,v
retrieving revision 1.35
diff -u -r1.35 register.c
--- src/register.c  12 Jan 2004 09:50:26 -  1.35
+++ src/register.c  12 Jan 2004 19:54:36 -
@@ -107,7 +107,8 @@
 struct RegisterChunkBuf* buf = 
 new_bufferlike_header(interpreter, sizeof(struct RegisterChunkBuf));
 *buf = *chunk;
-
+PObj_COW_CLEAR((PObj*)buf);
+
 Parrot_block_DOD(interpreter);
 Parrot_allocate_zeroed(interpreter, (PObj*)buf, stack-chunk_size);
 Parrot_unblock_DOD(interpreter);


[PATCH] new_noinit and init ops

2004-01-12 Thread Luke Palmer
I have somewhat a predicament.  I want to create a continuation, and
have that continuation stored in the register stack that it closes over
(this is how I'm implementing a loop with continuations).  Unless I'm
having a major braino, I don't think this is possible at the moment.

I got around this by adding two ops: new_noinit and init.  I've included
a patch that implements them.  Other solutions welcome.

Luke

Index: ops/pmc.ops
===
RCS file: /cvs/public/parrot/ops/pmc.ops,v
retrieving revision 1.16
diff -u -r1.16 pmc.ops
--- ops/pmc.ops 31 Dec 2003 11:54:38 -  1.16
+++ ops/pmc.ops 12 Jan 2004 19:54:45 -
@@ -52,6 +52,15 @@
 Like above. The forth argument is a property hash - it isn't copied in,
 only referended. The initializer may be NULL.
 
+=item Bnew_noinit(out PMC, in INT)
+
+Just like above, but doesn't initialize the PMC.  You must call Binit
+on it before using it.
+
+=item Binit(in PMC)
+
+Initializes a PMC created with new_noinit.
+
 =cut
 
 op new(out PMC, in INT) {
@@ -60,9 +69,6 @@
 abort(); /* Deserve to lose */
   }
 
-  /* Why?? If we're creating a continuation, the continuation PMC
-   * needs to be in the destination register before its init method
-   * copies the registers. */
   $1 = pmc_new_noinit(interpreter, $2);
   $1-vtable-init(interpreter, $1);
   goto NEXT();
@@ -84,6 +90,19 @@
   $1-vtable-init_pmc_props(interpreter, $1, $3, $4);
   goto NEXT();
 }
+# }
+
+op new_noinit(out PMC, in INT) {
+  if ($2 = 0 || $2 = enum_class_max) {
+internal_exception(1, Illegal PMC enum (%d) in new\n, (int)$2);
+  }
+  $1 = pmc_new_noinit(interpreter, $2);
+  goto NEXT();
+}
+
+op init(in PMC) {
+  $1-vtable-init(interpreter, $1);
+  goto NEXT();
 }
 
 


Re: [PATCH] new_noinit and init ops

2004-01-12 Thread Luke Palmer
Luke Palmer writes:
 ...
 
goto NEXT();
 @@ -84,6 +90,19 @@
$1-vtable-init_pmc_props(interpreter, $1, $3, $4);
goto NEXT();
  }
 +# }

 ^

Don't mind that.  I thought I saw an extra one, and commented it out to
make sure I wasn't being stupid.  Wasn't, and forgot to uncomment.

Luke

 +
 +op new_noinit(out PMC, in INT) {
 +  if ($2 = 0 || $2 = enum_class_max) {
 +internal_exception(1, Illegal PMC enum (%d) in new\n, (int)$2);
 +  }
 +  $1 = pmc_new_noinit(interpreter, $2);
 +  goto NEXT();
 +}
 +
 +op init(in PMC) {
 +  $1-vtable-init(interpreter, $1);
 +  goto NEXT();
  }
  
  


Re: [PATCH] Small register stack fix

2004-01-12 Thread Luke Palmer
Dan Sugalski writes:
 At 10:09 PM +0100 1/12/04, Leopold Toetsch wrote:
 Luke Palmer [EMAIL PROTECTED] wrote:
  This fixes a rather obvious and silly oversight in my patch.
 
  +PObj_COW_CLEAR((PObj*)buf);
 
 I don't think that works or better let's say: it's ok 50 percent - for
 the new buf chunk, but the old one, which maybe hasn't any refering
 COWed copy anymore still has the COW flag on that buffer.
 
 I think I'd as soon leave COW-marked buffers as COW forever, or until 
 they're garbage collected. Most stack segments that get marked COW 
 are either going to be unreferenced, in which case the COW status is 
 irrelevant, or are on a code path likely to create a continuation 
 with a handle on the COW'd chunk thus making its COW status 
 reasonable.

I agree with Dan here.  Thinking about the common cases, marking COW
means marking immutable, as in a continuation.  Once that's made, it
will never become mutable again.   Indeed, once the continuation gets
collected, then you can unmark the stack, but half of it's probably
already copied and in use somewhere else instead.

But that patch needs to go in anyway, as copying something so you can
mutate it and then keeping it cow is... silly at best.

Luke

 Since this is going to be invisible to user code, we can leave it as 
 is for now and revisit the entire scheme in its entirety later if we 
 want to do an optimizing run across the source.
 -- 
 Dan
 
 --it's like this---
 Dan Sugalski  even samurai
 [EMAIL PROTECTED] have teddy bears and even
   teddy bears get drunk


Re: [PATCH] new_noinit and init ops

2004-01-12 Thread Luke Palmer
Michal Wallace writes:
 On Mon, 12 Jan 2004, Luke Palmer wrote:
 
  I have somewhat a predicament.  I want to create a continuation, and
  have that continuation stored in the register stack that it closes
  over (this is how I'm implementing a loop with continuations).
  Unless I'm having a major braino, I don't think this is possible at
  the moment.
 
  I got around this by adding two ops: new_noinit and init.  I've
  included a patch that implements them.  Other solutions welcome.
 
 Hmm. That sounds like Coroutine. 

Uh, how so?  Are we mixing up Continuation/Coroutine vocabulary again?

 Also, when you invoke any kind of sub with the calling conventions,
 it's already in P0. Can't you store that in a local variable on the
 invoke?

Yeah, I wouldn't normally consider it pad material, but that does seem
like the cleanest way at the moment.

Luke



Re: [PATCH] new_noinit and init ops

2004-01-12 Thread Luke Palmer
Michal Wallace writes:
 On Mon, 12 Jan 2004, Luke Palmer wrote:
 
  Michal Wallace writes:
   On Mon, 12 Jan 2004, Luke Palmer wrote:
  
I have somewhat a predicament.  I want to create a continuation, and
have that continuation stored in the register stack that it closes
over (this is how I'm implementing a loop with continuations).
  
   Hmm. That sounds like Coroutine.
 
  Uh, how so?  Are we mixing up Continuation/Coroutine vocabulary again?
 
 :)
 
 Well... A Coroutine is a pausable, resumable continuation, right?
 Or basically a closure with a continuation inside it. 

Both of those sentences seem wildly redundant to me.  I think we might
be stuck on vocabulary.  We're surely both understanding the same thing
in different ways.

A continuation is one snapshot -- it never changes, it never runs.  To
invoke the continuation is to take you back to that snapshot and start
running from there.  To invoke it a second time is exactly like invoking
it the first time.

A coroutine is like a variable that holds continuations, and updates
itself whenever it yields.  I guess that's the best way I can put it
with my affliction against coming up with good similes.

I think this is what you were saying... maybe.

But it's easy to implement a loop using a single continuation.  Like
this:

newsub $P0, .Continuation, again
again:
# ... loop body
invoke $P0

That's not *exactly* what I was doing.   All I was doing was
implementing a loop that called subs repeatedly with a backtrack
continuation, so they could jump out at any point in their execution.
It seemed odd that there was no way to keep the continuation I was
giving everyone around without using a lexical pad.

It's working now (there are some weird things going on though which I'm
trying to track down), and I don't really mind the lexical pad.

Luke

 I was just guessing how you might be implementing the loop. It sounds
 like a recursive tail call, but that struck me as a job for goto
 instead of a continuation. So I thought maybe you needed the
 continuation to save for later, and that made me think of a Coroutine.
 
 That's what was running through my head anyway. As for
 why I mentioned it based on all those assumptions... uhh,
 beats me. My real point was just the part about the
 calling conventions the thing you're calling in P0. :)
 
 Sincerely,
 
 Michal J Wallace
 Sabren Enterprises, Inc.
 -
 contact: [EMAIL PROTECTED]
 hosting: http://www.cornerhost.com/
 my site: http://www.withoutane.com/
 --
 


[PATCH] Updatecc fix

2004-01-13 Thread Luke Palmer
In the spirit of getting real continuations working Just Right, this
modifies IMCC's PCC implementation to emit the updatecc *after* the
pushtop, so that the redundant pushtop isn't necessary when returning
with a real continuation.

I'm also thinking that updatecc should cow_copy_context, not
save_context.  Right?

Luke

Index: imcc/pcc.c
===
RCS file: /cvs/public/parrot/imcc/pcc.c,v
retrieving revision 1.39
diff -u -r1.39 pcc.c
--- imcc/pcc.c  16 Dec 2003 08:53:34 -  1.39
+++ imcc/pcc.c  14 Jan 2004 06:09:31 -
@@ -997,13 +997,13 @@
 /*
  * if we reuse the continuation, update it
  */
+ins = insINS(interp, unit, ins, savetop, regs, 0);
 if (!sub-pcc_sub-nci)
 if (!need_cc)
 ins = insINS(interp, unit, ins, updatecc, regs, 0);
 /*
  * emit a savetop for now
  */
-ins = insINS(interp, unit, ins, savetop, regs, 0);
 ins = insINS(interp, unit, ins, need_cc ? invokecc : invoke, regs, 0);
 ins-type |= ITPCCSUB;
 /*


Re: run-once code

2004-01-13 Thread Luke Palmer
David Storrs writes:
 Given this code:
  
 if ( some_expensive_lookup_function() = $MAX_RECORDS ) {
mark_that_we_have_reached_max_records();   
return;
 } 
 
 After I enter that block once, I never want to evaluate the condition
 again--I want the code to completely disappear from the bytecode (or,
 at least, be jumped around).  How would I do that in Perl 6?

Hmm...

my $max_reached;
sub mark_that_we_have_reached_max_records() {
$max_reached = 1;
}

if !$max_reached  some_expensive_lookup_function()  $MAX_RECORDS {
mark_that_we_have_reached_max_records();
return;
}

That's a new feature we're adding called conditional code removal,
sometimes known as short circuiting :-)

I've given some thought to this sort of thing for optimization, however.
Obviously a conditional on a variable isn't a big price to pay, but when
you have a lot of them, removing the code altogether might save you some
important cycles.  This is particularly true if this condition is within
a tight loop.

So, let's say you have something like:

$x = 100_000;
my $seen;
while $x -- 0 {
if $seen || cheap_condition() {
something();
}
$seen++ if other_cheap_condition();
}

We'd like this to be easy to unroll into:

$x = 100_000;
while $x -- 0 {
if cheap_condition() {
something();
}
last if other_cheap_condition();
}
while $x -- 0 {
something();
}

Especially if something() is a complex expression that's prone to typing
errors, we'd like to keep out the code duplication.

This could well be something the optimizer does, but assuming otherwise,
optimized currying could be to our benefit.

sub do_the_loop($x, $seen) {
while $x -- 0 {
if $seen || cheap_condition() {
something();
}
last if !$seen  other_cheap_condition();
}
return $x;
}

do_the_loop.assuming(seen = 1).(
do_the_loop.assuming(seen = 0).(100_000));

If curries are subject to a short constant-folding pass, this should
easily give us the effect we want.

 (I recall seeing something about how to make assertions drop out, but
 I want to be able to do this at run-time, not compile-time.)

As uri said, who can tell the difference?

Luke


Re: run-once code

2004-01-14 Thread Luke Palmer
Jonathan Scott Duff writes:
 On Tue, Jan 13, 2004 at 10:16:48PM -0700, Luke Palmer wrote:
  So, let's say you have something like:
  
  $x = 100_000;
  my $seen;
  while $x -- 0 {
 
 Don't do that!  I had to look at this twice before I decided that
 perl6 didn't get a new operator  :)

That was Damian's favorite trick for a while.  I liked it and adopted
it. :-)

  [ loop unroll + currying example elided ]

 Not sure I like the currying, but if that's what works, so be it.

I've been trying to stress this as an undertone in all my posts about
optimization:  Perl isn't going to optimize for you!  It's going to
help, but if you want real speed, you're probably going to have to work
for it.  Computers just aren't smart enough to do it for you --
especially in a language like Perl.

In fact, I'd like it to stay back and let me decide what needed speed.
If I care enough, I'll tell it.  I remember a project I did recently
that made extensive use of backward chaining.  For instance, you'd have:

rule '$age' = sub {
print What is your age? ;
$age = STDIN;
}
rule '$main' = sub {
$age;# Force the backward chain
$main = done;
}

But the line with just $age got optimized away by Perl, much to my
discontent, and I was unable to disable this feature.  So I ended up
saying:

sub null { }
...
$age  null;

To force the evaluation.  This I consider a hack, and would rather that
Perl 6 not force me to do this.  I don't mind something like a

no optimize;

Though.

/rant

Luke


<    4   5   6   7   8   9   10   11   12   13   >