Re: junctions and conditionals
Dave Whipp wrote: I'm thinking that the solution to this issue may be a little more radical than to-date: don't permit junctions to be stored in $ variables! Instead, require junctions to use a twiggle, to alert the reader that the surprises may be lurking. my $x = 1|2; #error my $|x = 1|2; # ok Then you just need to invent some syntax to say that collapse is (or perhaps isn't) desired: if [[ $|x 1 ]] { say $|x collapsed } The most important thing that this does is that it leaves open the option to allow $ variables to hold junctions in some future version of Perl, without that future version being constrained by legacy semantics. I'd second the twigil idea. Reason: I'd -really- like perl6 to be compilable into an efficient machine code without a JIT magic that we can currently only handwave about. For that, I'd propose a rule of a thumb: ints are ints. Of course, floats and other unboxed types should also be just plain unboxed types, but I'd like the rule of a thumb to be short and to the point. So, int $x = 1|2; should be an error. Also, int $x = 1 but not really a number; should also be an error or at least a warning that mixin stripping and unboxing took place. If you want polymorphic here, use Ints. That'd also mean that my @x of int; can be implemented as a homogenous int vector, meaning -really- efficient and manipulable through the kind of code that modern CPUs are really good at (since as soon as you know you won't be lazy, you only need to be polymorphic about asking for the beginning of the in-memory buffer that can be manipulated directly. Even if that buffer doesn't contain all the elements, you can refill it as needed, and that could still be fast as long as the other side of the partially-lazy barrier also speaks int). Also, as far as I'm aware, there is no tracing VM that can create a homogenous arrays for you if you can't already do them. From the above, the need for twigils in junctions should be apparent. Miro
Re: ***SPAM*** Re: perl 6 grammar
cdumont wrote: In japanese it could even be : wa { '' no baai ni { ... } } Getting rid off the thema or I guess here taking $_ as the default. is this possible : given $operator { '' {} '' {} } ? If Larry doesn't mind me elbowing into the conversation... The unmentioned detail here is that given and when are decoupled; they're not two keywords in the same construct. In other words, given can be used without when and when can be used inside any block. Cgiven only binds $_ and executes a block, it's kind of a single-shot Cfor. So you can do this: given $long_expression_that_is_difficult_to_type_more_than_once { .trim; s:g/!alpha//; .prettify; .indent; say $_; } And Cwhen simply matches the current $_ with its argument. So you can, for example, use it inside Cfor or Cmap: @encoded = map @list:{ when 'black' { 1 } when 'white' { 2 } when /#(.*)/ { $1 } } Miro
Implementing junctions
I've been looking at various Perl6 operators in terms of what their implementation would look at the Parrot level. Junctions struck me as possibly highly problematic. The issue is, how would one go about compiling them at the point when they get passed to a function call as 1 of the parameters. For instance, in pugs, this works: pugs my $a = 1|2 (1 | 2) pugs sin $a (0.8414709848078965 | 0.9092974268256817) pugs sub foo() { return 1|2; } pugs foo() (1 | 2) pugs sin foo (0.8414709848078965 | 0.9092974268256817) I came up with two ways: 1) Use Junction PMC that overloads various conversion entries in its vtable. Operators will have to use continuations to loop over junction contents. -- This seems a non-starter, as vtable entries can't spawn a continuation that can reenter them. (right?) 2) Expand explicitly. -- Problem is, you need to insert checks for each parameter before each function call, if a junction can be assigned to a variable like above. This means that perl6 calling convention would have to explicitly typecheck parameters everywhere. This strikes me as much less efficient then, say, checking for ties everywhere. And ties have to be explicitly declared. Would it make sense to require that Junctional variables *MUST* be declared as such, and same with function that return junctions? Strict reading of S9 seems to imply that this already is the case, but possibly a clarification with some examples might be in order. So the example above would read: my Junction $a = 1|2 sub foo(-- Junction) { return 1|2; } And hope this topic hasn't already been rehashed. :) Miro
Re: Runtime role issues
Paul Seamons wrote: On closer inspection, is it even possible to add a Role to a Class at runtime? If it isn't now, I would certainly like to have a hook available through MOP (which is, to the best of my knowledge, still unspecified). I thought that Class and Role composition outside of compile time resulted in a new pseudo Class for the subsequent instances of that composition - in which case the original Class would remain unmodified. I believe 'does' and 'but' operators work that way, yep. Additionally, they're per instance. Offhand I don't even recall any way to create an uninstantiated class with a role mixed at runtime (would my $class_foobar = ::Foo but ::Bar do the trick?) Miro
Re: RFC: multi assertions/prototypes: a step toward programming by contract
Aaron Sherman wrote: In the RFC, I was trying to develop a method by which a module could assert a stricture (consider this part of use strict in Perl 6 if you will) that would constrain the CALLER of that module (as well as the module itself, of course) to a particular signature template for a multi. This allows us to centrally document a multi that might be defined in many places, and have that documentation actively constrain the multi to match. In this way, the user doesn't have to figure out that max is a method on Array in order to find its documentation, and a module that uses Array gets Um, so if I get this right, you want to restrict the users of the module from *EVER* extending that particular part of the module's functionality? I would be strongly opposed to the existence of this feature. Firstly, what you propose is not DBC. Design by contract is about requiring minimal functionality from the parties in the contract, not about banning them from going above the requirements. Secondly, what happens when you use two modules with two different prototypes for the same multi? Without this declaration, and assuming the modules don't try to dispatch on the same argument lists, everything just works. But with this stricture, you simply aren't allowed to do this, and I don't see any justification for it. Frankly, sometimes things -will- be named the same and yes, sometimes you need to use grep to find the docs. Not sure why this is a problem, though. Miro
Re: RFC: multi assertions/prototypes: a step toward programming by contract
Aaron Sherman wrote: I certainly hope not, as I agree with you! That's not the goal at all, and in fact if that were a side effect, I would not want this to be implemented. The idea of having types AT ALL for protos was something that I threw in because it seemed to make sense at the end. The really interesting thing is to match signature shapes, not types. That is, max doesn't take two positional arguments, and a max that does is probably doing something that users of max will be shocked by. To this end, a programmer of a library *can* issue an assertion: all implementations of max will take one (no type specified) positional parameter and any number of adverbial named parameters (again, no type specified). What bugs me is a possible duplication of functionality. I believe that declarative requirements should go on roles. And then packages could do them, like this: package Foo does FooMultiPrototypes { ... } Of course, I hadn't quite thought this through - as packages aren't classes, there would probably have to be heavy constraints on what FooMultiPrototypes may declare. This would also allow you to reuse multi prototype sets. Also, I don't think you answered Trey's concern, that your mechanism allows you to declare what classes may export but not what they *have* to export, which I would also view as more important - your mechanism seems to only serve to ban extensions and convenience methods, but doesn't give any extra promises on the class behaviour. To extend your example, if a library developer provides a three-argument max, it won't get in the way and won't break any existing contracts. But if the same developer doesn't also provide 2-argument max on that same class, it may very well break any code that works with that class.
Re: Nitpick my Perl6 - parametric roles
TSa wrote: role Set[::T = Item] does Collection[T] where { all(.members) =:= one(.members); }; Nice usage of junctions! But buggy - one means *exactly* one. So for an array of more than 1 element, all(@array) never equals one(@array) - if they're all the same, it's more than 1, otherwise it's 0. all(.members) =:= any(.members) would also not work, as it will try to match each member with some other or same member of the array. It will always return true, in other words, as each element of the array is equal to itself. This leaves all(.members) =:= .members[0], possibly extra with non-emptiness test. Miro
Re: [svn:perl6-synopsis] r11969 - doc/trunk/design/syn
[EMAIL PROTECTED] wrote: +=head1 Cross operators + +The final metaoperator is the CX metaoperator. It applies the +modified operator across all permutations of its list arguments. All +CX operators are of list infix precedence, and are list associative. + +The bare form of CX is considered an operator in its own right. +Saying: + +a b X 1,2 X x y + +produces + +['a', 1, 'x'], +['a', 1, 'y'], +['a', 2, 'x'], +['a', 2, 'y'], +['b', 1, 'x'], +['b', 1, 'y'], +['b', 2, 'x'], +['b', 2, 'y'] Would it be possible to extend Cnext to pass its arguments to the iterator being 'nexted'. Along with proper arguments to whichever lazy object it generated by X, it'd enable this: (where :$slice argument would cause X to increment the member of the tuple at the appropriate index, and resets all the other ones): for 1,2,3 X 1,2,3 - [$i, $j] { if $j $i { next(slice = 0); } say $i, $j; } 11 21 22 31 32 33 As another example, if a tree iterator has :right keyword argument to return the node to the right, you could do: for $tree.each - $node { if $node.value $goal { next; } if $node.value $goal {next :right; } return $node; } Alternative proposal could be to allow expression after next, which gets evaluated instead of incrementing the iterator, iterator is topic in that expression and is replaced by the result. So next True; causes infinite loop, next .left calls .left accessor and next .right calls right accessor before reentering loop (but doesn't do the default increment that for does).
Re: [svn:perl6-synopsis] r8573 - doc/trunk/design/syn
[EMAIL PROTECTED] wrote: We can't. The problem is that: foo .bar has to mean: foo($_.bar) So the only way to allow whitespace in dot operations is to put it after the dot. Damian I believe Larry's latest updates to Synopses allow for some syntactic categories to be disabled in certain context, and to allow priorities between categories. So would this make sense? -- - C.bar can be successfully parsed as both method call (postfixish something?) and term - when postfix is disallowed, such as at the beginning of an expression or after a paren, C.bar is a term and means C$_.bar - otherwise, it's a method call, and to get Cfoo ($_.bar) you have to at least say Cfoo (.bar) -- requiring this actually seems more readable to me. Miro
Re: Class methods vs. Instance methods
[EMAIL PROTECTED] wrote: : class Dog { : method tail { brown and short } : }; : : class Chihuahua is Dog { : has $.color; : method tail { $.color _ and short } : }; : : You can say Dog.tail, Dog.new.tail, Chihuahua.new.tail, but not : Chihuahua.tail. That's extremely counter-intuitive. I don't think it's counterintuitive. You've defined Dog with an invariant .tail but not Chihuahua. It's doing exactly what you asked for under a prototype view of reality. Except there are no such things as classes in a prototype view of reality. Everything is an instance and there are no such things as class methods. The entire idea that an object (::Dog) can call methods that are for another object ($fido) is ... well ... it's a little off. That's like saying any object can call any method from any other object so long as that method is invariant. In a prototype-instance system, instance(Dog) isa class(Dog) instance(Chihuahua) isa class(Chihuahua) isa class(Dog) instance(Chihuahua) isa instance(Dog) Note that instances inherit doubly, from own class and from parent's instance. But this does not imply that: class(Chihuahua) isa instance(Dog) So I don't see a problem. Miro
Re: choice of signatures
[EMAIL PROTECTED] wrote: Jonathan Lang wrote: Instead of multi sub *infix:~(ArabicStr $s1, ArabicStr $s2) {...} multi sub *infix:~(Str $s1, ArabicStr $s2) {...} multi sub *infix:~(ArabicStr $s1, Str $s2) {...} as S13 say multi sub infix:+ (Us $us, Them $them) is commutative { myadd($us,$them) } I believe this declares that $a + $b == $b + $a, not just that you can swap the types of the arguments. I.e. it implements multi sub infix:+ (Them $them, Us $us) { $us + $them } for you. And string concatenation isn't commutative. Miro
Re: given too little
[EMAIL PROTECTED] wrote: If so then my and Eric's wishes are answered: when { $_ 5 } { ... } when { .caloric_value $doctors_orders } { ... } This isn't implemented in pugs yet, but I guess it can be once this is clarified. Actually when $_ 5 { ... } when .caloric_value $doctors_orders { ... } should also work because ~~ match table states that Anything ~~ boolean returns the boolean on the right. Miro
Re: Re(vised): Proposal to make class method non-inheritable
Disclaimer: I don't ~~ @larry :) [EMAIL PROTECTED] wrote: class Bar { our $.bar; { my $.foo; } } I assume that the leading $. is what makes the difference, however, IIRC the $. is just part of the name, and no more special than that. Which means that I can choose that name (yes, it is evil, but I assume I can still do it). U... I'm not sure that allowing $. injection from the nested blocks is a good thing. I don't think it's ambiguous, but to me it looks weird and confusing - if a user put the variable in the nested block like that, it's almost certain he actually meant to write { my $foo; } and the . was put there erroneously. But given that the variable will be accessible to all methods via the closure mechanism, the only thing missing I think is the ability to get at the variable via introspection. Now, as for class methods, I suppose it is possible to just stash then in the classes symbol table like with variables. However, do we then loose the method call syntax? Well, if it belongs to the module part of the class, the syntax would be Bar::method(...), right? This also means that they would not (directly) be inheritable since inheritence moves along superclass lines, and not with @ISA. Well, namespaces should generally be inheritable. How else would lexical namespaces inject variables from outer block into the inner? I guess at the package level declaration that Class1 is Class2 would just inject symbols from one module into the other? (yes, this is kinda handwavy :/ ) I am also not sure what you mean about multi-methods either, could you please explain more? Uhm. I'm not sure either. :) The way I read Larry's mail, multimethods use .isa operator to detect whether $foo belongs to Foo. And for every class, Foo.isa(Foo) is true (this is exceptional behaviour of .isa). So multi bla (Foo $f); would accept both bla(Foo.new()) and bla(::Foo). (Larry, please correct me on this if I'm misparaphrasing you :) ) Anyway, this makes me cringe on a certain level, although I'm not sure I can put the reason into words. Strictly speaking, it's bad only if there are cases where multimethod should behave differently for a class and an instance. One case I can think of is class AutoCreation { ... }; multi dwimmy_instance(class AutoCreation $obj) { $obj.new() } multi dwimmy_instance(AutoCreation $obj) { $obj } (I pulled the syntax out of my nose for this). Anyhow, this looks like a pretty contrieved usage. I'm still trying to think of a non-contrieved, more realistic situation when you might actually want something like this. Miro
Re: Re(vised): Proposal to make class method non-inheritable
[EMAIL PROTECTED] wrote: U... I'm not sure that allowing $. injection from the nested blocks is a good thing. I don't think it's ambiguous, but to me it looks weird and confusing - if a user put the variable in the nested block like that, it's almost certain he actually meant to write { my $foo; } and the . was put there erroneously. Gack, furthermore, I was thinking 'has' and reading/writing 'my'. Sorry. :( But given that the variable will be accessible to all methods via the closure mechanism, the only thing missing I think is the ability to get at the variable via introspection. Now, as for class methods, I suppose it is possible to just stash then in the classes symbol table like with variables. However, do we then loose the method call syntax? Well, if it belongs to the module part of the class, the syntax would be Bar::method(...), right? Yes, but the . is the method invocation operator, the :: is package symbol table access. I think they really mean different things. Yes. Now to be literal-minded, if Foo is a class... Foo::method() would mean package(Foo)::method() (do package access, call method. No invocant, but you can access the proper child of Foo as $*MODULE) Foo.method() would mean Class::method(Foo:) (forward to metaclass, with class as an invocant) Nicely symetric, and (IMHO) completely unintuitive. So what exactly means to say that a class is a module? This also means that they would not (directly) be inheritable since inheritence moves along superclass lines, and not with @ISA. Well, namespaces should generally be inheritable. I don't think this is true, this is a Perl 5-ism. How else would lexical namespaces inject variables from outer block into the inner? I think you are confusing namespacing with scoping. The scope rules are as such that the inner can access see the outer. Fair enough. I was talking about implementation - this means you need symbol table import and shadowing (with the symbols defined in the inner scope). Same (or similar) policy could be used for class methods and attributes. I guess at the package level declaration that Class1 is Class2 would just inject symbols from one module into the other? (yes, this is kinda handwavy :/ ) I don't think this would be so, unless you explicitly asked for it. I'm not sure I understand, why not? Anyway, this makes me cringe on a certain level, although I'm not sure I can put the reason into words. Strictly speaking, it's bad only if there are cases where multimethod should behave differently for a class and an instance. One case I can think of is class AutoCreation { ... }; multi dwimmy_instance(class AutoCreation $obj) { $obj.new() } multi dwimmy_instance(AutoCreation $obj) { $obj } I think we need some ability to differentiate between the class version of Foo and the instance version of Foo. I think we agree here. :) Miro
Re: Re(vised): Proposal to make class method non-inheritable
[EMAIL PROTECTED] wrote: I think what bothers me most about this is that it seems there is no way to tell the difference between class methods and instance methods. That the distinction is only made when the body of the method does something which is is not supposed to do (method called with a class invocant attempts to access an instance variable, etc). This is one of the major problems that I have always had with Perl 5 OO. That there is a very fuzzy fuzzy line between the responsibilities of a class and an instance. I can see the notion of a class which is not yet instantiated, this makes sense in many contexts. But I don't think that in order to have this, we need to bring back this element of Perl 5 OO. I think we can still have all the behaviors you have been describing, and still keep classes and their instances as distinct entities. It just recently occured to me that Class is a Package. So, on the object model level, class methods/attributes belong to the Package part of a class, while instance methods/attributes belong to the Class part of a class - insofar as they're made distinct by use of my/our. Larry's proposal is to remove that difference for multimethods. Personally I can't think of a good objection to that idea (except if it may be bad for performance - is there a plan to infer types and auto-inline? I that case, declaring that you don't care about instance part of the object's functionality can really help). Miro
Re: Sane (less insane) pair semantics
[EMAIL PROTECTED] wrote: Stuart Cook skribis 2005-10-10 22:58 (+1100): @args = (a = 1, get_overrides()); foo([EMAIL PROTECTED]); Not if you want that a=1 to be a named argument. Under the proposal, the only ways to pass a named argument are: 1) By using a literal pair in the syntactic top-level of the arg list 2) By splatting a pair, hash, or arg-list-object I find this counterintuitive, and also want arrays to be included in option 2. How would you splat an array of pairs if you want to preserve the pairs? It is consistent with the idea that * expands its RHS and evaluate it as if it was written literally. I'd like @_ or @?ARGS or something like that to be a *-able array that will be guaranteed to be compatible with the current sub's signature. This sounds nice, though. Maybe it suggests that the 'named splat' should be something other than *? Miro
Re: Exceptuations
[EMAIL PROTECTED] wrote: I'm not bashing your idea, because I think it has uses. But I'll point out that all of these can be easily accompilshed by writing a wrapper for open(). That would be the usual way to abstract this kind of thing. My take on this: resumable exceptions break encapsulation no more (and no less) than using callbacks. The function that throws a resumable exception can only do this knowingly, and it could just as well offer a callback for that specific patchable error. So why take away a potentially highly useful tool? BTW, two languages I know of have resumable exceptions: Common LISP and TOM. Neither supports continuations, instead, they separate raising exception (which runs a handler; this is implemented as a callback) from unwinding stack (which happens when the handler actually throws; it can choose to return instead, resuming execution if the raising function is okay with it). At least in Common LISP this is used a *lot* during interactive development, as it allows the developer to quickly patch things up without reruning the failed test. Assuming perl6 keeps the pugs-style interactive shell, I suspect resumable exceptions will be quickly added into the standard library if they don't pass into the standard. Yes, they're that useful. Miro
Re: $value but lexically ...
[EMAIL PROTECTED] wrote: Would this work too? 0 but role {} Most certainly, but you would have no way to refer to that role later, so it is questionable how useful that construct is. No, it's not questionable. That is a useless construct. Luke Can an inline role be named? 0 but role is_default {} Miro
A listop, a block and a dot
Playing with pugs, I ran into this corner case: sub f($x) { say $x; } f {1}.(); # ok, outputs 1 sub f([EMAIL PROTECTED]) { say @_; } f {1}.(); # outputs block, tries to call a method from the return of say, dies Whitespace after f doesn't change the behaviour (in either case). Is this behaviour a bug in pugs? Should . bind stronger than non-parenthesised function call regardless of slurpy? Miro
Re: Look-ahead arguments in for loops
[EMAIL PROTECTED] wrote: And that was never quite resolved. The biggest itch was with operators that have no identity, and operators whose codomain is not the same as the domain (like , which takes numbers but returns bools). Anyway, that syntax was $sum = [+] @items; And the more general form was: $sum = reduce { $^a + $^b } @items; Yes, it is called reduce, because foldl is a miserable name. To pick some nits, reduce and fold are different concepts. By definition, reduce doesn't take the initial value, while fold does. So reduce using fold is something like @items || die horribly; foldl fn, @items[0], @items[1..] ... while fold using reduce is: reduce fn, ($initial, @items) I think both are useful, depending on the circumstances. Miro
Re: Do slurpy parameters auto-flatten arrays?
[EMAIL PROTECTED] wrote: So how *do* I pass an unflattened array to a function with a slurpy parameter? I don't ~~ @larry, but my guess(es) would be bar([EMAIL PROTECTED]) or bar([EMAIL PROTECTED]) Miro
Re: Syntax for specifying role parameters
[EMAIL PROTECTED] wrote: I don't think that a role has a long and a short name. This is because they aren't subject to MMD. I think of them more as beeing expanded like C++ templates even though the actual mechanism will be much more sophisticated. Actually I think of them as F-bounds as well ;) Uhm, but C++ templates are subject to (compile-time) MMD, once you specialise them. In other words, role Something[Int $num] {...} role Something[String $num] {...} could just as well work. :) Miro
A regression test
This is an addition to t/operators/hyper.t. It regression-checks for the bug discussed on #perl6 (in a nutshell, hyper ops used to only work on list literals, but not on array variables). { # regression test, ensure that hyper works on arrays my @r1; my @r2; my @e1 = (2, 4, 6); my @e2 = (2, 3, 4); my @a = (1, 2, 3); @r1 = @a + @a; @r2 = @a + 1; is([EMAIL PROTECTED], [EMAIL PROTECTED], hyper op works on variables, too.); is([EMAIL PROTECTED], [EMAIL PROTECTED], hyper op and correctly promotes scalars); };
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
[EMAIL PROTECTED] wrote: Er, isn't that not just the wrong way around? The point is to do the bookkeeping that an object is needed that does .meth() and that it is stored in $a, and to complain when that is not the case when it should be. The earlier the better. I don't understand why writing 'my X $a' needs at least a declaration of X, but then '$a.meth()' does not consider '.meth' as a bare method that needs a declaration in X? Because you can do sub infect(X $a is rw) { role bla { method meth() {...} } $a does bla; } my X $a; infect($a); a.meth(); Remember, you can even change the class of instanced objects using 'does' (or 'but', but it'll at least copy the object). And as the example above shows, this is statically intractable - it can happen in a sub in a different autoloaded module. Also, what do you want to do if you actually want $a.meth() to throw a catchable exception if $a doesn't implement meth? It's what many OO languages do. In fact, I can't recall a single OO language that isn't derived from C++ that does /not/ just throw a runtime exception on unknown method. Miro
Re: Perl 6 Summary for 2005-03-07 through 2005-03-22
[EMAIL PROTECTED] wrote: pugs too lazy Miroslav Silovic noticed that closing a file handle in pugs did not force all the thunks associated with the file. While this was a bug in pugs, it led to conversation about whether = should be lazy or eager. Larry thinks that it will be safer to start eager and become lazy then vice versa. http://xrl.us/fijd Accused of the original burst of insight, pleading not guilty! ;) The original post was to perl6-compiler by Andrew Savige. http://groups-beta.google.com/group/perl.perl6.compiler/browse_frm/thread/2aca524a1203cd41/912bea4d0d05554a?q=surprised#912bea4d0d05554a Miro
Re: [Pugs] Closing a file handle surprised the heck out of me
[EMAIL PROTECTED] wrote: On the other hand, we can alternatively specify that closing a file handle must force all thunks associated to it, i.e. in this case fill @lines with real data. Pugs can do that just fine, but I have no idea how parrot is to achieve that... But it gets worse. my $lines = [ =$fh ]; seek($fh, 0); my $lines2 = [ =$fh ]; close $fh; $lines2 must somehow remember that seek has happened. Miro
Re: for @list sub;
[EMAIL PROTECTED] wrote: for [EMAIL PROTECTED], [EMAIL PROTECTED], [EMAIL PROTECTED] - $x { say $x }; should work. Are there any non-slashy versions of this? I'd guess for @a; @b; @c - $x { say $x;} or for (@a; @b; @c) - $x { say $x;} (are parens mandatory here?) Miro
Re: MMD as an object.
[EMAIL PROTECTED] wrote: Ok. If you'd really need such random dispatch, it could be done like this, when I interpret A12 correctly: sub run_random_bar($x) { my @meths = WALKMETH($x, :method('bar')); my $meth = @meths[rand(@meths.elems)]; $meth($x); } or even with my sub bar($x) {...} # same body as above bar($x); This is enough to make me completely happy. :) Miro
Re: MMD as an object.
[EMAIL PROTECTED] wrote: It would behave like a tied sub (or method), with a .dispatch method to decide which of the contained routines should be called this particular time. Manhattan would be the default. However, one can override the dispatch logic; implementing Luke's Patterns idea, for example. Hmm, that ties into my wishlist item. Would it be possible to implement method combinators (or rather, multimethod combinators) from Common LISP in addition to this? The only CLOS feature that A12 doesn't mention, can't let that happen. ;) class A { ... } class B is A { ... } 1 multi foo ($a) is before { ... } 2 multi foo (B $a) { ... next METHOD; ...} 3 multi foo (A $a) { ... } 4 multi foo ($a) is after { ... } 5 multi foo ($a) is around { ... next METHOD; } 6 multi foo ($a) is before { ... } and this runs all 5 methods, in order 5 1 2 6 3 (returns to 2) 4 (returns to 5) And yes, 6 and 1 do have the same signature. The rule is to run all before methods in order of the currently selected distance (ties broken in random order ;) ), and all after methods in the reverse order. Oh, and the reason why around methods are useful? multi foo ($a) is around { CATCH { ... } next METHOD; } Note that this catches the exceptions thrown by any version of foo, even though at this point you don't know whether foo will be specialised. before methods aren't useful for this since their stack frame and handler blocks don't linger during the executions of other methods. Common LISP references: Standard method combination (before, after, around) http://www.lispworks.com/documentation/HyperSpec/Body/07_ffb.htm Other method combinations (+, and, etc) http://www.lispworks.com/documentation/HyperSpec/Body/07_ffd.htm Creating your own method combinations (define-method-combination) http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_4.htm Come to think of this, it seems that the only thing that'd need to be modified to accomodate both Rod's and mine proposal is to move CALLONE and CALLALL from the class to be MMD object somehow. Perhaps multi CALLONE ($obj, $method where { $_ == func }, [EMAIL PROTECTED]) { ... } Hmm, but this syntax strikes me as icky. Miro
Re: MMD as an object.
[EMAIL PROTECTED] wrote: What about multi subs? They can be defined everywhere. Given: multi sub *foo(A $a, B $b) {...} Is this something like: %globals{foo} -- MultiSub{foo_A_B = Sub, ...} What about a not so global multi: multi sub foo(A $a, B $b) {...} Thanks for clarifying, leo Uh, the real problem is the interaction between multisubs and modules. If you import a multi with the same short name from another module, you get a real issue that needs resolving. Especially if they do fundamentally different things and you don't expect a clash. Like module Users; multi get(Stream $f, UserDescriptor $u) {...} ... module FileTransfer; multi get(Server $s, File $f) {...} Even if this is easy to fix by renaming, the error message would take a while to track down and it'd be annoying distraction during development. I believe the DWIM thing to do would be to merge multis into the same MMD object on module load. This would have to happen during runtime, since that's when the module load can occur. Miro
Re: [rbw3@cse.nau.edu: Re: Junctive puzzles.]
[EMAIL PROTECTED] wrote: Yes... but perhaps instead of the above transform we should just make sure that is transitive in the first place... so that no matter what if ab and bc then ac. OTOH... perhaps we are working with partially ordered sets (rather than completely ordered sets)? In that case maybe the above suggestion is useful after all. Partial ordering relations are also transitive by definition. Of course, you can overload '' to be something other than ordering relation, but I'd invoke PEBKAC on that. :) Miro
Re: Junctive puzzles.
[EMAIL PROTECTED] wrote: What if junctions collapsed into junctions of the valid options under some circumstances, so my $x = any(1,2,3,4,5,6,7); if(is_prime($x) # $x = any(2,3,5,7) and is_even($x) # $x = any(2) and $x 2) # $x = any() This is Just Wrong, IMO. How confusing is it going to be to find that calling is_prime($x) modifies the value of $x despite it being a very simple test operation which appears to have no side effects? As far as I can see it, in the example, it's perfectly logical for is_prime($x), is_even($x) and $x 2 to all be true, because an any() junction was used. If an all() junction was used it would be quite a different matter of course, but I would see is_prime() called on an any() junction as returning true the moment it finds a value inside that junction which is prime. It doesn't need to change $x at all. In a way, you're sort of asking 'has $x got something that has the characteristics of a prime number?' and of course, $x has - several of them, in fact (but the count is not important). Well, yes, unexpected side-effects are not so great, however, in this case they're sequestered behind junctions. In fact, the other post suggested using implicit backtracking for this (something that can have a real problem with *expected* side-effects). If you just think of junctions as 'Just Works', side effects are implementation detail. To address your idea, problem is, you generally don't know whether you've been passed a junction (short of very specific type query), and writing code without being able to rely on the fact that (is_prime($x) !!is_prime($x)) == false is Just Plain Evil. For example, something as simple as if (is_prime($x)) { ... } else { ... } may be buggy if $x is a junction. To make it work correctly, you will want to write if (is_prime($x)) { ... } if (!is_prime($x)) { ... } Evil, no? :) Miro
Re: Perl 6 Summary for 2005-01-31 through 2004-02-8
[EMAIL PROTECTED] wrote: i think so but i can't read larry's mind (nor would i want to! :) XP = extreme programming DBC = design by contract (or even designed by conway :) MP = ?? Modular Programming David I think it's Metaprogramming. :) Miro
Re: Junctive puzzles.
[EMAIL PROTECTED] wrote: Yup. My mathematic intuition cannot suffer that: 4 X 2 to be true in any circumstances -- as it violates associativity. If one wants to violate associativity, one should presumably *not* use the chained comparison notation! So Pugs will evaluate that to (#f|#f), by lifting all junctions out of a multiway comparison, and treat the comparison itself as a single variadic operator that is evaluated as a chain individually. I think this is correct, however... this is not what I meat in my comment. Note I didn't use chained comparison anywhere. What I meant is that for any form with two parameters (in the example, 4 ___ and ___ 2), aparently it's not the same whether the two parameters refer to the same junction or to two equal (but distinct) junctions. Miro
Re: Junctive puzzles.
[EMAIL PROTECTED] wrote: Well, we see the same kind of thing with standard interval arithmetic: (-1, 1) * (-1, 1) = (-1, 1) (-1, 1) ** 2 = [0, 1) The reason that junctions behave this way is because they don't collapse. You'll note the same semantics don't arise in Quantum::Entanglement (when you set the try to be true option). But you can force a collapse like this: my $x = 4 $j; if $j 2 { say never executed } By which I mean: my $x = 4 $j; if $x 2 { say never executed } Uh, I'm not sure this does what I think you wanted to say it does. ;) $x is a boolean, unless returns a magical object... in which case, the magical part of $x ought to be a reference to the original $j, no? I'm wonding if we should allow a method that returns a junction that is allowed to collapse the original: if 4 $j.collapse and $j.collapse 2 { say never executed; } But that's probably not a good idea, just by looking at the implementation complexity of Quantum::Entanglement. People will just have to learn that junctions don't obey ordering laws. Well, I suspect that junctions will have to be references and just collapse every time. Observe: my $x = any(1, 2, 3, 4, 5); print SHOULD NOT RUN if (is_prime($x) is_even($x) $x 2); This only works if $x collapses. Same for matching junctioned strings: my $a = any (a b c); print Boo! if $a ~ /a/ and $a ~ /b/ and $a ~ /c/; (perhaps I meant to use ~~, I don't quite remember :) ) Either way, autocollapsing juntions is a Good Thing IMHO, and the only remaining confusion (to go back to my initial post) is that the only case that doesn't work is when you instance a junction twice as a pair of same literals: print SUCCESS, unfortunately if (is_prime(any(1, 2, 3, 4, 5)) is_even(any(1, 2, 3, 4, 5)) any(1, 2, 3, 4, 5) 2); Hope I'm making sense. Been a hard day at work. ;) Miro
Re: Junctive puzzles.
[EMAIL PROTECTED] wrote: pugs ? 4 (0 | 6) 2 (#t|#f) Here's my take on it. Compare my $a = (0 | 6); say 4 $a and $a 2; vs say 4 (0 | 6) and (0 | 6) 2; The difference is that in the first case the junction refers to the same object, and the result should probably be expanded only once: (4 0 and 0 2) | (4 6 and 6 2) while in the second case, we have two different junctions, and each gets threaded separately: (4 0 and 0 2) | (4 6 and 6 2) | (4 0 and 6 2) | (4 6 and 0 2) The first expansion gives the correct result, while the other is really a variant on what you have. And I believe this becomes highly dangerous if you start assigning junctions around. :) Miro
Re: Retry: ITypes and VTypes.
[EMAIL PROTECTED] wrote: However, I wonder how to talk about an array that can contain elements of any value type, but all the elements must have the same type. Is Perl6 capable of expressing such a restraint? Thanks, /Autrijus/ The problem (in general) with this requirement is that it conflicts with inhericance. Perl6 allows you to extend any type (using 'but' operator, for example) and so, any time you promise that something will be of a certain type, the type's children will be allowed. That's at least the way I read A12. I also think that juntions will have their elements' type's interface and so they can also pose for any type. In other words, you need a real polymorphic object system in Haskell for this to work. Fortunately there's one handily described at http://homepages.cwi.nl/~ralf/OOHaskell/ While we're on the topic, which of the following are true? 3 but three ~ int (false?) 3 but three ~ Integer (true?) 3 5 ~ int (true?) 3 5 ~ Integer (true?) (Skipping off topic, to Parrot. Sorry. :) ) If 3 5 is actually int, and this is only determinable at runtime, to me this seems like a problem with I# register allocation - ints can't be reliably assigned to I# registers. Unless, of course, you autothread at the point when a junction has to be cast into an int. Do I understand junction semantics correctly? Miro
Re: continuation enhanced arcs
[EMAIL PROTECTED] wrote: What this means is that care must be taken when you are writing code that you expects to be invoked multiple times. However, if you are a function that on your second invocation returns via the continuation from you first invocation, you should probably expect to be called again because it happened the first time! The contentious point is precisely that there is no way to tell at the compile time that you will be invoked multiple times. If something you pull from a library or a callback passed to you captures the continuation, you may notice that your return continuation had been promoted, but at that point it's already too late to kill all I/N/S register usage and to double-reference all PMCs. Of course, unless you keep the original AST and keep recompiling it to PIR. I'd argue that it's vastly more complex and error prone than Leo's solution he refered to in his post. It's also no better than refetching all lexicals. Also, note that return-continuation-restores semantics is simply a (possibly premature) optimisation in its own right. CPS is supposed to treat every continuation the same (which turned out to be inefficient), and then return continuations were added to simplify the most common case. So, while return continuation is unpromoted, it's perfectly okay for it to behave any way it wants. Once it does get promoted, I'd argue that it should behave like a normal continuation first because it's more practical (see above) and second because that way it doesn't break CPS semantics. Miro
Re: Exceptions, sub cleanup, and scope exit
Dan Sugalski wrote: It's also important for people writing these things to take into account the possibility that their exit actions may potentially be triggered multiple times, courtesy of the joys of continuations. Hmm, the first thing to take into the account is that return continuations can be promoted to the fully blown continuations. This should affect the handlers in the same way - so exception handlers could have become arbitrary invokable objects at the point when the exception is thrown. Miro
Re: Exceptions, sub cleanup, and scope exit
Dan Sugalski wrote: Hmm, the first thing to take into the account is that return continuations can be promoted to the fully blown continuations. This should affect the handlers in the same way - so exception handlers could have become arbitrary invokable objects at the point when the exception is thrown. I'd rather not, if we can avoid it. Assumptions on control flow and such are likely to be very different, and I can't think of a good reason to treat an error handler as a normal sub. (If you have one then we can think on it some) While that's not what I commented on, sure. Common LISP and TOM both invoke error handler -before- unwinding the stack (then the handler explicitely unwinds if it can't recover). I still don't think it's something Parrot should care about, as their (hypothetical) compilers can install their own error handling, and other languages don't expect their own throw to ever return - so I wouldn't call this a good reason. :) Miro
Re: calling conventions, tracebacks, and register allocator
[EMAIL PROTECTED] wrote: On Nov 8, 2004, at 11:15 AM, Matt Fowles wrote: Dan~ On Mon, 8 Nov 2004 13:45:08 -0500, Dan Sugalski [EMAIL PROTECTED] wrote: The calling conventions and code surrounding them will *not* change now. When all the sub stuff, and the things that depend on it, are fully specified and implemented... *then* we can consider changes. Until then, things stand the way they are. I missunderstood. I though you were saying that what is currently in is final and will *never* be changed. Thanks for the clarification. Nevertheless, this is a legitimate topic for discussion, and the issues are fresh in people's minds. That's independent of any impediments that might block implementing changes at the current time. I think it'd be a good idea to at least agree on a good TODO list, and commit that to the bugtracker. Because it may turn out that some changes are fine to delay, while some must be implemented now or never (because, for example, a large ammount of compiler code will get broken because of them). Miro
Re: Why is the fib benchmark still slow - part 1
[EMAIL PROTECTED] wrote: a) accessing a new register frame and context b) during DOD/GC We have to address both areas to get rid of the majority of cache misses. ad a) For each level of recursion, we are allocating a new context structure and a new register frame. Half of these is coming from the recently implemented return continuation and register frame chaches. The other half has to be freshly allocated. We get exactly for every second function call L2 cache misses for both the context and the register structure. Or it would make sense to use multi-frame register chunks. I kept locality of access in mind but somehow never spelled it out. But I *think* I mentioned 64kb as a good chunk size precisely because it fits well into the CPU cache - without ever specifying this as the reason. Anyway, if you can pop both register frames -and- context structures, you won't run GC too often, and everything will nicely fit into the cache. Is the context structure a PMC now (and does it have to be, if the code doesn't specifically request access to it?) ad b) The (currently broken) Parrot setting ARENA_DOD_FLAGS shows one possibility to reduce cache misses in DOD. During a sweep (which runs through all allocated object memory) the memory itself isn't touched, just a nibble per object is used, which holds the relevant information like is_live. Is there a way to find out how many misses came out from DoD, compared to register frames allocation? I believe that you shouldn't litter (i.e. create an immediately GCable object) on each function call - at least not without generational collector specifically optimised to work with this. This would entail the first generation that fits into the CPU cache and copying out live objects from it. And this means copying GC for Parrot, something that (IMHO) would be highly nontrivial to retrofit. Miro
Re: Why is the fib benchmark still slow - part 1
Leopold Toetsch wrote: I believe that you shouldn't litter (i.e. create an immediately GCable object) on each function call - at least not without generational collector specifically optimised to work with this. The problem isn't the object creation per se, but the sweep through the *whole object memory* to detect dead objects. It's of course true, that we don't need the return continuation PMC for the fib benchmark. Well, creation is also the problem if you crawl the entire free heap before triggering the next GC round. You get a potential cache miss on each creation and on each mark and on each destruction. To keep GC out of the way, the entire arena has to be confined to cache size or less. But a HLL translated fib would use Integer PMCs for calculations. Hmm, I'm nitpicking here, but it's not how e.g. Psyco works. It specialises each function to specific argument types and recompiles for each new argument type set. Assuming that you'll call only very few functions with more than 1-2 type combinations, this is a good tradeoff. It also removes a lot of consing, especially for arithmetics. ... This would entail the first generation that fits into the CPU cache and copying out live objects from it. And this means copying GC for Parrot, something that (IMHO) would be highly nontrivial to retrofit. A copying GC isn't really hard to implement. And it has the additional benefit of providing better cache locality. Nontrivial to retrofit or not, we need a generational GC. Copying and generational are orthogonal concepts. It's quite possible to have noncopying gengc (and nongenerational copying GC, but that's beside the point). This gives you quick mark phases but without so much gain with locality (I think Boehm GC can do this). The problem with copying GC is that pointers can change under your feet at every opportunity. Embedded C libraries that try to manipulate GCed objects really hate when that happens - in particular where some pointers get cached in the CPU registers - and telling GC to (un)protect a pointer is a chore on C programmers (as bad as manual refcounting). I suppose that there are good solutions to this, I'm just not aware of any. The gain is that you can guarantee that the youngest generation will be no bigger than X kb. This can be very good thing. However, for the problem at hand - namely, littering during function calls, custom deallocator (that'd be chunks) could be enough. In particular, it makes sense to use it in conjunction with a non-copying gengc. Miro
Re: [Summary] Register stacks again
[EMAIL PROTECTED] wrote: Could we have the chunks only hold one frame and avoid much of the compaction work? If we return to the inderict access mechanism, we can switch register frames by changing one pointer. But if we keep the one frame per chunk, we do not need to compact frames, standard DOD/GC will be able to reclaim frames. I recall there being efficiency issues with frames being frequently allocated/deallocated too frequently, so we could have a special free list for frames. This proposal feels to me like a slightly simpler version of yours. Thus I would argue for it on the grounds of do the simple thing first and compare its efficiency. Well, for the code that doesn't do call/cc, bigger chunks mean that that you can use them as a classical stack. So you won't ever have to allocate them, and never have to run the compaction. For call/cc, you still don't have to compact them as often, since the non-captured continuations will get popped normally, and the watermark lowering will take care of temporarily captured continuations (between two GC's). Basically bigger chunks mean that frames are allocated using the special scheme just for them. Considering that you're going to allocate one on each function call, I would agree with LT that the complexity is justified (and is not too bad - the way I understand the Parrot internals, which is to say, not too well ;), arrays of PMC pointers already get copy-collected; stack frame chunks are not too different from these). Miro
[Summary] Register stacks again
This is a summary of a private mail conversation between Leo and myself. lieNo, it didn't start by me forgetting to fix Reply-To when trying to post follow-up on the list./lie ;) Essentially we whipped up a GC scheme for collecting the register stacks that doesn't make call/cc-using code, well, unusably slow. In addition to LT's original post on the register stack, here's how to allocate them and clean up after their use. LT, feel free to hit me with wet noodles if I forgot anything. Terminology: --- Register frame is an actual frame of 4x16 registers. Register chunk is a flat chunk of memory containing multiple register frames. It has a water mark that points where a new frame should be pushed into the chunk. I'm using stack and chunk interchangably. Frames are subject to DoD, and chunks are subject to GC. There are plenty of tricks that can prevent GC from happening in many cases (read on for details). DoD is necessary anyway (to retrieve the live PMCs pointed from the register frames). A chunk is pinned if GC currently can't copy it over and kill it (read on for details). Allocation: --- Register stacks should be allocated in fairly big chunks. However, since there must be at least one active chunk per thread (and per coroutine), choosing anything actually huge will pose a scaling problem. Frames are allocated from the current stack, simply by advancing the water mark of the currently active chunk. If this causes the water mark to overflow, a new chunk needs to be allocated. Note that if a continuation has been captured and then invoked, the water mark will not necessarily point at the end of the current frame (since the invoked continuation may keep its registers deeper in the chunk) Deallocation: --- The stack frame can only be popped if the current continuation hasn't been captured (from the frame being popped). Here, pop means changing both frame pointer and the watermark. This ammounts to adding a flag to the current frame and bumping the flag if the return continuation gets moved into any directly accessible location. If the frame can't be popped, only the frame pointer should be changed to the caller's. GC: --- During DoD, the register frames should be marked (as parts of their chunks). Then the dead frames get dealt with in the following manner: Remove the trailing dead frames from each chunk (by just lowering the water mark). If after this the water mark remains high (e.g. past 50% of the chunk) but more than certain ammount of the chunk is salvagable as dead frames (50% seems like a good number again), the chunk should be copied, all the frame pointers fixed up, then the chunk gets killed. Essentially the chunks are treated as buffers. The watermark lowering won't help in cases when continuations get invoked in a round-robin manner (wish I could think of some simple Scheme example here that behaves this way), and start littering the chunk with interlaced dead frames. Two caveats: The frame pointer of the currently active frames (can be more than 1 due to threads) may be kept in a CPU register and can't be fixed-up. So the chunk containing currently active frame is pinned until it either overflows into another chunk or gets freed by popping. Chunks can contain reverse pointers to the continuations that use its frames. When copying the frame, just go through these reverse pointers and fix the continuations they point to. Performance: --- This scheme requires some GC flags to each frame (as well as reverse pointers). Possibly also next pointers to the frames, if they are not cut to equal size. Without continuations, this behaves like C function calling. Nothing will read return continuation and so the frames will simply get popped from the stack on return. When continuations begin to prevent popping, the stack will start growing from the last captured continuation (even if its dead). Watermark will drop in GC if the GC happens to hit while the active frame is way down the stack (i.e. just between two function calls). Otherwise, GC will wait till the chunk overflows (so that the active frame is in a higher chunk) and then will copy the live frames to a newly allocated chunk, compacting several chunks together if possible. Copying can be skipped if the chunk is near-full of the live frames. I think this about sums it up. Comments, corrections, wet noodles? Miro
Re: S5 updated
[EMAIL PROTECTED] wrote: I'll show you. Here are some of the generators. This is very dense, functional code. Read at your own risk (but I'm certainly not writing it to be executed!). Quite. ;) For the regexp /a aa aaa a aa/, this would sequentially search through all possible ways to decompose 21 until it hit 1+2+3+4+5+6; then it'd return ax21 as the single result. This... might take a while. Since programming in Theoretic Perl6 (Terl6?) /is/ fun, here's my take: # compositions2($length, @listoflists) gives all possible ways to depompose # $length into the sum of the form a1+a2+a3+...+an so that a[i] is contained # in @listoflists[i] multi generate(Rule::Group $group: Int $length) { # For each assignent of lengths to each of $groups children # such that they sum to $length... compositions2($length, map(possible_lengths, $group.children)) == map - @comp { @comp $group.children == map - $n, $pat { # Generate every string of length $n that the subpattern # matches [ $pat.generate($n) ] } == # Join our results together outer == join '' } } use IntegerIntervalArithmetics add_lists, mult_lists ; # add_lists(@list1, @list2) returns the list of sums of all possible # elements of the lists. However, it should take .. and ... operators # into account. This generally requires range tree datastructure of some # sort. # mult_lists(@list1, @list2) returns the list of all products multi possible_lengths(Rule::Group $group) { [ reduce(add_lists, map(possible_lengths, $group.children)) ]; } multi possible_lengths(Rule::Plus $plus) { [ mult_lists($plus.expression, 1... ]; } multi possible_lengths(Rule::Constant $const) { [ length($const.chars) ]; } I'm still not claiming that this is something one should use, but it /was/ fun to tinker with. :) Miro
Re: S5 updated
On Tue, 2004-09-21 at 02:52 -0600, Luke Palmer wrote: If you replace the first line: method Rule::Group::generate(Int $n) { With multi generate (Rule::Group $group: Int $n) { Everything ought still to work. I think the best you can do is to implement it as a routine. You can't really make it a modifier, because it's pretty separate from actually matching anything. Minor nitpick, you can do away with the integer parameter - to me it makes more sense to just lazily spew an infinite list of generated matches. Then you'd do @results = generate(/a*/) [0..999]; to get 1000 results, but you can also do @results = generate(/a*/); while !$hell.frozen() { shift @results; } Miro
Re: S5: grammar compositions
On Wed, 2004-09-15 at 12:47 -0700, [EMAIL PROTECTED] wrote: Grammar roles? Larry Hmm, actually a few questions on the topic: S5 doesn't specify whether grammars can have attributes. Can they? Can they have methods, or at least local subs, to call from the code within the rules? Can grammars inherit from classes/roles (to pull methods into their namespace, for code within the rules)? Can classes inherit from grammars? (to pull their rules into their namespace) Miro