Re: PCC and IMC
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
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
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
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
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
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
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
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]
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
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
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
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?
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
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
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
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
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
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
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
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
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
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
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
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
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)
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
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
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
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
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
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
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
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
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
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
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]
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]
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....??
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....??
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....??
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?
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
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
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
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
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?
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
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
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
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
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
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
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
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)
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)
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
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?
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
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
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
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
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
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
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.
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
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
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.
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
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
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
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?
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
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
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?
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?
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
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?
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!
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
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!
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
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
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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