Re: scalar/array contexts in perl5 vs. perl6

2005-12-04 Thread Sam Vilain
On Sun, 2005-12-04 at 13:10 -0500, Mike Li wrote:
> what is a good translation of the following C into perl6?
> 
 [...]
>int x = 0; int y[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; y[x++]++; /* line
> that matters */
 [...]
> 
> 
> in perl5, i would've written something like:
> 
> my $x = 0; my @y = 1..9; @y[$x++]++; print "$x\n"; print "@y\n"
> 

Note that when you run this in perl 5:

$ perl -we 'my $x = 0; my @y = 1..9; @y[$x++]++; print "$x\n";
print "@y\n"'
Scalar value @y[$x++] better written as $y[$x++] at -e line 1.
1
2 2 3 4 5 6 7 8 9

You've already used a Perl6-ism!

> but in perl6, the '@' sigil always means list context, so should i
> write the following?
> 
> 
> my $x = 0; my @y = 1..9; [EMAIL PROTECTED]; print "$x\n"; print "@y\n"
> 

I'm not sure what you're trying to do with all those derefs, but the
only change you need to make to your original code is to put the @y
interpolation inside a block;

{ my $x = 0; my @y = 1..9; @y[$x++]++; print "$x\n"; print "{ @y }\n" }

Try downloading and installing pugs; it's great for trying out this sort
of thing!

Sam.



Re: Some thoughts on threading

2005-12-11 Thread Sam Vilain
On Thu, 2005-12-08 at 17:16 +0100, Ron Blaschke wrote:
> The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software."
> [1] He starts with "The biggest sea change in software development since
> the OO revolution is knocking at the door, and its name is Concurrency."

Perhaps have a read of:

http://svn.openfoundry.org/pugs/docs/AES/S17draft.pod

Two non-traditional methods of concurrency are discussed;

  * atomic blocks - an atomic { } guard around a block that, assuming
the block performs no I/O, will guarantee atomic
success or failure of the block.

  * co-routines - essentially co-operative multitasking between
  'blocking' threads that actually switch tasks when
  they block (or yield).

There is also some stuff there on other types of timesharing and
multiprocessing - Threads, Processes and Multiplexing (like Ruby).

Sam.



Re: handling undef - second draft

2005-12-18 Thread Sam Vilain
On Sat, 2005-12-17 at 17:27 -0800, Darren Duncan wrote:
> 3. A flag that says we know that some operation failed, such as would 
> be exploited in the " err " 
> situations.
> This concept is like an exception which isn't thrown but returned.

"Dropping" an exception, perhaps?  :)

> 1. I accept the proposal that we just make another class that 
> implements the SQL concept of a null value, perhaps named Null or 
> SQL::Null, rather than having this behaviour in the core language, so 
> that should simplify the rest of the discussion.  If someone wants 
> undefs to propagate through expressions like SQL's NULLs do, rather 
> than failing or defaulting, then this can be done with the new class. 
> A Null object would be defined but false.  It would overload standard 
> operators so that most expressions involving it would propagate a 
> Null object, or compare unequally as desired.  Therefore, this sort 
> of behaviour will be isolated and standard data types won't behave 
> this way by default.

I think this is out of scope; if a module chooses to use "undef" as a
well defined part of its interface, that's its call.

> 2. Modify the 'Exceptions' section of S04 so that built-in functions 
> return a 'error' or 'failure' or 'exception' if they fail, instead of 
> an "interesting value of undef".  The behaviour and handling of or 
> response to these is essentially unchanged, but the value is called 
> something more distinctive and it is not called 'undef'.  Instead of 
> testing for .defined(), invoke a different method like .failed() or 
> .error() instead; invoking .defined() on an error should perhaps 
> return true instead of false.  Perhaps update err() to activate on 
> the error rather than or in addition to undef.

I'm not sure what this adds.  You ask for a system call, you don't get a
result.  In other words, the result is undefined, and it has a
supplemental error.

It just seems a bit silly to make the "err" operator have to call *two*
methods in sequence, it would be a hack just for system calls.

Besides, aren't all these values just "undef but { .error = '...' }"
etc?

> 3. Have the functionality of 'use fatal' turned on by default in 
> large programs, though not one-liners, and it can be turned off 
> otherwise.  It is safer to have them brought to your attention where 
> you make a conscious effort to respond to or dismiss them.
>
> 4. An expression or statement having an 'err' would impose a 
> try-block around the expression it is attached to, so the right thing 
> still happens when errors are thrown by default.  And 'err' is a 
> conscious effort to deal.
>
> 5. Autovivification in larger programs should not happen by default, 
> unless you have something like 'use autovivify;'.  But with 
> one-liners it would work by default.
>
> 6. Attempts to use undef where a defined value is expected, such as 
> wherever they currently generate warnings, should be upgraded to a 
> stricture and fail by default in larger programs.  But like with 
> other strictures, this would be turned off by default in one-liners. 
> If the DWIM behaviour is wanted in larger programs, one can say 'no 
> strict undefs;' or such.

I think we need to be very careful not to impose too many good practice
measures on the developer.  All of the situations you describe (except
perhaps autovivification) can potentially be picked up by the compiler,
and warnings generated.

> There may be remaining holes in my suggestions, but hopefully I dealt 
> with the worst ones from the preceeding first draft.

FWIW, I didn't read the first thread.

Sam.



Re: Obsoleting "require 'Some/Module.pm'"

2005-12-19 Thread Sam Vilain
On Mon, 2005-12-19 at 14:58 +0200, Gaal Yahas wrote:
> Can we make this work?
> 
>  my $mod = "Some::Module";
>  require $mod;

What about casting it to a package;

  require ::{$mod};

(not sure if the syntax is quite right)

Sam.



Re: Another dotty idea

2006-04-10 Thread Sam Vilain
Damian Conway wrote:

>I'm not enamoured of the .# I must confess. Nor of the #. either. I wonder 
>whether we need the dot at all. Or, indeed, the full power of arbitrary 
>delimiters after the octothorpe.
>  
>

Agreed.

>What if we restricted the delimiters to the five types of balanced brackets? 
>And then simply said that, when any comment specifier (i.e. any octothorpe) is 
>followed immediately by an opening bracket, the comment extends to the 
>corresponding closing bracket?
>
>Then you could have:
>
>   #[ This is a comment ]
>   #( This is a comment )
>   #{ This is a comment }
>   #< This is a comment >
>   #« This is a comment »
>  
>

This does mean that if you comment out blocks with s/^/#/, you mess up on:

#sub foo
#{
#  if foo { }
#}


>That would also mean that # is *always* the comment introducer
>(and the *only* comment introducer).
>  
>

I agree with this goal.

I propose this form: #*   *#

As a leading * on a line is unusual, and it also has visual similarity
to multi-line comments in C.

>As for gappy dotting, that would become:
>
>   $x#[  ].foo()
>  or:
>
> $x.#<  >foo()
>  
>

For comparison:

$x#*  *#.foo()
  or:

$x.#*  *#foo()





Re: Another dotty idea

2006-04-10 Thread Sam Vilain
Larry Wall wrote:

>On Tue, Apr 11, 2006 at 12:26:13PM +1200, Sam Vilain wrote:
>: This does mean that if you comment out blocks with s/^/#/, you mess up on:
>: 
>: #sub foo
>: #{
>: #  if foo { }
>: #}
>
>Well, actually, that still works.  
>  
>

Oh, true :-)

But this fragment dies:

 #sub foo
 #{
 #  bar { } unless baz
 #}


Unless you consider the idea of balancing the {}'s inside the comment,
which I think would be just plain nasty.

The #* .. *# form actually has a natural follow-on I didn't think of before:

#[ This is a comment ]#
#( This is a comment )#
#{ This is a comment }#
#< This is a comment >#
#« This is a comment »#

While technically the same thing applies to code that uses these delimited, it 
means that the block I gave is now a parsefail.  #-comments directly following 
closing braces are probably sufficiently uncommon for this not to be such a 
problem.

>To be certain though, you could always
>use s/^/##/ or s/^/# /.  
>  
>

I guess that works, but it breaks convention of # somewhat.

>Even better is:
>
>=begin UNUSED
>sub foo
>{
>  if foo { }
>}
>=end UNUSED
>
>And I don't really care if that's not what people are used to.
>The whole point of Perl 6 is to change How Things Work.
>  
>

Sure, but there is still the principle of least surprise to worry about.

Sam.



Re: Another dotty idea

2006-04-10 Thread Sam Vilain
Larry Wall wrote:

>: But this fragment dies:
>: 
>:  #sub foo
>:  #{
>:  #  bar { } unless baz
>:  #}
>I don't see how that's different at all from the first example.
>  
>

“#sub foo” is parsed as a comment token
“#{
# bar { }” is the next comment token

then we get “unless baz”

Unless you are balancing {}'s inside the # blocks, like q{ } does.

Sam.


Re: using the newer collection types

2006-05-04 Thread Sam Vilain
Darren Duncan wrote:

>Speaking a little more technically, a Relation has 2 main components, 
>its heading and its body.  The heading is a set of 0..N keys (called 
>"attributes" in relation-land), and the body is a set of 0..N 
>Mappings (called "tuples" in relation-land), where they set of keys 
>of each Mapping is identical to the Relation's heading.  Its very 
>likely that a language-embedded Relation implementation would 
>actually not repeat the keys for each member Mapping, but we can 
>conceptualize as if they were present for simplicity.
>  
>

I don't think this terminology or these restrictions are particularly
useful.

I do think that a Pair should be a sub-type of a more general "Tuple"
type, with the 'where' clause being { .items == 2 } or something like that.

I think that the most flexible arrangement is to define;

- a Collection as a Bag of Tuples
- a Relation as a Collection where the tuples have a shape and no
duplicate tuples are allowed (but Relation does not need to be a core type)

Then, Mappings, Sequences, etc, become sub-types of one of the above two
types. For instance, a sequence is a Collection of (Int, Any) where the
first Int is unique across the collection. Similarly a Mapping is a
Collection of (Any, Any) where Unique(0).

something like

role Tuple { has @.items };
role Collection { has Tuple @.tuples };
subset Pair of Tuple where { .items.items == 2 };
subset Bag of Collection where { ! .tuples.grep:{.items > 1 } }
subset Set of Bag where {
all( .tuples.map:{ .items } ) == one( .tuples.map:{ .items } )
}
subset Mapping of Collection where { ! .tuples.grep:{ .items != 2 } }
subset Array of Mapping where { .tuples.grep:{ .items[0].isa(Int) } }
subset Hash of Mapping where { .tuples.grep:{ .items[0].does(Str) } }

The above should probably all be written in terms of parametric roles
(see S12), but for now the above run-time checking versions should
hopefully express the relationships between the core collection-like
types as I see them.

That sounds like it might bite, but you wouldn't normally access an
Array as a Collection of (Int, Any), you'd access it as an Array, so you
get the nice .post_circumfix:<[ ]> method that makes array access easy.
You don't care that it has this higher order type as a parent class, and
you certainly wouldn't care for the 'bare' Collection interface (as for
one, you don't want to have to deal with the Integer keys). And it is
probably all backed by native methods.

I'm prototyping much of this using Moose in Perl 5, however Hubris is
delaying its release :-)

>Moreover, the Relation type has these 
>operators that the Set type doesn't have: rename(), project(), 
>restrict(), extend(), join(), divide(), summarize(), group(), 
>ungroup(), wrap(), unwrap(), matching(), etc.
>

Is there a reference for the meaning of these methods?

>1.  Are Sets or Junctions allowed to contain undefined elements?  Can 
>undef be a key of a Mapping or Hash?
>  
>

undef.isa(Object), so you should be able to use it as you would any
other object. I would definitely not think of it as the absence of a
value in this context.

>2.  What actually is the practical distinction between a Set and a 
>Junction?  Why would someone use one over the other?  I recognize 
>that the use of Junctions is supposed to make parallelism easier, as 
>iterating through one is known to be order independent.  But, 
>conceptually a Set and a Relation are exactly the same;  you could 
>process their members in any order and/or in parallel as well.  So is 
>the use of a Junction effectively like a compiler flag to make 
>certain kinds of Set ops faster at the expense of others?
>  
>

Well one side effect at the moment is that Junctions are immutable,
whilst Sets are mutable. This is perhaps a deficiency in my original
Set.pm design; all of the mutating functions should be in a seperate
role, really (or just not be mutators).

>6.  Can I declare with named Set (or Junction) and Mapping typed 
>variables and/or parameters that their members are restricted to 
>particular types, such as Str, as I can with Arrays and Hashes, so 
>that Perl itself will catch violations?  Eg, can I say as a parameter 
>"Set of Str :$heading?" or "Set of Mapping(Str) of Any :$body?" so 
>Perl will check that arguments are suchwise correct?
>  
>

These are variously called "Generics" (ada I think, Java 1.5+),
"Parametric Types", "Higher Order Types" (Pierce et al), "Generic
Algebraic Data Types" (Haskell)

In Perl 6 they are parametric roles (as in S12 mentioned above)

>7.  Can we add some operators to Mapping that are like the Relation 
>ones, so that implementing a Relation over Mappings is easier (or, 
>see the end of #8)?  Eg, these would be useful: rename(), project(), 
>extend(), join().  In particular, implementing join() into Mapping 
>would help save CPU cycles:
>  
>

Again, a reference to a prototype of the behaviour would be useful.

Sam.


Re: using the newer collection types

2006-05-05 Thread Sam Vilain
Darren Duncan wrote:

>>>Is there a reference for the meaning of these methods?
>>>  
>>>
>>There are many written references to these methods; just type 
>>"relational algebra" into Google.
>>
>>
>
>I will add that the first hit on such a search, the Wikipedia page on 
>relational algebra ( http://en.wikipedia.org/wiki/Relational_algebra 
>), is a perfectly good primer on what relational algebra is and what 
>its importance is.
>  
>

Thanks for the pointer.

>While this may not actually change anything, I should point out that 
>every collection type can also be expressed in terms of a Relation 
>definition and/or they can all be implemented over a Relation (whose 
>members are actually always unique).  For example:
>
>1. A Set of Any is a Relation with one Any attribute.
>2. A Bag of N Any attributes is a Relation of N+1 attributes, where 
>the extra attribute is an Int (constrained >= 1) that counts 
>occurrances of the distinct other attributes.
>3. A Mapping can be a Relation of 2 Any attributes.
>4. A Hash is a Relation of 2 attributes, Str (key) and Any (value), 
>where the key has a unique constraint.
>5. A Seq is a Relation of 2 attributes, typed Int (>= 0) and Any, 
>where the first shows their ordinal position and the second is the 
>actual value; the first has a unique constraint.
>6. An Array is the same, assuming it is a sparse; if it is not 
>sparse, there is an additional constraint that the greatest Int value 
>is the same / one less than the count of Relation members.
>  
>

I don't know if anyone will care, but you can't emulate the raw
"Collection" type with this fixed Relation type. That is, a collection
of tuples, each of which may be of differing length and type.

This is what leads me to think that Collection is the more generic role.
I'm not saying Relations are not useful, perhaps they are more useful
than Collections in the practical case, but they are a sub-type.

Also, I don't agree with the notion of a "header" of each relation. It
has a type for each tuple item, sure, but "header" just sounds like the
sort of thing you want in a ResultSet, not a Relation.

Sam.


Re: using the newer collection types

2006-05-07 Thread Sam Vilain
Darren Duncan wrote:

>>Also, I don't agree with the notion of a "header" of each relation. It
>>has a type for each tuple item, sure, but "header" just sounds like the
>>sort of thing you want in a ResultSet, not a Relation.
>>Sam.
>>
>>
>A relation's heading is essentially the definition of the relation's 
>structure, and is not redundant if the relation has no tuples in it, 
>which is valid.
>  
>

The Relation has a type, which is a Relation of Tuples of something. The
"Header" you refer to is the higher order part of the Tuple, the
"something".

Sam.


Re: ACID transactions for in-memory data structures

2006-05-17 Thread Sam Vilain
Rob Kinyon wrote:

>On 5/15/06, Audrey Tang <[EMAIL PROTECTED]> wrote:
>  
>
>>Rob Kinyon wrote:
>>
>>
>>>I'm pretty sure it wouldn't be very feasible to do this natively in
>>>P5. But, would it be possible to do it natively in P6? As in,
>>>supported within the interpreter vs. through some sort of overloading.
>>>  
>>>
>>Look at "is atomic" in S17draft, and Software Transaction Memory in general?
>>
>>
>
>Would there be a way for me to say "Yes, I understand that Perl may
>not generically understand how to revert this outside resource, such
>as a database, but I do." and do a catch-type block for the revert?
>  
>

There was discussion about this on one of the dbi2 lists at some point. 
I think a minimal API was even fleshed out - but it probably died there
and would love someone to pick it up.

Sam.


Re: packages vs. classes

2006-05-22 Thread Sam Vilain
Larry Wall wrote:

>'Course, I left out everything about prototype objects there...
>
>The name Foo also (in context) represents an uninitialized object of
>the class in question.  Any object, initialized or not, can get at
>its type handlers by saying
>
>Foo.meta
>$foo.meta
>
>and, in fact, the Foo.^bar syntax is just short for Foo.meta.bar.
>  
>

Perhaps saying it is like:

Foo.meta.get_attribute("bar")

Would be safer. Don't want to stomp on the meta-objects.

>[...]
>of the actual magic being defined elsewhere.  It would be possible
>to access classes et al. only via the mechanisms supplied by the
>metaobject protocols, but that would be kind of like the bad old
>[...]
>  
>

Right, but we should really ship with at least a set of Meta Object
Protocol Roles, that covers the core requirements that we will need for
expressing the core types in terms of themselves;

- classes and roles
- attributes and methods
- subsets (ie constraints/subtypes)
- generics (including, by induction, nested generics)

I *think*, at this point, that's all that are necessary. They are
actually quite a useful set for the concerns I raised earlier about
automatically inferring relational information from the metamodel (if
only I knew these terms back then... ;))
http://groups.google.com/groups?threadm=200303042358.56560.sam%40vilain.net

People can instantiate the roles that cover all that to an actual
metaclass in whatever way they like (eg,
Moose::Meta::Class->isa(Class::MOP::Class)), but not having to detect
the type and then figure out how to talk to it for at least the core of
the object system would be good.

People can diverge completely with completely incompatible metaclasses
that don't .do those roles, the only side effect of which being that
people who write code for the standard Perl 6 metamodel will be
incompatible, and maybe some ways of setting up the class won't work
without another layer of trickery. I *think* that's what you're getting
at. Of course, it shouldn't be prohibited just because it smells.

On different note, there should be nice, per-class ways to make type
constraints not simply code blocks - otherwise too much reverse
engineering will be required to do the final stage of compiling typesafe
code, where you close the classes and discard all the runtime type checks.

An easy example of this is generics. With "where", this is what you
write (ignore the syntax errors for now):

class "Array of Str" is Array where { $_.isa(Str) for @$_ }

But that sucks, because that information about the type of the container
is buried deep within the code reference, is slow, and we can't build
our methods with the right signatures. So, we write;

role Array[::T] { ... }
class "Array of Str" does Array[Str];

Great. Now that information is available to Array in a structured manner
and the signatures can be built correspondingly. But to represent the
core types like Mapping or Set, we also need, for instance, the "unique"
constraint to be represented as an object, not a code block:

For instance,

role Mapping[::T1, ::T2] does Coll[::T1, ::T2] where Unique(0);

The "where Unique(0)" is the important bit. What is "Unique", and who
uses it? In my prototypes, I've been considering it being the job of the
composing class or role to handle that, as a meta-object method call.

So, the above might call Coll.meta.Unique(0) (look, I'm stomping all
over the meta-object now) during the composition of the "Mapping" role,
and it uses this to affect the methods that it builds until you get
something that behaves not entirely quite unlike a Mapping.

However feel free to continue to handwave for now. Personally I'd like
to see this synoptic before the Perl 6.0 release, to avoid the mistakes
of other (*cough* C# *cough* Java 1.5 *cough*) languages that slipped on
getting the generics in their libraries, to their ultimate detriment.

Sam.


Re: hyp-op examples of a Bag type in S03

2006-05-22 Thread Sam Vilain
Darren Duncan wrote:

> $bag1 >>-<< 1; # Bag(2,7,[1,Seq(8,2)],7)
> $bag2 >>-<< (1,1,1,1); # probably the same
> $bag3 >>-<< (1,1,2,1); # ?
>  
>

Bag's won't .does(Array) or .does(Coll[Seq,...]), so that hyperoperator
won't work - if anything it would try to add the (1,1,1,1) list to all
of the elements of the bag. You'd need to put the bag in something that
does imply ordering first.

This applies to any unordered collection, bags or sets.

Sam.


Re: [svn:perl6-synopsis] r9307 - doc/trunk/design/syn

2006-05-25 Thread Sam Vilain
[EMAIL PROTECTED] wrote:

>+In either case this sets the C property of the container to C.
>+Subroutines have a variant of the C property, C, that
>+sets the C property instead.  The C property specifies
>+a constraint to be checked upon calling C that, unlike the C
>+property, is not advertized as the type of the routine:
>

It doesn't have to be run-time; it could also merely alter the signature
of the (implied or explicit) return() function within that sub.

Sam.


Re: Concurrency: hypothetical variables and atomic blocks

2006-05-31 Thread Sam Vilain
Jonathan Lang wrote:

>How does an atomic block differ from one in which all variables are
>implicitly hypotheticalized?  I'm thinking that a "retry" exit
>statement may be redundant; instead, why not just go with the existing
>mechanisms for successful vs. failed block termination, with the minor
>modification that when an atomic block fails, the state rolls back?
>  
>

State rolling back automatically is the key feature of STM.

However, it can only cover pure perl state; any time that you enter a
function that performs I/O of any kind, then you are forcing bad things
to happen.

With Haskell this is sorted out by making the default "pure", and
everything else must be in a Monad.  However we're not into bondage here
so "is pure" is not default.  Instead we just die and rollback just
before I/O is attempted.  In principle, the compiler could automatically
attach "pure" traits to all functions and methods that it can prove will
never perform I/O and warn about this at compile time.

It might be possible for clever classes to circumvent this and carefully
call special unsafeIO() methods, and be passed messages about the STM
and hope that they do the right thing.  I don't know that anyone's
explored this area in depth in Perl 6 space.

>Also, what can "retry_with" do that testing the atomic block for
>failure can't?
>

I think the answer lies in the "checkpointing" references in that
document.  I don't know whether that's akin to a SQL savepoint (ie, a
point mid-transaction that can be rolled back to, without committing the
entire transaction) or more like a continuation that when resumed can
see the atomic changes, and when exiting finally applies them (or rolls
back).  Perhaps someone else will have more of a clue.

Sam.


Re: Concurrency: hypothetical variables and atomic blocks

2006-05-31 Thread Sam Vilain
Daniel Hulme wrote:

>>How does an atomic block differ from one in which all variables are
>>implicitly hypotheticalized?
>>
>>
>I assume that the atomicness being controlled by some kind of lock on
>entry, it also applies to I/O and other side-effecty things that you
>can't undo.
>

The lock on entry approach will only be for non-threaded interpreters
that don't know how to do real STM.

Sam.


Re: Perl5 -> Perl 6 Translations Design Document

2006-06-05 Thread Sam Vilain
Sage La Torra wrote:

>Hello all,
>
>I'm the student picking up on the translation work lwall started. Since the
>perl 5 parser is more or less complete, I've headed straight to the
>translation work. I'm going to be taking on the translations a few at a
>time, starting with the easiest translations and moving to the more complex.
>I've got a design document detailing the first few translations I'll be
>handling, and I'd greatly appreciate feedback and advice. Larry already took
>a good crack at it, catching a few things I had stupidly thought were
>simpler then they are, and now it's ready for general review.
>
>The current version can be found at
>http://infohost.nmt.edu/~slatorra/conversionstageone.txt
>
>Any advice/comments/criticism on the document and even ideas on
>implementation would be greatly appreciated.
>  
>

Looks like a reasonable starting point.

I assume that the "AST" will include comment nodes etc?

Sam.


Re: easier duck typing in .can

2006-06-17 Thread Sam Vilain

Yuval Kogman wrote:

Since CANDO is a multimethod, IMHO this can be safely extended to
allow:

$object.can(Class);
$object.can(Role);

to better support duck typing.
  


Why would you not use .does or .isa there?  Are you wanting this to go 
through all of the Class/Role's methods and check that the $object.can() 
them?


I think that perhaps .can($Method) (where $Method.isa(Meta::Method)) 
would be acceptable, then .can(Role) can either be defined to be 
.can(all(Role.get_methods)), or we just leave the user to use that 
snippet - after all, such extreme duck typing is expensive and shouldn't 
be  huffmanised overly IMHO.  We want people to use the Role objects 
unless they have a really good reason, and besides you can always just 
wrap things up in a Facade if you have to.


Sam.



Re: lvalue functions and lvalue parameters

2006-06-20 Thread Sam Vilain
Jonathan Scott Duff wrote:
>> sub cond(Bool $c, $a, $b) is rw {
>>   if $c return $a else return $b;
>> }
>>
>> Will this fail because $a and $b are not rw? If so, will it fail at run-
>> or compile-time? What about this:
>> 
> That looks like it should be a compile-time failure to me.
>   

Depends on the interpreter of course, but ideally, yes, compile time.

>> sub cond(Bool $c, $a is copy, $b is copy) is rw {
>>   if $c return $a else return $b;
>> }
>>
>> Is it allowed, and if so is the behaviour to return a writeable copy of
>> $a or $b? I imagine that in any case
>> 
> I'd expect a compile-time failure here too, or at the very least a
> warning.  Besides, returning a local copy each time hardly seems
> useful, except perhaps as a way to leak memory.
>   

It doesn't have to be a real copy, that's up to the implementation to
apply whatever COW mechanism it likes. The type of $a and $b in this
case is compatible with the return type of the function, so it should be
fine.

This example is a bit useless - cond($x, $a, $b) = $foo won't store the
result anywhere. So this could be a warning along the lines of "useless
use of variable in void context" (but more tailored to this condition)

>> sub cond(Bool $c, $a is rw, $b is rw) is rw {
>>   if $c return $a else return $b;
>> }
>>
>> will do what I want. 
>> 
> That is what I would expect too.
>   

Right.

>> my Int $a is constant = 0;
>> my Int $b is constant = 0;
>> (cond(True, $a,$b))++;
>> 
>
> We have a "constant" declarator now, so that would be 
>
> constant Int $a = 0;
> constant Int $b = 0;
> (cond(True, $a,$b))++;
>
> and that should fail at compile time because the compiler knows that
> $a and $b are constant and can't be rw.
>   


Indeed it should, with the same disclaimer as above re: compile/runtime

Sam.


Re: features of and declaring Mapping|Set|Hash values|variables

2006-06-29 Thread Sam Vilain
Darren Duncan wrote:
> 1. Looking at the language in Synopsis 6 for data types, I see:
>
>  Set Unordered Seqs that allow no duplicates
>  JunctionSets with additional behaviours
>  PairSeq of two elements that serves as an one-element Mapping
>  Mapping Pairs with no duplicate keys
>
> I would like to know if Mapping.does(Set) and whether I could use the 
> full range of Set operators on them, as I would like to do?
>
> My impression is that it be reasonable to define a generic Mapping as 
> being a Set whose elements are all constrained to be Pairs, and 
> further that all keys of those pairs are distinct; eg:
>
>subset Mapping of Set where {
>  all(.members).does(Pair) and +all(.members.map:{.key}) == +all(.members)
>};
>   

Hmm. I still think a more generic Collection makes this more correct.

subset Set of Collection where {
all(.members) =:= one(.members);
}

subset Mapping of Collection where {
all(.members).does(Pair) and
all(.members).key =:= one(.members).key;
}

ie, being a Set is introducing a constraint, which is then duplicated in
the Mapping type. Now, you could argue that the Set constraint is
"shadowed" by the Mapping constraint and the constraints analysis system
could prove it does not need to be applied, but that's quite a high
level thing to expect the compiler to do at this point, I think.

However the above definitions, in my opinion, miss the potential of
parametric roles.

> If this is true, then I suggest rewording the above line in Synopsis 
> 6 to better clarify the situation, like this:
>
>  Mapping Set of Pairs that allow no duplicate Pair keys
>
> It would be very useful to employ Set operations like subset() or 
> union() or difference() etc on Mappings, that return Mappings.  
>
> 2. Similarly, I would like to know if Hash.does(Mapping) and so that 
> we can therefore use all the Set and Mapping operators on Hashes, but 
> that their output is Hashes.  Likewise very useful.
>   
How about;

Mapping Collection of Pairs that allow no duplicate Pair keys.

If "Collection" is parametric it must be a role, which means that we
can't directly subset it; we use role composition instead (I'm assuming
that we can use where{} during role composition).

role Set of Collection[Item] where { all(.members) =:= one(.members) };

# one of these
role Mapping of Collection[Pair] where {
all(.members).key =:= one(.members).key
};

# what is a pair, anyway?
role Pair of Seq[Item,Item] {
method key of Item { &.item(0) }
method value of Item { &.item(1) }
};

role HEK of Seq[Str, Item] does Pair;

role Hash of Collection[HEK] does Mapping;

role ArrayItem of Seq[Int, Item] {
method index of Int { &.item(0) }
method value of Item { &.item(1) }
};

role Array of Collection[ArrayItem] where {
all(.members).index == one(.members).index;
} {
method post_circumfix:<[ ]>(Int $index) of Item {
my $seq = first { .index == $index } &.members;
$seq ?? $seq.value :: undef;
}
}

There are some problems with the above, notably "Pair" could be
parametric, and the Array post_circumfix method should be an lvalue return.

I'm terribly sorry I haven't dedicated more time to developing this into
a working prototype module for Perl 5. RSN I hope.

> 3. I missed the syntax for declaring anonymous Set or Mapping in the 
> Synopsis.  Has it been defined yet?
>
> Something that is distinct from:
>
>[1,2] # Array
>(1,2) # Seq
>{1=>2,3=>4} # Hash
>(1=>2) # Pair in positional context
>1=>2 # Pair in named context
>all(1,2,3) # Junction
>
> Eg, do we need to use keywords:
>
>set(1,2,3)
>mapping(1=>2,3=>4)
>
> Or can this be accomplished without such keywords?
>
> I am assuming we don't have to invoke some new() because these are 
> built-in basic types.
>   

I don't see a problem with .new() for these types, which some might
consider arcane.

set() doesn't work for the Perl 5 prototypes, too many modules want to
use $object->set().

Users who want a shorthand can use a module that lets them write ⟦ ⟧ etc
(say).

> 4. Since they are already known to be unique, is it possible to get 
> an actual Set returned when invoking something akin to .keys or 
> .pairs or a Mapping or Hash?  Or do we need to always construct such 
> ourself by wrapping the call with a set() or all(), in order to use 
> set operations on them?  Would the latter case be inefficient or 
> verbose?
>   

Interesting idea. I guess that there are many places where a list or
array type is specified where it should be a set.

> 5. I'm wondering about syntax for using Sets like Junctions.  Eg, if 
> I want to see if one set is a proper subset of another, can I say 
> this:
>
>all($s1) === any($s2)
>
> Or do I have to rewrap their members into explicit Junctions first like this:
>
>all($s1.members) === any($s2.members)
>
> I am ignoring for the moment that Set probably declares named 
> operators that let me do this:
>
>$s2.subset($s1)
>
> I don't want to have

Re: binding operators and related introspection

2006-07-17 Thread Sam Vilain
Darren Duncan wrote:
> But I would also like to have an easy way to change all bindings to 
> the same variable at once to point to the same new variable. 
> [...]
>my $x = 'foo';
>my $y = 'bar';
>my $z := $x;# $x and $z point to same 'foo', $y to a 'bar'
>$z.rebind_all_aliases_to( $y ); # $x and $y and $z all point to 'bar'
>   

Maybe we need ruby's Object.all or whatever it is. Then you can write
something like

Object.all.grep:{ $_ =:= $z }.map{ $_ := $y };

Sam.




Re: META vs meta

2006-09-12 Thread Sam Vilain
Larry Wall wrote:
> : There is currently a mismatch between S12 and Pugs.  The former specifies 
> $obj.META, the latter has implemented $obj.meta.
>
> .META is more correct at the moment.
>   

Does making it all upper caps really help? It's still a pollution of the
method space, any way that you look at it...

What about this form:

# $o.?meta
# $o.?type
# $o.?var
# $o.?id

> Only that I'm thinking of renaming all the meta-ish methods to use
> interrogative pronouns:
>
> .META ->  .HOW
> .SKID ->  .WHO
> .PKG  ->  .WHAT
> .VAR  ->  .WHERE
>   

Oo-er. Well, you're the linguist ;)

Sam.


Re: Udates to "Perl 6 and Parrot Essentials"

2006-09-21 Thread Sam Vilain
Agent Zhang wrote:
> On 9/19/06, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote:
>   
>> Have there been any significant changes since the 2nd. edition of "Perl 6
>> and Parrot Essentials"?
>>
>> If so, where should I look for a summary?
>>
>> 
>
> Yes, there have. That book is completely out of date. Please check out
> http://perlcabal.org/syn for the latest Synopses and other helpful
> documentation there.
>   

Having just read the second edition, I think "completely out of date" is
a bit harsh.  I think the best plan is to make sure as you go along that
all of the code snippets work as expected; as when you would when
normally working through a text, ie take the examples, run them, play
with them, etc in order to understand them.  There is always this list
to ask when you get stuck.

I actually think that as far as compact, easy to read summaries of Perl
6 go, this book is a treasure.

Sam.


Re: Capture sigil

2006-09-21 Thread Sam Vilain
Larry Wall wrote:
> Okay, I think this is worth bringing up to the top level.
>
> Fact: Captures seem to be turning into a first-class data structure
> that can represent:
>
> argument lists
> match results
> XML nodes
> anything that requires all of $, @, and % bits.
>   

Also;

  role type parameters

Sam.


Nitpick my Perl6 - parametric roles

2006-09-25 Thread Sam Vilain
Anyone care to pick holes in this little expression of some Perl 6 core
types as collections?  I mean, other than missing methods ;)

  role Collection[\$types] {
   has Seq[$types] @.members;
  }
 
  role Set[::T = Item] does Collection[T] where {
  all(.members) =:= one(.members);
  };
 
  role Pair[::K = Item, ::V = Item] does Seq[K,V] {
  method key of K { .[0] }
  method value of V { .[1] }
  };
 
  role Mapping[::K = Item, ::V = Item] does Collection[Pair[K,V]] {
  all(.members).does(Pair) and
  all(.members).key =:= one(.members).key;
  }
 
  role Hash[Str ::K, ::V = Item] does Mapping[K, V]
  where { all(.members).key == one(.members).key }
  {
  method post_circumfix:<{ }> (K $key) of V|Undefined {
  my $seq = first { .key == $key } &.members;
  $seq ?? $seq.value :: undef;
  }
  }
 
  role ArrayItem[::V = Item] does Seq[Int, V] {
  method index of Int { .[0] }
  method value of Item { .[1] }
  };
 
  role Array of Collection[ArrayItem]
  where { all(.members).index == one(.members).index }
  {
  method post_circumfix:<[ ]> (Int $index) of Item {
  my $seq = first { .index == $index } &.members;
  $seq ?? $seq.value :: undef;
  }
  }

I'll take the feedback I get, and try to make a set of Perl 6 classes in
the pugs project that look and feel just like regular Perl 6 hash/arrays
but are expressed in more elementary particles.

Cheers,
Sam.


Re: Nitpick my Perl6 - parametric roles

2006-09-25 Thread Sam Vilain
TSa wrote:
>>   role Collection[\$types] {
>>has Seq[$types] @.members;
>>   }
> This is a little wrapper that ensures that collections have got
> a @.members sequence of arbitrary type. This immediately raises
> the question how Seq is defined.
> [...and later...]
> Are you sure that the underlying Seq type handles the one and
> two parameter forms you've used so far?

Ah, yes, a notable omission.  I understood a Seq as a list with
individual types for each element, which are applied positionally.  The
superclass for things like Pair.

Here's a quick mock-up of what I mean:

   role Seq[ \$types ] {
   submethod COMPOSE {  # a la BUILD for classes
   loop( my $i = 0; $i < $types.elems; $i++ ) {
   # assumption: "self" here is the class
   # we're composing to, and "has" is a class
   # method that works a little like Moose
   self.has( $i++ => (isa => $types.[$i]) );
   }
   }
   my subset MySeqIndex of Int
   where { 0 <= $_ < $types.elems };

   method post_circimfix:<[ ]>( $element: MySeqIndex ) {
   $?SELF.$element;
   }
   }

Seq is certainly interesting for various reasons.  One is that it is a
parametric role that takes an arbitrary set of parameters.  In fact,
it's possible that the type arguments are something more complicated
than a list (making for some very "interesting" Seq types); the above
represents a capture, but the above code treats it was a simple list.

>>   role Set[::T = Item] does Collection[T] where {
>>   all(.members) =:= one(.members);
>>   };
> 
> Nice usage of junctions! But how is the assertion of
> uniqueness transported into methods that handle adding
> of new values?

I haven't defined any mutable state yet; it's still "pure".

I'd expect mutability to be a different role, and a set of primitives
that work on this level by returning a new set with the changes made.
In fact the mutable Set could re-use those primitives, by just having a
Set as a member (that 'handles' the Set role methods), and automatically
changing that member each time a change is made, to point to the new Set
with the new contents.

Which all sounds very inefficient and scary until you realise what
happens inside generative GC VMs that support STM.

>>   role Mapping[::K = Item, ::V = Item] does Collection[Pair[K,V]] {
>>   all(.members).does(Pair) and
>>   all(.members).key =:= one(.members).key;
>>   }
> 
> I guess this is a typo and you wanted a where clause. The first
> assertion of the members doing the Pair role should be guaranteed
> by using Pair as the type argument when instantiating the Collection
> role.

Well spotted; yes, that is superfluous.

>>   role Hash[Str ::K, ::V = Item] does Mapping[K, V]
> 
> Will the Str assertion not be too specific for non-string hashes?

Another assumption I make here is that there is a basic type "Hash",
which as its name suggests, is all about hashing strings, and that the
more general form is called "Mapping" where any object can be the
source, not just Str subtypes.

Thanks for your other nitpicks and comments - much appreciated!

Sam.


>>   where { all(.members).key == one(.members).key }
>>   {
>>   method post_circumfix:<{ }> (K $key) of V|Undefined {
> 
> Nice union type as return type. But isn't the type name Undef?
> 
>>   my $seq = first { .key == $key } &.members;
> 
> Wasn't that @.members?
> 
>>   $seq ?? $seq.value :: undef;
> 
> Ternary is spelled ?? !! now.
> 
> 
>>   }
>>   }
>>  
>>   role ArrayItem[::V = Item] does Seq[Int, V] {
>>   method index of Int { .[0] }
>>   method value of Item { .[1] }
>>   };
> 
> Here we see the two parameter version of Seq at work.
> 
> 
>>   role Array of Collection[ArrayItem]
>>   where { all(.members).index == one(.members).index }
>>   {
>>   method post_circumfix:<[ ]> (Int $index) of Item {
>>   my $seq = first { .index == $index } &.members;
> 
> Is this first there a grep-like function? Shouldn't it then
> read 'first { .index == $index }, @.members'?
> 
> 
>>   $seq ?? $seq.value :: undef;
>>   }
>>   }
>>
>> I'll take the feedback I get, and try to make a set of Perl 6 classes in
>> the pugs project that look and feel just like regular Perl 6 hash/arrays
>> but are expressed in more elementary particles.
> 
> This might be very useful in future debates about these types. But
> I think everything hinges on the basic Seq type.
> 
> 
> Regards, TSa.



Re: Mutability vs Laziness

2006-09-25 Thread Sam Vilain
Aaron Sherman wrote:
> Carried over form IRC to placeholder the conversation as I saw it:
> 
> We define the following in S06 as immutable types:
> 
> ListLazy Perl list (composed of Seq and Range parts)
> Seq Completely evaluated (hence immutable) sequence
> Range   Incrementally generated (hence lazy) sequence
> Set Unordered Seqs that allow no duplicates
> JunctionSets with additional behaviours
> PairSeq of two elements that serves as a one-element Mapping
> Mapping Pairs with no duplicate keys
> 
> It seems to me that there are three core attributes, each of which has
> two states:
> 
> Laziness: true, false
> Mutability: true, false
> Ordered: true, false

I don't think "Ordered" is an attribute of a collection other than in
the abstract, user-centric sense - it is a type parameter difference
(though also there are method differences etc).  Things that are not
ordered map from items to presence (or themselves, if you prefer).
Things that are ordered map from array indices to items.

> There are, thus, eight types of containers, but two (unordered, mutable,
> lazy/eager) don't really work very well, so let's say 6:

Mutable sets don't work?  I don't see why not.

> Ordered,   Immutable, Eager:  Seq
> Ordered,   Immutable, Lazy:   Range and/or Seq of Range?
> Ordered,   Mutable,   Eager:  ?
>  Ordered,   Mutable,   Lazy:   Array
> Unordered, Immutable, Eager:  Set
> Unordered, Immutable, Lazy:   x and/or Set of x?
> 
> In that last example, x is "an unordered range",

Sounds a bit like an iterator.

Sam.


Re: Nitpick my Perl6 - parametric roles

2006-09-26 Thread Sam Vilain
Darren Duncan wrote:
> Unless I'm mistaken, you may be going about this the wrong way.
>
> Within a system that already has an underlying 
> set-like type, the Junction in this case, a test 
> for uniqueness is (pardon any spelling):
>
>all(@items).elements.size === @items.size
>
> The all() will strip any duplicates, so if the 
> number of elements in all(@items) is the same as 
> @items, then @items has no duplicates.
>   

Perhaps, but then Junctions might not assume elements have equality or
identity operations defined.  To do that you need to require this (and
which identity operator would you like to use today?), and that would
also have the side effect of making creating a junction an O(N^2) operation.

I think that the S06 definition needs re-wording.  It's more like a Bag
than a Set AIUI.

Sam.


Re: Nitpick my Perl6 - parametric roles

2006-09-26 Thread Sam Vilain
Miroslav Silovic wrote:
> 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.
>
>   

perl -MPerl6::Junction=one,all -le '@foo=qw(1 2 3 4); print "yes" if
(all(@foo) eq one(@foo))'
yes

Didn't test on pugs yet.

Sam.

> 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: Nitpick my Perl6 - parametric roles

2006-09-26 Thread Sam Vilain
TSa wrote:
> HaloO,
>
> Sam Vilain wrote:
>   
>> perl -MPerl6::Junction=one,all -le '@foo=qw(1 2 3 4); print "yes" if
>> (all(@foo) eq one(@foo))'
>> yes
>> 
>
> But does it fail for duplicates? I guess not because junctions
> eliminate duplicates and you end up testing unique values as
> above. E.g. all(1,1,2) == one(1,1,2) might actually give the
> same result as all(1,2) == one(1,2).
>   

Neither Pugs nor Perl6::Junction behaves like this.

pugs> for ([1,2,3], [1,1,2,3]) -> $x { my @x = @$x; my $all_unique = (
all(@x) == one(@x) ); print "{ $x.join(",") } became ", $all_unique; say
" (which is { $all_unique ?? "TRUE" !! "FALSE" })" }
1,2,3 became all(VJunc one(VBool True)) (which is TRUE)
1,1,2,3 became all(VJunc one(VBool False,VBool True),VJunc one()) (which
is FALSE)

Sam.


Re: Nitpick my Perl6 - parametric roles

2006-09-26 Thread Sam Vilain
Darren Duncan wrote:
>> Perhaps, but then Junctions might not assume elements have equality or
>> identity operations defined.
>> 
> As I recall, every type in Perl 6 has an equality and identity 
> operation defined because the Object superclass provides one.  If 
> nothing else, the type's equality and identity are the same as =:= 
> and .WHERE.
>   

Ok, seems reasonable.

>>  and that would
>> also have the side effect of making creating a junction an O(N^2) operation.
>> 
> Not if the type uses a hash-like index internally; then creating a 
> junction (or set) is more like O(N).
>   

Oh, yes, good point.

>> I think that the S06 definition needs re-wording.  It's more like a Bag
>> than a Set AIUI.
>> 
> I don't know what part you are reading, but the list of types that I 
> see says that a Junction is "Sets with additional behaviours".
>   

We're on the same page. It's just not the way that any of the prototypes
have behaved to date.

Sam.


Re: class interface of roles

2006-10-01 Thread Sam Vilain
TSa wrote:
> HaloO,
>
> is this subject not of interest? I just wanted to start a
> discussion about the class composition process and how a
> role designer can require the class to provide an equal
> method and then augment it to achieve the correct behavior.
> Contrast that with the need to do the same in every class
> that gets the equal method composed into if the role doesn't
> have a superclass interface as described in the article.
>   

This will be the same as requiring that a class implements a method,
except the method's name is infix:<==>(::T $self: T $other) or some such.

Sam.


Re: [perl #41478] [PATCH] add Test::More::skip()

2007-02-13 Thread Sam Vilain
Nicholas Clark via RT wrote:
> On Tue, Feb 13, 2007 at 11:44:01AM +0200, Allison Randal wrote:
>   
>> Why the reversed order of arguments from Test::Builder.skip?
>> 
>
> Well, it's not reversed from Perl 5's Test::Builder
>
> =item B
>
>   SKIP: {
>   skip $why, $how_many if $condition;
>
>   ...normal testing code goes here...
>   }
>
>
>   
>>  It seems that:
>> skip(5, 'lengthy message about reasoning')
>>
>> is more readable than:
>>
>> skip('lengthy message about reasoning', 5)
>> 
>
> I agree. I believe that I've made this mistake before in writing tests in
> Perl 5.
>
>   
>> Is the assumption that skipping a single test with a message is more 
>> common than skipping a number of tests without a message?
>> 
>
> This is my guess too. Probably need to as Schwern to find out the original
> (Perl 5) reason.
>
>   
multi-sub?

  skip string
  skip int, string

Sam.
 


> Nicholas Clark
>
>
>   

>From fe91f8e4469a56285254424e7c408dfc7e13241e Mon Sep 17 00:00:00 2001
From: Sam Vilain <[EMAIL PROTECTED]>
Date: Wed, 14 Feb 2007 01:27:23 +1300
Subject: [PATCH] [t/pmc] convert multisub test to PIR

---
 t/pmc/multisub.pir.t |   47 +++
 t/pmc/multisub.t |   42 --
 2 files changed, 47 insertions(+), 42 deletions(-)
 create mode 100644 t/pmc/multisub.pir.t
 delete mode 100644 t/pmc/multisub.t

diff --git a/t/pmc/multisub.pir.t b/t/pmc/multisub.pir.t
new file mode 100644
index 000..3c73408
--- /dev/null
+++ b/t/pmc/multisub.pir.t
@@ -0,0 +1,47 @@
+#! parrot
+# Copyright (C) 2001-2007, The Perl Foundation.
+# $Id$
+
+.macro IMPORT ( lib, subname, TEMP )
+	.TEMP = find_global .lib, .subname
+	store_global .subname, .TEMP
+.endm
+
+.sub main
+load_bytecode 'library/Test/More.pir'
+
+.local pmc _
+.IMPORT( 'Test::More', 'plan', _ )
+.IMPORT( 'Test::More', 'ok',   _ )
+.IMPORT( 'Test::More', 'is',   _ )
+
+plan( 2 )
+
+=head1 NAME
+
+t/pmc/multisub.t - Multi Sub PMCs
+
+=head1 SYNOPSIS
+
+% prove t/pmc/multisub.t
+
+=head1 DESCRIPTION
+
+Tests the creation and invocation of Perl6 multi subs.
+
+=cut
+
+new P0, .MultiSub
+I0 = defined P0
+ok(I0, "create PMC")
+
+elements I0, P0
+is(I0, 0, "multisubs start empty")
+
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 70
+# End:
+# vim: expandtab shiftwidth=4:
diff --git a/t/pmc/multisub.t b/t/pmc/multisub.t
deleted file mode 100644
index 24a9844..000
--- a/t/pmc/multisub.t
+++ /dev/null
@@ -1,42 +0,0 @@
-#! perl
-# Copyright (C) 2001-2005, The Perl Foundation.
-# $Id$
-
-use strict;
-use warnings;
-use lib qw( . lib ../lib ../../lib );
-use Test::More;
-use Parrot::Test tests => 1;
-
-=head1 NAME
-
-t/pmc/multisub.t - Multi Sub PMCs
-
-=head1 SYNOPSIS
-
-% prove t/pmc/multisub.t
-
-=head1 DESCRIPTION
-
-Tests the creation and invocation of Perl6 multi subs.
-
-=cut
-
-pasm_output_is( <<'CODE', <<'OUTPUT', "create PMC" );
-new P0, .MultiSub
-    print "ok 1\n"
-elements I0, P0
-print I0
-print "\n"
-end
-CODE
-ok 1
-0
-OUTPUT
-
-# Local Variables:
-#   mode: cperl
-#   cperl-indent-level: 4
-#   fill-column: 100
-# End:
-# vim: expandtab shiftwidth=4:
-- 
1.5.0.rc3.g3e023

>From 271801a9d4a3cbe7bd66418dd09be934d4b6f7ef Mon Sep 17 00:00:00 2001
From: Sam Vilain <[EMAIL PROTECTED]>
Date: Wed, 14 Feb 2007 02:54:09 +1300
Subject: [PATCH] [t/pmc] add a multisub test

Guessing from the code, it looks like it is designed to have Sub
objects pushed onto it.
---
 t/pmc/multisub.pir.t |   67 -
 1 files changed, 60 insertions(+), 7 deletions(-)

diff --git a/t/pmc/multisub.pir.t b/t/pmc/multisub.pir.t
index 3c73408..7b42410 100644
--- a/t/pmc/multisub.pir.t
+++ b/t/pmc/multisub.pir.t
@@ -7,15 +7,33 @@
 	store_global .subname, .TEMP
 .endm
 
-.sub main
+.sub skipone
+.param string why
+$S0 = "mmd - S - " . why
+.return($S0)
+.end
+
+.sub skipn
+.param int i
+.param string why
+$S1 = i
+$S0 = "mmd - IS - x" . $S1
+$S0 = $S0 . " - "
+$S0 = $S0 . why
+.return($S0)
+.end
+
+.sub main :main
 load_bytecode 'library/Test/More.pir'
 
 .local pmc _
 .IMPORT( 'Test::More', 'plan', _ )
 .IMPORT( 'Test::More', 'ok',   _ )
 .IMPORT( 'Test::More', 'is',   _ )
+$P0 = find_global 'Test::More', 'skip'
+store_global '_skip', $P0
 
- 

Re: [svn:parrot-pdd] r17312 - trunk/docs/pdds/draft

2007-03-04 Thread Sam Vilain
[EMAIL PROTECTED] wrote:
> (When you extend an existing class, it actually creates
> +a new class, that replaces the old class in the Namespace, but the old
> +class can't be thrown away if it has objects instantiated in it. The old
> +objects still point to the old class and do their method resolution and
> +attribute lookup through that class. If a class hasn't been
> +instantiated, adding a method doesn't create a new class. If it has been
> +instantiated, the it creates a new class the first time its extended,
> +and then doesn't create a new class until it is instantiated again.)

Is it intended that if languages need to make changes to the behaviour
of existing obejcts through their type, that something may follow up
after this and replace the old objects with objects of the new type?

Sam.


Re: [PATCH]: tools for using Subversion branches; ops2c.pl refactored

2007-03-04 Thread Sam Vilain
James Keenan wrote:
> The patch attached is really two patches in one:
>
> 1.  A resubmission in patch form of my refactoring of tools/build/ 
> ops2c.pl into lib/Parrot/Ops2c/Utils.pm and lib/Parrot/Ops2c/ 
> Auxiliary.pm, along with a test suite in t/tools/ops2cutils/.
>
> 2.  4 new files which provide an argument for more use of Subversion  
> branches in Parrot development and some tools to make using branches  
> easier.  The files being submitted for the first time are:
>   

Why are these two changes tied together?  Surely if you have a capable
feature branching system this is not necessary.

> docs/svn_branching.pod
> lib/Parrot/Subversion/BranchManager.pm
> tools/util/svn_new_branch.pl
> tools/util/svn_synch.pl
>   

The method of tracking which branch has been merged does not follow best
practices.

Several best practices have emerged with SVN and branching, when copying
changes from one branch to another:

1. best (if the UUID matches the repository it is being stored in) -
insert a property called "svk:merge" into the merge commit which refers
to the SVN repo UUID and revision number of the other parent commit
which Subversion was incapable of representing.

2. second best - copy revisions individually from one branch to the
other, such as "svk smerge -Il" does.

3. crappy and crack fueled -the Subversion manual's recommendation that
you should note in the commit message which revisions you are "merging"
when you copy changes from one part of subversion repositories to another.

4. Option 1, except that the UUID and revision number are not related to
the repository they are being stored in, so end up having no meaning at
all (unless the repository they refer to is also published, and even
then it's not exactly turn-key to get history information)

Even looking at the tags that have recently been created nearby to your
changes it is difficult to see what value this entirely novel system adds.

Sam.

> While I'm pretty certain the first two of these four files are in the  
> correct directories, I'm less certain about the last two.  They are  
> utilities intended for use by Parrot developers but, since they're  
> not used by Configure.pl, make, or make test, they're not necessary  
> for Parrot itself.
>
> Comments?  I would particularly welcome tryouts of the two utilities  
> on Windows and Linux.
>
> kid51
>   



Re: [PATCH]: tools for using Subversion branches; ops2c.pl refactored

2007-03-04 Thread Sam Vilain
James Keenan wrote:
>> Why are these two changes tied together?  Surely if you have a capable
>> feature branching system this is not necessary.
> I submitted individual patches and new files last week for the  
> refactoring of ops2c.pl.  Following the instructions in docs/ 
> submission.pod, I edited MANIFEST to include the new files and paths.
>
> Those patches and new files haven't been reviewed yet.  When I went  
> to my next round of submissions, I wanted to get it done quickly  
> (I've been dealing with eye infections the last several days and am  
> tiring easily) and decided to submit a single patch.  The MANIFEST  
> had entries for both submissions.
>   

Mixing things together is everything that you are attempting to resolve.
Why are you making excuses for not achieving this?

> It's not novel with me.  I solicited advice on Perlmonks (http:// 
> perlmonks.org/?node_id=597867) on how to synchronize a Subversion  
> branch with trunk.  The scripts I wrote implemented one of the  
> options described in that Perlmonks thread, which was provided from a  
> fellow Perl hacker who has never steered me wrong.
>   

Sorry. Of the four first responses to that thread, you picked the one
with the worst advice.

> My main point is this:  At this point in Parrot's development, a lot  
> more of that development should be going on in branches rather than  
> in direct commits to trunk.  People need tools to manager branches  
> effectively and, AFAICT, no one else had addressed this problem.   
> particle asked me to come up with something that would reflect my  
> experience so far with branches and that other people would find  
> useful.  The four files I've submitted represent my attempt to  
> respond to particle's request.
>
> I freely concede that what I've submitted is a hack -- and have so  
> conceded in the documentation.  Perhaps what we should provide our  
> fellow Parrot hackers is a menu of choices for how to manage  
> branches.  If so, then instead of my suggestion of lib/Parrot/ 
> Subversion/, we should have lib/Parrot/VersionControl:  a directory  
> which would enable people to manage branches in the Parrot repository  
> (a) in a variety of ways using Subversion as their client; and/or (b)  
> using other clients such as svk.  If you would like to code up such a  
> tool (either (a) or (b)), then code away!  After all, (i) these are  
> just developers' tools; they're not essential to Parrot itself; (ii)  
> this is Perl:  TIMTOWTDI.
>   

I appreciate that, but with all due respect this system is unworkable
and needs addressing - somebody would come along later, decypher the
ad-hoc system that you or your advisors have invented and convert it to
something standard.

> If we took that approach, then we could accommodate a variety of ways  
> to manage branches in our repository, all with the goal of getting  
> people to develop more in branches.
>   

I agree with this goal.

Sam.


Re: [PATCH]: tools for using Subversion branches; ops2c.pl refactored

2007-03-04 Thread Sam Vilain
chromatic wrote:
>> Mixing things together is everything that you are attempting to resolve.
>> Why are you making excuses for not achieving this?
>> 
>
> I don't think that's entirely fair.  James's experiment here is an 
> experiment, 
> and if it fails we can learn something from it.
>   

Yes, sorry if it wasn't clear - I commend the goal and effort but
ultimately this particular experiment should be declared a dead end.

> Personally, I find that using SVK and creating local branches saves me from 
> this trouble, but I have commit access to Parrot and that might not be the 
> easiest solution for other people.
>   

Right, and SVK tracks the merge progress with its merge tickets - so
long as you're merging between mirror paths.  Otherwise its merge
tickets refer to your local repository.

> Perhaps an alternate solution is to document how people can create and update 
> their own local branches effectively even if they don't have commit access 
> (or whether they prefer SVK or Git).
>   

For sure.

Sam.


Patches for review

2007-03-12 Thread Sam Vilain
I've submitted a set of changes to the ML for review.

Do you really want tickets for all of those changes?  Some of them are
quite minor.

Sam.


Re: Patches for review

2007-03-12 Thread Sam Vilain
Will Coleda wrote:
> In *general*, yes, tickets good, so we don't lose any patches, even  
> the minor ones.
>
> That said, email a list of subjects and I'll take a look. (most of  
> what I see from you on the list went to parrotbug and so already has  
> a ticket.)
>   

Well, look at that, they didn't arrive :)

Obviously something on mx.develooper.com thought the e-mails weren't
generated by a human or something. hmm. Does anyone know if there's a
public trashed bin or something for the perl.org lists?

Sam.



> Regards.
>
> On Mar 12, 2007, at 10:30 PM, Sam Vilain wrote:
>
>   
>> I've submitted a set of changes to the ML for review.
>>
>> Do you really want tickets for all of those changes?  Some of them are
>> quite minor.
>>
>> Sam.
>>
>> 
>
> --
> Will "Coke" Coleda
> [EMAIL PROTECTED]
>
>
>   



[PATCH 6/6] [lib] Test::More - add isa_ok()

2007-03-13 Thread Sam Vilain
Add the isa_ok() method
---

 runtime/parrot/library/Test/More.pir |   80 ++
 t/library/test_more.t|   38 
 2 files changed, 117 insertions(+), 1 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index f9f6673..7a1d18d 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -19,6 +19,7 @@ Test::More - Parrot extension for testing modules
 .IMPORT( 'Test::More', 'isnt', _ )
 .IMPORT( 'Test::More', 'is_deeply', _ )
 .IMPORT( 'Test::More', 'like', _ )
+.IMPORT( 'Test::More', 'isa_ok', _ )
 
 # set a test plan
 plan( 13 )
@@ -47,6 +48,11 @@ Test::More - Parrot extension for testing modules
 like( 'foo', 'f o**{2}', 'passing regex compare with diagnostic' )
  .end
 
+$P0 = getclass "Moose"
+$P0.new()
+
+isa_ok($P0, "Moose", "new Moose")
+
 =head1 DESCRIPTION
 
 C is a pure-Parrot library for testing modules.  It provides
@@ -943,6 +949,80 @@ actually skipped.  Arguments are optional.
 test.'skip'()
 .end
 
+=item C
+
+Pass if the pmc passed "isa" class.  The "name" passed in is a
+description of what it is you've passed in, not a comment.  It is
+presented as "name isa class" in the description.
+
+Good input: "C", "C"
+
+Bad input: "C"
+
+=cut
+
+.sub isa_ok :multi(pmc, string)
+.param pmc thingy
+.param string class_name
+.param string name :optional
+.param int got_name :opt_flag
+
+.local pmc test
+find_global test, 'Test::More', '_test'
+
+.local string _name
+_name = name
+if got_name goto great
+_name = "object"
+great: 
+$S0 = _name . " isa "
+$S0 = $S0 . class_name
+
+$I0 = isa thingy, class_name
+test.'ok'($I0, $S0)
+if $I0 goto out
+_isa_ok_diag(test, class_name, _name, thingy)
+out:   
+.end
+
+.sub isa_ok :multi(pmc, pmc)
+.param pmc thingy
+.param pmc class
+.param string name :optional
+.param int got_name :opt_flag
+
+.local pmc test
+find_global test, 'Test::More', '_test'
+
+.local string _name, class_name
+_name = name
+if got_name goto great
+_name = "object"
+great: 
+$S0 = _name . " isa "
+class_name = classname class
+$S0 = $S0 . class_name
+
+$I0 = isa thingy, class
+test.'ok'($I0, $S0)
+if $I0 goto out
+_isa_ok_diag(test, class_name, _name, thingy)
+out:   
+.end
+
+.sub _isa_ok_diag
+.param pmc test
+.param string class_name
+.param string name
+.param pmc thingy
+$S0 = name . " isn't a "
+$S0 = $S0 . class_name
+$S0 = $S0 . " it's a "
+$S1 = typeof thingy
+$S0 = $S0 . $S1
+test.'diag'($S0)
+.end
+
 .sub _make_diagnostic
 .param string received
 .param string expected
diff --git a/t/library/test_more.t b/t/library/test_more.t
index b7aa317..17b0671 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -26,6 +26,7 @@
.IMPORT( 'Test::More', 'like' )
.IMPORT( 'Test::More', 'skip' )
.IMPORT( 'Test::More', 'is_deeply' )
+   .IMPORT( 'Test::More', 'isa_ok' )
.IMPORT( 'Test::Builder::Tester', 'plan' )
.IMPORT( 'Test::Builder::Tester', 'test_out' )
.IMPORT( 'Test::Builder::Tester', 'test_diag' )
@@ -33,7 +34,7 @@
.IMPORT( 'Test::Builder::Tester', 'test_pass' )
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
-   plan( 55 )
+   plan( 60 )
test_skip()
test_ok()
test_is()
@@ -41,6 +42,7 @@
test_is_deeply()
test_diagnostics()
test_isnt()
+   test_isa_ok()
 
test.'finish'()
 .end
@@ -411,3 +413,37 @@
 

 .end
+
+.sub test_isa_ok
+   .local pmc dog, terrier, daschund, Spot, Sossy
+
+   dog = newclass "dog"
+   terrier = subclass dog, "terrier"
+   daschund = subclass dog, "daschund"
+
+   Spot = new "terrier"
+   Sossy = new "daschund"
+
+   test_pass( 'Spot isa terrier' )
+   isa_ok(Spot, "terrier", "Spot")
+   test_test( 'passing isa_ok for PMC/string (class =)' )
+
+   test_pass( 'Spot isa dog' )
+   isa_ok(Spot, "dog", "Spot")
+   test_test( 'passing isa_ok for PMC/string (super)')
+
+   test_pass( 'Sossy isa daschund' )
+   isa_ok(Sossy, "daschund", "Sossy")
+   test_test( 'passing isa_ok for PMC/PMC (class =)' )
+
+   test_pass( 'Sossy isa dog' )
+   isa_ok(Sossy, "dog", "Sossy")
+   test_test( 'passing isa_ok for PMC/PMC (super)')
+
+   test_fail( 'Spot isa daschund' )
+test_diag( "Spot isn't a daschund it's a terrier" )
+   isa_ok(Spot, 'daschund', "Spot")
+   test_test( 'failing test isnt() for PMC/string')
+   
+.end
+



[PATCH 4/6] [library/Test::More] add isnt() to test inequality - ints only

2007-03-13 Thread Sam Vilain
refactor the is() :multi for integers into a _cmp_ok() function, and
then use that to provide is() and isnt()
---
 runtime/parrot/library/Test/More.pir |   53 --
 t/library/test_more.t|   16 +-
 2 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index fd297ab..dea010c 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -16,11 +16,12 @@ Test::More - Parrot extension for testing modules
 .IMPORT( 'Test::More', 'diag', _ )
 .IMPORT( 'Test::More', 'ok', _ )
 .IMPORT( 'Test::More', 'is', _ )
+.IMPORT( 'Test::More', 'isnt', _ )
 .IMPORT( 'Test::More', 'is_deeply', _ )
 .IMPORT( 'Test::More', 'like', _ )
 
 # set a test plan
-plan( 12 )
+plan( 13 )
 
 # run your tests
 ok( 1 )
@@ -28,6 +29,7 @@ Test::More - Parrot extension for testing modules
 
 is( 100, 100 )
 is( 200, 100, 'failing integer compare with diagnostic' )
+isnt( 200, 100, 'passing integer negative compare' )
 
 is( 1.001, 1.001, 'passing float compare with diagnostic' )
 is( 8.008, 4.004 )
@@ -148,22 +150,17 @@ add more.
 
 =cut
 
-.sub is :multi( int, int )
+.sub _cmp_ok :multi( int, int, pmc )
 .param intleft
 .param intright
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass   = 0
-
-if left == right goto pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -181,6 +178,22 @@ add more.
   done:
 .end
 
+.sub is :multi( int, int )
+.param intleft
+.param intright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_int"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_int
+.param intleft
+.param intright
+$I0 = iseq left, right
+.return($I0)
+.end
+
 .sub is :multi( float, float )
 .param float  left
 .param float  right
@@ -306,6 +319,28 @@ add more.
   done:
 .end
 
+=item C
+
+As C, but the test passes if the arguments I match.
+
+=cut
+
+.sub isnt :multi( int, int )
+.param intleft
+.param intright
+.param string description :optional
+.local pmc comp
+comp = find_name "_ne_int"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _ne_int
+.param intleft
+.param intright
+$I0 = isne left, right
+.return($I0)
+.end
+
 =item C
 
 Prints C to the screen, without affecting test comparisons.
diff --git a/t/library/test_more.t b/t/library/test_more.t
index 23576eb..4bc08b8 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -21,6 +21,7 @@
.local pmc import_sub
.IMPORT( 'Test::More', 'ok' )
.IMPORT( 'Test::More', 'is' )
+   .IMPORT( 'Test::More', 'isnt' )
.IMPORT( 'Test::More', 'diag' )
.IMPORT( 'Test::More', 'like' )
.IMPORT( 'Test::More', 'skip' )
@@ -32,13 +33,14 @@
.IMPORT( 'Test::Builder::Tester', 'test_pass' )
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
-   plan( 47 )
+   plan( 49 )
test_skip()
test_ok()
test_is()
test_like()
test_is_deeply()
test_diagnostics()
+   test_isnt()
 
test.'finish'()
 .end
@@ -360,3 +362,15 @@
skip()
test_test( 'skip()' )
 .end
+
+.sub test_isnt
+   test_fail()
+   isnt( 100, 100 )
+   test_diag( 'Received: 100' )
+   test_diag( 'Expected: 100' )
+   test_test( 'failing test isnt() for ints')
+
+   test_pass()
+   isnt( -100, 200 )
+   test_test( 'passing test isnt() for ints')
+.end
-- 
1.5.0.759.g41ffe



[PATCH 3/6] [lib/Test::More] base comparison type on expected, not received PMC type

2007-03-13 Thread Sam Vilain
The type of the 'left' argument was being used for the selection
of which comparison function to use.  This does not agree with the
typical usage of the second argument to is() to mean the expected
value (as in English).
---

 runtime/parrot/library/Test/More.pir |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index 51660ea..fd297ab 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -258,11 +258,11 @@ add more.
 .local int pass
 pass = 0
 
-   .local string l_type
-   l_type = typeof left
+   .local string r_type
+   r_type = typeof right
 
-   if l_type == 'Float' goto num_compare
-   if l_type == 'Int'   goto num_compare
+   if r_type == 'Float' goto num_compare
+   if r_type == 'Int'   goto num_compare
goto string_compare
 
   num_compare:



[PATCH 5/6] [library/Test::More] add isnt() to test inequality - str and float

2007-03-13 Thread Sam Vilain
Continue the previous factoring out of the comparison and
test function, by adding _cmp_ok() for other types
---
 runtime/parrot/library/Test/More.pir |  233 +++---
 t/library/test_more.t|   39 ++-
 2 files changed, 222 insertions(+), 50 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index dea010c..f9f6673 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -32,10 +32,12 @@ Test::More - Parrot extension for testing modules
 isnt( 200, 100, 'passing integer negative compare' )
 
 is( 1.001, 1.001, 'passing float compare with diagnostic' )
+isnt( 1.001, 1.001, 'failing float negative compare with diag' )
 is( 8.008, 4.004 )
 
 is( 'foo', 'foo', 'passing string compare with diagnostic' )
 is( 'foo', 'bar', 'failing string compare with diagnostic' )
+isnt( 'foo', 'bar', 'passing string negative compare with diag' )
 
 is( some_pmc, another_pmc, 'pmc comparison uses "eq" op' )
 
@@ -194,22 +196,17 @@ add more.
 .return($I0)
 .end
 
-.sub is :multi( float, float )
+.sub _cmp_ok :multi( float, float, pmc )
 .param float  left
 .param float  right
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
-
-eq left, right, pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -227,22 +224,46 @@ add more.
   done:
 .end
 
-.sub is :multi( string, string )
+.sub is :multi( float, float )
+.param floatleft
+.param floatright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_float"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_float
+.param floatleft
+.param floatright
+$I0 = 0
+if left == right goto pass_it
+
+   # XXX - significant places?  I don't care :)
+   .local float diff
+   diff = left - right
+   abs diff
+
+   if diff < 0.0001 goto pass_it
+
+   goto out
+pass_it:
+   $I0 = 1
+out:   
+.return($I0)
+.end
+
+.sub _cmp_ok :multi( string, string, pmc )
 .param string left
 .param string right
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
-
-eq left, right, pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -260,63 +281,128 @@ add more.
   done:
 .end
 
-.sub is :multi()
+.sub is :multi( string, string )
+.param stringleft
+.param stringright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_string"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_string
+.param stringleft
+.param stringright
+$I0 = iseq left, right
+.return($I0)
+.end
+
+.sub _ne_string
+.param stringleft
+.param stringright
+$I0 = isne left, right
+.return($I0)
+.end
+
+.sub _cmp_ok :multi()
 .param pmcleft
 .param pmcright
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
+pass = comp(left, right)
+
+  report:
+test.ok( pass, description )
+if pass goto done
+
+.local string diagnostic
+.local string l_string
+.local string r_string
+
+l_string= left
+r_string= right
+
+diagnostic = _make_diagnostic( l_string, r_string )
+test.diag( diagnostic )
+  done:
+.end
 
-   .local string r_type
-   r_type = typeof right
+.sub _is_or_isnt :multi()
+.param pmcleft
+.param pmcright
+.param string which
+.param string description :optional
 
-   if r_type == 'Float' goto num_compare
-   if r_type == 'Int'   goto num_compare
-   goto string_compare
+.local string func
+func = "_" . which
+func = func . "_"
 
-  num_compare:
+.local string r_type
+r_type = typeof right
+
+.local pmccomp
+if r_type == 'Float'  goto float_compare
+if r_type == 'Int'goto int_compare
+if r_type == 'String' goto string_compare
+goto object_compare
+
+  float_compare:
.local float l_val
.local float r_val
l_val = left
r_val = right
-
-if l_val == r_val goto pass_it
-
-   # XXX - significant places?  I don't care :)
-   .local float diff
-   diff = l_val - r_val
-
-   if diff < 0.0001 goto pass_it
+   func = func . "float"
+   comp = find_name func
+   say "# comparing floats"
+   _cmp_ok(l_val, r_val, comp, description)
+   goto out
 
   string_compare:
.local string l_val
.l

[PATCH 5/6] [library/Test::More] add isnt() to test inequality - str and float

2007-03-13 Thread Sam Vilain
Continue the previous factoring out of the comparison and
test function, by adding _cmp_ok() for other types
---

 runtime/parrot/library/Test/More.pir |  233 +++---
 t/library/test_more.t|   39 ++
 2 files changed, 222 insertions(+), 50 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index dea010c..f9f6673 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -32,10 +32,12 @@ Test::More - Parrot extension for testing modules
 isnt( 200, 100, 'passing integer negative compare' )
 
 is( 1.001, 1.001, 'passing float compare with diagnostic' )
+isnt( 1.001, 1.001, 'failing float negative compare with diag' )
 is( 8.008, 4.004 )
 
 is( 'foo', 'foo', 'passing string compare with diagnostic' )
 is( 'foo', 'bar', 'failing string compare with diagnostic' )
+isnt( 'foo', 'bar', 'passing string negative compare with diag' )
 
 is( some_pmc, another_pmc, 'pmc comparison uses "eq" op' )
 
@@ -194,22 +196,17 @@ add more.
 .return($I0)
 .end
 
-.sub is :multi( float, float )
+.sub _cmp_ok :multi( float, float, pmc )
 .param float  left
 .param float  right
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
-
-eq left, right, pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -227,22 +224,46 @@ add more.
   done:
 .end
 
-.sub is :multi( string, string )
+.sub is :multi( float, float )
+.param floatleft
+.param floatright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_float"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_float
+.param floatleft
+.param floatright
+$I0 = 0
+if left == right goto pass_it
+
+   # XXX - significant places?  I don't care :)
+   .local float diff
+   diff = left - right
+   abs diff
+
+   if diff < 0.0001 goto pass_it
+
+   goto out
+pass_it:
+   $I0 = 1
+out:   
+.return($I0)
+.end
+
+.sub _cmp_ok :multi( string, string, pmc )
 .param string left
 .param string right
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
-
-eq left, right, pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -260,63 +281,128 @@ add more.
   done:
 .end
 
-.sub is :multi()
+.sub is :multi( string, string )
+.param stringleft
+.param stringright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_string"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_string
+.param stringleft
+.param stringright
+$I0 = iseq left, right
+.return($I0)
+.end
+
+.sub _ne_string
+.param stringleft
+.param stringright
+$I0 = isne left, right
+.return($I0)
+.end
+
+.sub _cmp_ok :multi()
 .param pmcleft
 .param pmcright
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
+pass = comp(left, right)
+
+  report:
+test.ok( pass, description )
+if pass goto done
+
+.local string diagnostic
+.local string l_string
+.local string r_string
+
+l_string= left
+r_string= right
+
+diagnostic = _make_diagnostic( l_string, r_string )
+test.diag( diagnostic )
+  done:
+.end
 
-   .local string r_type
-   r_type = typeof right
+.sub _is_or_isnt :multi()
+.param pmcleft
+.param pmcright
+.param string which
+.param string description :optional
 
-   if r_type == 'Float' goto num_compare
-   if r_type == 'Int'   goto num_compare
-   goto string_compare
+.local string func
+func = "_" . which
+func = func . "_"
 
-  num_compare:
+.local string r_type
+r_type = typeof right
+
+.local pmccomp
+if r_type == 'Float'  goto float_compare
+if r_type == 'Int'goto int_compare
+if r_type == 'String' goto string_compare
+goto object_compare
+
+  float_compare:
.local float l_val
.local float r_val
l_val = left
r_val = right
-
-if l_val == r_val goto pass_it
-
-   # XXX - significant places?  I don't care :)
-   .local float diff
-   diff = l_val - r_val
-
-   if diff < 0.0001 goto pass_it
+   func = func . "float"
+   comp = find_name func
+   say "# comparing floats"
+   _cmp_ok(l_val, r_val, comp, description)
+   goto out
 
   string_compare:
.local string l_val
.l

[PATCH 3/6] [lib/Test::More] base comparison type on expected, not received PMC type

2007-03-13 Thread Sam Vilain
The type of the 'left' argument was being used for the selection
of which comparison function to use.  This does not agree with the
typical usage of the second argument to is() to mean the expected
value (as in English).
---
 runtime/parrot/library/Test/More.pir |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index 51660ea..fd297ab 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -258,11 +258,11 @@ add more.
 .local int pass
 pass = 0
 
-   .local string l_type
-   l_type = typeof left
+   .local string r_type
+   r_type = typeof right
 
-   if l_type == 'Float' goto num_compare
-   if l_type == 'Int'   goto num_compare
+   if r_type == 'Float' goto num_compare
+   if r_type == 'Int'   goto num_compare
goto string_compare
 
   num_compare:
-- 
1.5.0.759.g41ffe



[PATCH 0/6] A round of Test/More updates

2007-03-13 Thread Sam Vilain
This patch series extends the Test/More.pir library in various ways.

I'm sending it this way because it's trivial for me to do so, and
potentially makes the patches easier for the list to review and
comment on particular portions.

Sam.



[PATCH 6/6] [lib] Test::More - add isa_ok()

2007-03-13 Thread Sam Vilain
---
 runtime/parrot/library/Test/More.pir |   80 ++
 t/library/test_more.t|   38 -
 2 files changed, 117 insertions(+), 1 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index f9f6673..7a1d18d 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -19,6 +19,7 @@ Test::More - Parrot extension for testing modules
 .IMPORT( 'Test::More', 'isnt', _ )
 .IMPORT( 'Test::More', 'is_deeply', _ )
 .IMPORT( 'Test::More', 'like', _ )
+.IMPORT( 'Test::More', 'isa_ok', _ )
 
 # set a test plan
 plan( 13 )
@@ -47,6 +48,11 @@ Test::More - Parrot extension for testing modules
 like( 'foo', 'f o**{2}', 'passing regex compare with diagnostic' )
  .end
 
+$P0 = getclass "Moose"
+$P0.new()
+
+isa_ok($P0, "Moose", "new Moose")
+
 =head1 DESCRIPTION
 
 C is a pure-Parrot library for testing modules.  It provides
@@ -943,6 +949,80 @@ actually skipped.  Arguments are optional.
 test.'skip'()
 .end
 
+=item C
+
+Pass if the pmc passed "isa" class.  The "name" passed in is a
+description of what it is you've passed in, not a comment.  It is
+presented as "name isa class" in the description.
+
+Good input: "C", "C"
+
+Bad input: "C"
+
+=cut
+
+.sub isa_ok :multi(pmc, string)
+.param pmc thingy
+.param string class_name
+.param string name :optional
+.param int got_name :opt_flag
+
+.local pmc test
+find_global test, 'Test::More', '_test'
+
+.local string _name
+_name = name
+if got_name goto great
+_name = "object"
+great: 
+$S0 = _name . " isa "
+$S0 = $S0 . class_name
+
+$I0 = isa thingy, class_name
+test.'ok'($I0, $S0)
+if $I0 goto out
+_isa_ok_diag(test, class_name, _name, thingy)
+out:   
+.end
+
+.sub isa_ok :multi(pmc, pmc)
+.param pmc thingy
+.param pmc class
+.param string name :optional
+.param int got_name :opt_flag
+
+.local pmc test
+find_global test, 'Test::More', '_test'
+
+.local string _name, class_name
+_name = name
+if got_name goto great
+_name = "object"
+great: 
+$S0 = _name . " isa "
+class_name = classname class
+$S0 = $S0 . class_name
+
+$I0 = isa thingy, class
+test.'ok'($I0, $S0)
+if $I0 goto out
+_isa_ok_diag(test, class_name, _name, thingy)
+out:   
+.end
+
+.sub _isa_ok_diag
+.param pmc test
+.param string class_name
+.param string name
+.param pmc thingy
+$S0 = name . " isn't a "
+$S0 = $S0 . class_name
+$S0 = $S0 . " it's a "
+$S1 = typeof thingy
+$S0 = $S0 . $S1
+test.'diag'($S0)
+.end
+
 .sub _make_diagnostic
 .param string received
 .param string expected
diff --git a/t/library/test_more.t b/t/library/test_more.t
index b7aa317..17b0671 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -26,6 +26,7 @@
.IMPORT( 'Test::More', 'like' )
.IMPORT( 'Test::More', 'skip' )
.IMPORT( 'Test::More', 'is_deeply' )
+   .IMPORT( 'Test::More', 'isa_ok' )
.IMPORT( 'Test::Builder::Tester', 'plan' )
.IMPORT( 'Test::Builder::Tester', 'test_out' )
.IMPORT( 'Test::Builder::Tester', 'test_diag' )
@@ -33,7 +34,7 @@
.IMPORT( 'Test::Builder::Tester', 'test_pass' )
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
-   plan( 55 )
+   plan( 60 )
test_skip()
test_ok()
test_is()
@@ -41,6 +42,7 @@
test_is_deeply()
test_diagnostics()
test_isnt()
+   test_isa_ok()
 
test.'finish'()
 .end
@@ -411,3 +413,37 @@
 

 .end
+
+.sub test_isa_ok
+   .local pmc dog, terrier, daschund, Spot, Sossy
+
+   dog = newclass "dog"
+   terrier = subclass dog, "terrier"
+   daschund = subclass dog, "daschund"
+
+   Spot = new "terrier"
+   Sossy = new "daschund"
+
+   test_pass( 'Spot isa terrier' )
+   isa_ok(Spot, "terrier", "Spot")
+   test_test( 'passing isa_ok for PMC/string (class =)' )
+
+   test_pass( 'Spot isa dog' )
+   isa_ok(Spot, "dog", "Spot")
+   test_test( 'passing isa_ok for PMC/string (super)')
+
+   test_pass( 'Sossy isa daschund' )
+   isa_ok(Sossy, "daschund", "Sossy")
+   test_test( 'passing isa_ok for PMC/PMC (class =)' )
+
+   test_pass( 'Sossy isa dog' )
+   isa_ok(Sossy, "dog", "Sossy")
+   test_test( 'passing isa_ok for PMC/PMC (super)')
+
+   test_fail( 'Spot isa daschund' )
+test_diag( "Spot isn't a daschund it's a terrier" )
+   isa_ok(Spot, 'daschund', "Spot")
+   test_test( 'failing test isnt() for PMC/string')
+   
+.end
+
-- 
1.5.0.759.g41ffe



[PATCH 1/6] [library] Test::More: use hllmacros.pir in man page example

2007-03-13 Thread Sam Vilain
Use current best practice for importing symbols in the example.
---

 runtime/parrot/library/Test/More.pir |   26 --
 1 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index 8441b25..51660ea 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -4,23 +4,20 @@ Test::More - Parrot extension for testing modules
 
 =head1 SYNOPSIS
 
+ .include "hllmacros.pir"
+
+ .sub main :main
 # load this library
 load_bytecode 'library/Test/More.pir'
 
-# get the testing functions
-.local pmc plan
-.local pmc diag
-.local pmc ok
-.local pmc is
-.local pmc is_deeply
-.local pmc like
-
-plan  = find_global 'Test::More', 'plan'
-diag  = find_global 'Test::More', 'diag'
-ok= find_global 'Test::More', 'ok'
-is= find_global 'Test::More', 'is'
-is_deeply = find_global 'Test::More', 'is_deeply'
-like  = find_global 'Test::More', 'like'
+# from hllmacros.pir
+.local pmc _
+.IMPORT( 'Test::More', 'plan', _ )
+.IMPORT( 'Test::More', 'diag', _ )
+.IMPORT( 'Test::More', 'ok', _ )
+.IMPORT( 'Test::More', 'is', _ )
+.IMPORT( 'Test::More', 'is_deeply', _ )
+.IMPORT( 'Test::More', 'like', _ )
 
 # set a test plan
 plan( 12 )
@@ -44,6 +41,7 @@ Test::More - Parrot extension for testing modules
 is_deeply( some_deep_pmc, another_deep_pmc, 'deep structure comparison' )
 
 like( 'foo', 'f o**{2}', 'passing regex compare with diagnostic' )
+ .end
 
 =head1 DESCRIPTION
 



[PATCH 2/6] [t/library/Test::More] move skip test to be first

2007-03-13 Thread Sam Vilain
The tested output from test_skip() depends on the number of tests
that ran in the unrelated sections before it.  Tidy this up.
---

 t/library/test_more.t |   16 
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/t/library/test_more.t b/t/library/test_more.t
index 7baefd5..23576eb 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -33,12 +33,12 @@
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
plan( 47 )
+   test_skip()
test_ok()
test_is()
test_like()
test_is_deeply()
test_diagnostics()
-test_skip()
 
test.'finish'()
 .end
@@ -338,25 +338,25 @@
 .local pmc test
 test = new 'Test::Builder'
 
-   test_out( 'ok 43 #skip skipping' )
-   test_out( 'ok 44 #skip skipping' )
+   test_out( 'ok 1 #skip skipping' )
+   test_out( 'ok 2 #skip skipping' )
 test.'skip'( 2, 'skipping' )
test_test( 'skip test should pass' )
 
-   test_out( 'ok 45 #skip skipped' )
+   test_out( 'ok 3 #skip skipped' )
skip( 1 )
test_test( 'skip(int)' )
 
-   test_out( 'ok 46 #skip jumping' )
+   test_out( 'ok 4 #skip jumping' )
skip( "jumping" )
test_test( 'skip(string)' )
 
-   test_out( 'ok 47 #skip lunch' )
-   test_out( 'ok 48 #skip lunch' )
+   test_out( 'ok 5 #skip lunch' )
+   test_out( 'ok 6 #skip lunch' )
skip( 2, "lunch" )
test_test( 'skip(int, string)' )
 
-   test_out( 'ok 49 #skip skipped' )
+   test_out( 'ok 7 #skip skipped' )
skip()
test_test( 'skip()' )
 .end



[PATCH 1/6] [library] Test::More: use hllmacros.pir in man page example

2007-03-13 Thread Sam Vilain
Use current best practice for importing symbols in the example.
---
 runtime/parrot/library/Test/More.pir |   26 --
 1 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index 8441b25..51660ea 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -4,23 +4,20 @@ Test::More - Parrot extension for testing modules
 
 =head1 SYNOPSIS
 
+ .include "hllmacros.pir"
+
+ .sub main :main
 # load this library
 load_bytecode 'library/Test/More.pir'
 
-# get the testing functions
-.local pmc plan
-.local pmc diag
-.local pmc ok
-.local pmc is
-.local pmc is_deeply
-.local pmc like
-
-plan  = find_global 'Test::More', 'plan'
-diag  = find_global 'Test::More', 'diag'
-ok= find_global 'Test::More', 'ok'
-is= find_global 'Test::More', 'is'
-is_deeply = find_global 'Test::More', 'is_deeply'
-like  = find_global 'Test::More', 'like'
+# from hllmacros.pir
+.local pmc _
+.IMPORT( 'Test::More', 'plan', _ )
+.IMPORT( 'Test::More', 'diag', _ )
+.IMPORT( 'Test::More', 'ok', _ )
+.IMPORT( 'Test::More', 'is', _ )
+.IMPORT( 'Test::More', 'is_deeply', _ )
+.IMPORT( 'Test::More', 'like', _ )
 
 # set a test plan
 plan( 12 )
@@ -44,6 +41,7 @@ Test::More - Parrot extension for testing modules
 is_deeply( some_deep_pmc, another_deep_pmc, 'deep structure comparison' )
 
 like( 'foo', 'f o**{2}', 'passing regex compare with diagnostic' )
+ .end
 
 =head1 DESCRIPTION
 
-- 
1.5.0.759.g41ffe



[PATCH 2/6] [t/library/Test::More] move skip test to be first

2007-03-13 Thread Sam Vilain
The tested output from test_skip() depends on the number of tests
that ran in the unrelated sections before it.  Tidy this up.
---
 t/library/test_more.t |   16 
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/t/library/test_more.t b/t/library/test_more.t
index 7baefd5..23576eb 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -33,12 +33,12 @@
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
plan( 47 )
+   test_skip()
test_ok()
test_is()
test_like()
test_is_deeply()
test_diagnostics()
-test_skip()
 
test.'finish'()
 .end
@@ -338,25 +338,25 @@
 .local pmc test
 test = new 'Test::Builder'
 
-   test_out( 'ok 43 #skip skipping' )
-   test_out( 'ok 44 #skip skipping' )
+   test_out( 'ok 1 #skip skipping' )
+   test_out( 'ok 2 #skip skipping' )
 test.'skip'( 2, 'skipping' )
test_test( 'skip test should pass' )
 
-   test_out( 'ok 45 #skip skipped' )
+   test_out( 'ok 3 #skip skipped' )
skip( 1 )
test_test( 'skip(int)' )
 
-   test_out( 'ok 46 #skip jumping' )
+   test_out( 'ok 4 #skip jumping' )
skip( "jumping" )
test_test( 'skip(string)' )
 
-   test_out( 'ok 47 #skip lunch' )
-   test_out( 'ok 48 #skip lunch' )
+   test_out( 'ok 5 #skip lunch' )
+   test_out( 'ok 6 #skip lunch' )
skip( 2, "lunch" )
test_test( 'skip(int, string)' )
 
-   test_out( 'ok 49 #skip skipped' )
+   test_out( 'ok 7 #skip skipped' )
skip()
test_test( 'skip()' )
 .end
-- 
1.5.0.759.g41ffe



[PATCH 4/6] [library/Test::More] add isnt() to test inequality - ints only

2007-03-13 Thread Sam Vilain
refactor the is() :multi for integers into a _cmp_ok() function, and
then use that to provide is() and isnt()
---

 runtime/parrot/library/Test/More.pir |   53 --
 t/library/test_more.t|   16 ++
 2 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index fd297ab..dea010c 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -16,11 +16,12 @@ Test::More - Parrot extension for testing modules
 .IMPORT( 'Test::More', 'diag', _ )
 .IMPORT( 'Test::More', 'ok', _ )
 .IMPORT( 'Test::More', 'is', _ )
+.IMPORT( 'Test::More', 'isnt', _ )
 .IMPORT( 'Test::More', 'is_deeply', _ )
 .IMPORT( 'Test::More', 'like', _ )
 
 # set a test plan
-plan( 12 )
+plan( 13 )
 
 # run your tests
 ok( 1 )
@@ -28,6 +29,7 @@ Test::More - Parrot extension for testing modules
 
 is( 100, 100 )
 is( 200, 100, 'failing integer compare with diagnostic' )
+isnt( 200, 100, 'passing integer negative compare' )
 
 is( 1.001, 1.001, 'passing float compare with diagnostic' )
 is( 8.008, 4.004 )
@@ -148,22 +150,17 @@ add more.
 
 =cut
 
-.sub is :multi( int, int )
+.sub _cmp_ok :multi( int, int, pmc )
 .param intleft
 .param intright
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass   = 0
-
-if left == right goto pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -181,6 +178,22 @@ add more.
   done:
 .end
 
+.sub is :multi( int, int )
+.param intleft
+.param intright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_int"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_int
+.param intleft
+.param intright
+$I0 = iseq left, right
+.return($I0)
+.end
+
 .sub is :multi( float, float )
 .param float  left
 .param float  right
@@ -306,6 +319,28 @@ add more.
   done:
 .end
 
+=item C
+
+As C, but the test passes if the arguments I match.
+
+=cut
+
+.sub isnt :multi( int, int )
+.param intleft
+.param intright
+.param string description :optional
+.local pmc comp
+comp = find_name "_ne_int"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _ne_int
+.param intleft
+.param intright
+$I0 = isne left, right
+.return($I0)
+.end
+
 =item C
 
 Prints C to the screen, without affecting test comparisons.
diff --git a/t/library/test_more.t b/t/library/test_more.t
index 23576eb..4bc08b8 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -21,6 +21,7 @@
.local pmc import_sub
.IMPORT( 'Test::More', 'ok' )
.IMPORT( 'Test::More', 'is' )
+   .IMPORT( 'Test::More', 'isnt' )
.IMPORT( 'Test::More', 'diag' )
.IMPORT( 'Test::More', 'like' )
.IMPORT( 'Test::More', 'skip' )
@@ -32,13 +33,14 @@
.IMPORT( 'Test::Builder::Tester', 'test_pass' )
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
-   plan( 47 )
+   plan( 49 )
test_skip()
test_ok()
test_is()
test_like()
test_is_deeply()
test_diagnostics()
+   test_isnt()
 
test.'finish'()
 .end
@@ -360,3 +362,15 @@
skip()
test_test( 'skip()' )
 .end
+
+.sub test_isnt
+   test_fail()
+   isnt( 100, 100 )
+   test_diag( 'Received: 100' )
+   test_diag( 'Expected: 100' )
+   test_test( 'failing test isnt() for ints')
+
+   test_pass()
+   isnt( -100, 200 )
+   test_test( 'passing test isnt() for ints')
+.end



[PATCH 0/6] A round of updates to Test::More

2007-03-13 Thread Sam Vilain
This patch series extends the Test/More.pir library in various ways.

I'm sending it this way because it's trivial for me to do so, and
potentially makes the patches easier for the list to review.

Sam.


Re: [PATCH 1/6] [library] Test::More: use hllmacros.pir in man page example

2007-03-13 Thread Sam Vilain
Will Coleda wrote:
> FYI, all six patches were just opened as tickets.
>   

01:33 <@Coke> do me a favor. Forward each of them to RT and open a
ticket. HA!

I followed this instruction, "moments" before you forwarded them. Where
"moments" is a time period defined by the perl.org mailserver.

So,
41809 is a dup of 41803
41810 is a dup of 41804
41811 is a dup of 41805
41812 is a dup of 41807
41813 is a dup of 41806

The lower numbered ones are more up to date, though the only difference
is they have had the hllmacros.pir one removed from underneath them all
so should apply without any merging.

Sam.

* *
> I marked this on the ticket for 1/6 and it's closed out. the rest  
> await a ruling.
>   



Re: [perl #41818] [PATCH */4]: [t/op] add tests for string memory layout

2007-03-14 Thread Sam Vilain
Jerry Gay via RT wrote:
>> +.end
>> +
>> +#.constant STRINGINFO_STRSTART 2
>> +#.constant STRINGINFO_BUFLEN   3
>> +#.constant STRINGINFO_FLAGS4
>> +#.constant STRINGINFO_BUFUSED  5
>> +#.constant STRINGINFO_STRLEN   6
>>
>>  # Local Variables:
>>  #   mode: pir
>> --
>> 1.5.0.2.21.gdcde2
>>
>>
>> 
> this patch looks great, until the end. instead of manually defining
> your own constants, C<.include 'stringinfo.pasm'>--then they're
> defined for you. it's an easy fix, and can be done by the committer
> who applies this patch.
>   

Oh, sorry - those are actually comments.  They should be marked as a
TODO list for finishing the test.

Sam.


[PATCH] [library/Test::More] add isnt() to test inequality - str and float

2007-03-15 Thread Sam Vilain
Continue the previous factoring out of the comparison and
test function, by adding _cmp_ok() for other types
---
 runtime/parrot/library/Test/More.pir |  233 +++---
 t/library/test_more.t|   39 ++-
 2 files changed, 222 insertions(+), 50 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index dea010c..f9f6673 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -32,10 +32,12 @@ Test::More - Parrot extension for testing modules
 isnt( 200, 100, 'passing integer negative compare' )
 
 is( 1.001, 1.001, 'passing float compare with diagnostic' )
+isnt( 1.001, 1.001, 'failing float negative compare with diag' )
 is( 8.008, 4.004 )
 
 is( 'foo', 'foo', 'passing string compare with diagnostic' )
 is( 'foo', 'bar', 'failing string compare with diagnostic' )
+isnt( 'foo', 'bar', 'passing string negative compare with diag' )
 
 is( some_pmc, another_pmc, 'pmc comparison uses "eq" op' )
 
@@ -194,22 +196,17 @@ add more.
 .return($I0)
 .end
 
-.sub is :multi( float, float )
+.sub _cmp_ok :multi( float, float, pmc )
 .param float  left
 .param float  right
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
-
-eq left, right, pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -227,22 +224,46 @@ add more.
   done:
 .end
 
-.sub is :multi( string, string )
+.sub is :multi( float, float )
+.param floatleft
+.param floatright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_float"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_float
+.param floatleft
+.param floatright
+$I0 = 0
+if left == right goto pass_it
+
+   # XXX - significant places?  I don't care :)
+   .local float diff
+   diff = left - right
+   abs diff
+
+   if diff < 0.0001 goto pass_it
+
+   goto out
+pass_it:
+   $I0 = 1
+out:   
+.return($I0)
+.end
+
+.sub _cmp_ok :multi( string, string, pmc )
 .param string left
 .param string right
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
-
-eq left, right, pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -260,63 +281,128 @@ add more.
   done:
 .end
 
-.sub is :multi()
+.sub is :multi( string, string )
+.param stringleft
+.param stringright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_string"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_string
+.param stringleft
+.param stringright
+$I0 = iseq left, right
+.return($I0)
+.end
+
+.sub _ne_string
+.param stringleft
+.param stringright
+$I0 = isne left, right
+.return($I0)
+.end
+
+.sub _cmp_ok :multi()
 .param pmcleft
 .param pmcright
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass = 0
+pass = comp(left, right)
+
+  report:
+test.ok( pass, description )
+if pass goto done
+
+.local string diagnostic
+.local string l_string
+.local string r_string
+
+l_string= left
+r_string= right
+
+diagnostic = _make_diagnostic( l_string, r_string )
+test.diag( diagnostic )
+  done:
+.end
 
-   .local string r_type
-   r_type = typeof right
+.sub _is_or_isnt :multi()
+.param pmcleft
+.param pmcright
+.param string which
+.param string description :optional
 
-   if r_type == 'Float' goto num_compare
-   if r_type == 'Int'   goto num_compare
-   goto string_compare
+.local string func
+func = "_" . which
+func = func . "_"
 
-  num_compare:
+.local string r_type
+r_type = typeof right
+
+.local pmccomp
+if r_type == 'Float'  goto float_compare
+if r_type == 'Int'goto int_compare
+if r_type == 'String' goto string_compare
+goto object_compare
+
+  float_compare:
.local float l_val
.local float r_val
l_val = left
r_val = right
-
-if l_val == r_val goto pass_it
-
-   # XXX - significant places?  I don't care :)
-   .local float diff
-   diff = l_val - r_val
-
-   if diff < 0.0001 goto pass_it
+   func = func . "float"
+   comp = find_name func
+   say "# comparing floats"
+   _cmp_ok(l_val, r_val, comp, description)
+   goto out
 
   string_compare:
.local string l_val
.l

[PATCH] [t/library/Test::More] move skip test to be first

2007-03-15 Thread Sam Vilain
The tested output from test_skip() depends on the number of tests
that ran in the unrelated sections before it.  Tidy this up.
---
 t/library/test_more.t |   16 
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/t/library/test_more.t b/t/library/test_more.t
index 7baefd5..23576eb 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -33,12 +33,12 @@
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
plan( 47 )
+   test_skip()
test_ok()
test_is()
test_like()
test_is_deeply()
test_diagnostics()
-test_skip()
 
test.'finish'()
 .end
@@ -338,25 +338,25 @@
 .local pmc test
 test = new 'Test::Builder'
 
-   test_out( 'ok 43 #skip skipping' )
-   test_out( 'ok 44 #skip skipping' )
+   test_out( 'ok 1 #skip skipping' )
+   test_out( 'ok 2 #skip skipping' )
 test.'skip'( 2, 'skipping' )
test_test( 'skip test should pass' )
 
-   test_out( 'ok 45 #skip skipped' )
+   test_out( 'ok 3 #skip skipped' )
skip( 1 )
test_test( 'skip(int)' )
 
-   test_out( 'ok 46 #skip jumping' )
+   test_out( 'ok 4 #skip jumping' )
skip( "jumping" )
test_test( 'skip(string)' )
 
-   test_out( 'ok 47 #skip lunch' )
-   test_out( 'ok 48 #skip lunch' )
+   test_out( 'ok 5 #skip lunch' )
+   test_out( 'ok 6 #skip lunch' )
skip( 2, "lunch" )
test_test( 'skip(int, string)' )
 
-   test_out( 'ok 49 #skip skipped' )
+   test_out( 'ok 7 #skip skipped' )
skip()
test_test( 'skip()' )
 .end
-- 
1.5.0.759.g41ffe



[PATCH] [library] Test::More: use hllmacros.pir in man page example

2007-03-15 Thread Sam Vilain
From: Sam Vilain <[EMAIL PROTECTED]>

Use current best practice for importing symbols in the example.
---
 runtime/parrot/library/Test/More.pir |   26 --
 1 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index 8441b25..51660ea 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -4,23 +4,20 @@ Test::More - Parrot extension for testing modules
 
 =head1 SYNOPSIS
 
+ .include "hllmacros.pir"
+
+ .sub main :main
 # load this library
 load_bytecode 'library/Test/More.pir'
 
-# get the testing functions
-.local pmc plan
-.local pmc diag
-.local pmc ok
-.local pmc is
-.local pmc is_deeply
-.local pmc like
-
-plan  = find_global 'Test::More', 'plan'
-diag  = find_global 'Test::More', 'diag'
-ok= find_global 'Test::More', 'ok'
-is= find_global 'Test::More', 'is'
-is_deeply = find_global 'Test::More', 'is_deeply'
-like  = find_global 'Test::More', 'like'
+# from hllmacros.pir
+.local pmc _
+.IMPORT( 'Test::More', 'plan', _ )
+.IMPORT( 'Test::More', 'diag', _ )
+.IMPORT( 'Test::More', 'ok', _ )
+.IMPORT( 'Test::More', 'is', _ )
+.IMPORT( 'Test::More', 'is_deeply', _ )
+.IMPORT( 'Test::More', 'like', _ )
 
 # set a test plan
 plan( 12 )
@@ -44,6 +41,7 @@ Test::More - Parrot extension for testing modules
 is_deeply( some_deep_pmc, another_deep_pmc, 'deep structure comparison' )
 
 like( 'foo', 'f o**{2}', 'passing regex compare with diagnostic' )
+ .end
 
 =head1 DESCRIPTION
 
-- 
1.5.0.759.g41ffe



[PATCH] [lib/Test::More] base comparison type on expected, not received PMC type

2007-03-15 Thread Sam Vilain
The type of the 'left' argument was being used for the selection
of which comparison function to use.  This does not agree with the
typical usage of the second argument to is() to mean the expected
value (as in English).
---
 runtime/parrot/library/Test/More.pir |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index 51660ea..fd297ab 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -258,11 +258,11 @@ add more.
 .local int pass
 pass = 0
 
-   .local string l_type
-   l_type = typeof left
+   .local string r_type
+   r_type = typeof right
 
-   if l_type == 'Float' goto num_compare
-   if l_type == 'Int'   goto num_compare
+   if r_type == 'Float' goto num_compare
+   if r_type == 'Int'   goto num_compare
goto string_compare
 
   num_compare:
-- 
1.5.0.759.g41ffe



[PATCH] [library/Test::More] add isnt() to test inequality - ints only

2007-03-15 Thread Sam Vilain
refactor the is() :multi for integers into a _cmp_ok() function, and
then use that to provide is() and isnt()
---
 runtime/parrot/library/Test/More.pir |   53 --
 t/library/test_more.t|   16 +-
 2 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index fd297ab..dea010c 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -16,11 +16,12 @@ Test::More - Parrot extension for testing modules
 .IMPORT( 'Test::More', 'diag', _ )
 .IMPORT( 'Test::More', 'ok', _ )
 .IMPORT( 'Test::More', 'is', _ )
+.IMPORT( 'Test::More', 'isnt', _ )
 .IMPORT( 'Test::More', 'is_deeply', _ )
 .IMPORT( 'Test::More', 'like', _ )
 
 # set a test plan
-plan( 12 )
+plan( 13 )
 
 # run your tests
 ok( 1 )
@@ -28,6 +29,7 @@ Test::More - Parrot extension for testing modules
 
 is( 100, 100 )
 is( 200, 100, 'failing integer compare with diagnostic' )
+isnt( 200, 100, 'passing integer negative compare' )
 
 is( 1.001, 1.001, 'passing float compare with diagnostic' )
 is( 8.008, 4.004 )
@@ -148,22 +150,17 @@ add more.
 
 =cut
 
-.sub is :multi( int, int )
+.sub _cmp_ok :multi( int, int, pmc )
 .param intleft
 .param intright
+.param pmccomp
 .param string description :optional
 
 .local pmc test
 find_global test, 'Test::More', '_test'
 
 .local int pass
-pass   = 0
-
-if left == right goto pass_it
-goto report
-
-  pass_it:
-pass = 1
+pass = comp(left, right)
 
   report:
 test.ok( pass, description )
@@ -181,6 +178,22 @@ add more.
   done:
 .end
 
+.sub is :multi( int, int )
+.param intleft
+.param intright
+.param string description :optional
+.local pmc comp
+comp = find_name "_eq_int"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _eq_int
+.param intleft
+.param intright
+$I0 = iseq left, right
+.return($I0)
+.end
+
 .sub is :multi( float, float )
 .param float  left
 .param float  right
@@ -306,6 +319,28 @@ add more.
   done:
 .end
 
+=item C
+
+As C, but the test passes if the arguments I match.
+
+=cut
+
+.sub isnt :multi( int, int )
+.param intleft
+.param intright
+.param string description :optional
+.local pmc comp
+comp = find_name "_ne_int"
+_cmp_ok(left,right,comp,description)
+.end
+
+.sub _ne_int
+.param intleft
+.param intright
+$I0 = isne left, right
+.return($I0)
+.end
+
 =item C
 
 Prints C to the screen, without affecting test comparisons.
diff --git a/t/library/test_more.t b/t/library/test_more.t
index 23576eb..4bc08b8 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -21,6 +21,7 @@
.local pmc import_sub
.IMPORT( 'Test::More', 'ok' )
.IMPORT( 'Test::More', 'is' )
+   .IMPORT( 'Test::More', 'isnt' )
.IMPORT( 'Test::More', 'diag' )
.IMPORT( 'Test::More', 'like' )
.IMPORT( 'Test::More', 'skip' )
@@ -32,13 +33,14 @@
.IMPORT( 'Test::Builder::Tester', 'test_pass' )
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
-   plan( 47 )
+   plan( 49 )
test_skip()
test_ok()
test_is()
test_like()
test_is_deeply()
test_diagnostics()
+   test_isnt()
 
test.'finish'()
 .end
@@ -360,3 +362,15 @@
skip()
test_test( 'skip()' )
 .end
+
+.sub test_isnt
+   test_fail()
+   isnt( 100, 100 )
+   test_diag( 'Received: 100' )
+   test_diag( 'Expected: 100' )
+   test_test( 'failing test isnt() for ints')
+
+   test_pass()
+   isnt( -100, 200 )
+   test_test( 'passing test isnt() for ints')
+.end
-- 
1.5.0.759.g41ffe



[PATCH] [lib] Test::More - add isa_ok()

2007-03-15 Thread Sam Vilain
---
 runtime/parrot/library/Test/More.pir |   80 ++
 t/library/test_more.t|   38 -
 2 files changed, 117 insertions(+), 1 deletions(-)

diff --git a/runtime/parrot/library/Test/More.pir 
b/runtime/parrot/library/Test/More.pir
index f9f6673..7a1d18d 100644
--- a/runtime/parrot/library/Test/More.pir
+++ b/runtime/parrot/library/Test/More.pir
@@ -19,6 +19,7 @@ Test::More - Parrot extension for testing modules
 .IMPORT( 'Test::More', 'isnt', _ )
 .IMPORT( 'Test::More', 'is_deeply', _ )
 .IMPORT( 'Test::More', 'like', _ )
+.IMPORT( 'Test::More', 'isa_ok', _ )
 
 # set a test plan
 plan( 13 )
@@ -47,6 +48,11 @@ Test::More - Parrot extension for testing modules
 like( 'foo', 'f o**{2}', 'passing regex compare with diagnostic' )
  .end
 
+$P0 = getclass "Moose"
+$P0.new()
+
+isa_ok($P0, "Moose", "new Moose")
+
 =head1 DESCRIPTION
 
 C is a pure-Parrot library for testing modules.  It provides
@@ -943,6 +949,80 @@ actually skipped.  Arguments are optional.
 test.'skip'()
 .end
 
+=item C
+
+Pass if the pmc passed "isa" class.  The "name" passed in is a
+description of what it is you've passed in, not a comment.  It is
+presented as "name isa class" in the description.
+
+Good input: "C", "C"
+
+Bad input: "C"
+
+=cut
+
+.sub isa_ok :multi(pmc, string)
+.param pmc thingy
+.param string class_name
+.param string name :optional
+.param int got_name :opt_flag
+
+.local pmc test
+find_global test, 'Test::More', '_test'
+
+.local string _name
+_name = name
+if got_name goto great
+_name = "object"
+great: 
+$S0 = _name . " isa "
+$S0 = $S0 . class_name
+
+$I0 = isa thingy, class_name
+test.'ok'($I0, $S0)
+if $I0 goto out
+_isa_ok_diag(test, class_name, _name, thingy)
+out:   
+.end
+
+.sub isa_ok :multi(pmc, pmc)
+.param pmc thingy
+.param pmc class
+.param string name :optional
+.param int got_name :opt_flag
+
+.local pmc test
+find_global test, 'Test::More', '_test'
+
+.local string _name, class_name
+_name = name
+if got_name goto great
+_name = "object"
+great: 
+$S0 = _name . " isa "
+class_name = classname class
+$S0 = $S0 . class_name
+
+$I0 = isa thingy, class
+test.'ok'($I0, $S0)
+if $I0 goto out
+_isa_ok_diag(test, class_name, _name, thingy)
+out:   
+.end
+
+.sub _isa_ok_diag
+.param pmc test
+.param string class_name
+.param string name
+.param pmc thingy
+$S0 = name . " isn't a "
+$S0 = $S0 . class_name
+$S0 = $S0 . " it's a "
+$S1 = typeof thingy
+$S0 = $S0 . $S1
+test.'diag'($S0)
+.end
+
 .sub _make_diagnostic
 .param string received
 .param string expected
diff --git a/t/library/test_more.t b/t/library/test_more.t
index b7aa317..17b0671 100644
--- a/t/library/test_more.t
+++ b/t/library/test_more.t
@@ -26,6 +26,7 @@
.IMPORT( 'Test::More', 'like' )
.IMPORT( 'Test::More', 'skip' )
.IMPORT( 'Test::More', 'is_deeply' )
+   .IMPORT( 'Test::More', 'isa_ok' )
.IMPORT( 'Test::Builder::Tester', 'plan' )
.IMPORT( 'Test::Builder::Tester', 'test_out' )
.IMPORT( 'Test::Builder::Tester', 'test_diag' )
@@ -33,7 +34,7 @@
.IMPORT( 'Test::Builder::Tester', 'test_pass' )
.IMPORT( 'Test::Builder::Tester', 'test_test' )
 
-   plan( 55 )
+   plan( 60 )
test_skip()
test_ok()
test_is()
@@ -41,6 +42,7 @@
test_is_deeply()
test_diagnostics()
test_isnt()
+   test_isa_ok()
 
test.'finish'()
 .end
@@ -411,3 +413,37 @@
 

 .end
+
+.sub test_isa_ok
+   .local pmc dog, terrier, daschund, Spot, Sossy
+
+   dog = newclass "dog"
+   terrier = subclass dog, "terrier"
+   daschund = subclass dog, "daschund"
+
+   Spot = new "terrier"
+   Sossy = new "daschund"
+
+   test_pass( 'Spot isa terrier' )
+   isa_ok(Spot, "terrier", "Spot")
+   test_test( 'passing isa_ok for PMC/string (class =)' )
+
+   test_pass( 'Spot isa dog' )
+   isa_ok(Spot, "dog", "Spot")
+   test_test( 'passing isa_ok for PMC/string (super)')
+
+   test_pass( 'Sossy isa daschund' )
+   isa_ok(Sossy, "daschund", "Sossy")
+   test_test( 'passing isa_ok for PMC/PMC (class =)' )
+
+   test_pass( 'Sossy isa dog' )
+   isa_ok(Sossy, "dog", "Sossy")
+   test_test( 'passing isa_ok for PMC/PMC (super)')
+
+   test_fail( 'Spot isa daschund' )
+test_diag( "Spot isn't a daschund it's a terrier" )
+   isa_ok(Spot, 'daschund', "Spot")
+   test_test( 'failing test isnt() for PMC/string')
+   
+.end
+
-- 
1.5.0.759.g41ffe



Re: [PRE-RELEASE] Release of 0.0.7 tomorrow evening

2002-07-22 Thread Sam Vilain

"Sean O'Rourke" <[EMAIL PROTECTED]> wrote:

> languages/perl6/README sort of hides it, but it does say that "If you have
> Perl <= 5.005_03, "$a += 3" may fail to parse."  I guess we can upgrade
> that to "if you have < 5.6, you lose".

I notice that DBI no longer supports Perl releases <5.6.  Seems enough
people are happy that 5.005 is obsolete.
--
   Sam Vilain, [EMAIL PROTECTED] WWW: http://sam.vilain.net/
7D74 2A09 B2D3 C30F F78E  GPG: http://sam.vilain.net/sam.asc
278A A425 30A9 05B5 2F13

  I regret to say that we of the FBI are powerless to act in cases of
oral-genital intimacy, unless it has in some way obstructed interstate
commerce.
J EDGAR HOOVER



Re: S29: punt [pwned!]

2005-05-12 Thread Sam Vilain
Rod Adams wrote:
It looks like I'm going to have to punt on finishing S29.
On behalf of pugs committers, we will gladly adopt this task, which is in
the pugs repository already at docs/S29draft.pod, as well as having a set
of foundation classes that correspond to all these object methods in
docs/src/ (of course, most of the actual code is in src/Pugs/Prim.hs etc)
I'm finding myself in a perpetual state of either no time to work on it, 
or when there is time, having insufficient brain power left to properly 
assimilate everything that needs to be considered to do any of the 
functions justice. Looking ahead, I do not see this state changing for 
the better in the foreseeable future.
Drop the feeling of guilt for not having written enough and it will already
be better.  Thanks for what you have done, it is an outstanding achievement!
It's my hope that someone none(@Larry) can and will pick this effort up. 
I will give whatever assistance I can to anyone choosing to do so. Drop 
me a line.
If you could make sure your last revision corresponds to what is in the
pugs repository, that will be more than enough...
Sam.


Re: Quick question: '1.28' * '2.56'

2005-05-17 Thread Sam Vilain
Rob Kinyon wrote:
If that's the case, then if I change a variable that isa Str (that isa
Num), does it change what it inherits from?
Please don't use "inherits" when talking about these core types.  Classical
inheritance just doesn't work with the varied sets of numbers.  All those
stories you were told about Classical Inheritance being able to describe any
problem were naïve lies.  Roles-based inheritance (or Traits-based if you
like Smalltalk, or Haskell's Classes) is a superset of classical inheritance.
In fact it seems reasonable to me at this point in time that a Perl 6 Class
is a subtype of a Role.  The distinctions seem minor enough not to matter.
See also http://svn.openfoundry.org/pugs/docs/src/number-types.png
Sam.


Re: Quick question: '1.28' * '2.56'

2005-05-17 Thread Sam Vilain
Larry Wall wrote:
: pugs> '1.28' * '2.56'
: 3.2768
: What is (or should be) going on here here?
: [1] role NumRole {
:   method infix:<*> returns Num (NumRole $x, NumRole $y: ) { ... }
: }
: Str.does(NumRole);
: [3] multi sub prefix:<+> (Str $x) returns Num { ... }
: multi sub infix:<*> (Num $x, Num $y) returns Num { ... }
: multi sub infix:<*> (Any $x, Any $y) returns Num { +$x * +$y }
I tend to think of it most like [3], but it's possible that it's the
same as [1] if the role is supplying the coercion assumed in [3].
I like #3, because it doesn't have any nasty implications to the type
calculus.
I don't really have the theoretical or practical knowledge to really be
able to back this up, but I have a strong hunch that value-based type
shifting is the type system equivalent of $&.
Sam.


Re: Default precedence level of user defined infix ops

2005-05-18 Thread Sam Vilain
Luke Palmer wrote:
And how do I explicitly define the precedence?
Using the `tighter`, `looser`, and `equiv` traits.  You specify
precedence in terms of the precedence of other existing ops.
sub infix:<.>(&f, &g) is looser(&infix:<+>) {...}
This is interesting.  So, infix:< > is similar to Haskell's
() circumfix operator, like ((+) 1 2) â (1 + 2).
Which method does &infix:<+> refer to, if you have;
 multi sub infix:<+>(Num $i, Num $j) { $i.add($j) }
 multi sub infix:<+>(Set $i, Set $j) { $i.union($j) }
?
Are these automatically locked to the same level, in fact, does it
make sense for any 'operator' (ie, the sub's short name) to exist
in multiple precedence levels at once?
Or is it simply a major ParseF*** to have to determine precedence
/after/ determining types of operands?
Sam.


Re: reduce metaoperator on an empty list

2005-05-19 Thread Sam Vilain
Edward Cherlin wrote:
Here is the last answer from Ken Iverson, who invented reduce in 
the 1950s, and died recently.
file:///usr/share/j504/system/extras/help/dictionary/intro28.htm
  [snip]
Thanks for bringing in a little history to the discussion.  Those links
are all local to your system; do you have internet reachable versions of them?
Cheers,
Sam.


Re: reduce metaoperator on an empty list

2005-05-19 Thread Sam Vilain
Stuart Cook wrote:
In Haskell, there is a distinction between foldl and foldl1 (similar
remarks apply to foldr/foldr1[1]):
The former (foldl) requires you to give an explicit 'left unit'[2],
which is implicitly added to the left of the list being reduced. This
means that folding an empty list will just give you the unit.
i.e.
foldl (+) 0 [a,b,c] = ((0+a)+b)+c
foldl (+) 0 [] = 0
The latter (foldl1) doesn't use a unit value, but this means that you
can't fold empty lists.
i.e.
foldl1 (+) [a,b,c] = (a+b)+c
foldl1 (+) [] = ***error***
sure.  Maybe the identity values could be supplied by making the reduce 
operator
for them a curried version of reduce, where reduce requires a list with at least
one element (or DIES :))
eg, something similar to; (sorry for the psuedo-perl6, corrections welcome :))
  sub prefix:<[+]> ([EMAIL PROTECTED]) ::= &reduce.assuming(func => &infix:<+>, 
first => 0);
  sub prefix:<[*]> ([EMAIL PROTECTED]) ::= &reduce.assuming(func => &infix:<*>, 
first => 1);
This would mean that unless the operator specifically defines a curried reduce
version of itself, then the [] version of it on an empty list will be a hard 
run-time
error.
Then again, maybe an identity trait is more elegant and covers the varied ways
that multiple operators combine inside reduce..
> You /could/ try to do something 'sensible' and return 0 or undef, but
> this seems likely to result in more confusion.
Personally I think returning an undef for this kind of situation would be as 
wrong
as returning undef for 0/0.
Sam.


Re: Complex Arithmetic

2005-05-19 Thread Sam Vilain
Edward Cherlin wrote:
There was a discussion of the principal value of square root on 
this list some time back, making the point that for positive 
   [...]
It turns out that the domain and range and the location of the 
cut lines have to be worked out separately for different 
functions. Mathematical practice is not entirely consistent in 
making these decisions, but in programming, there seems to be 
widespread agreement that the shared definitions used in the 
APL, Common LISP, and Ada standards are the best available.
Do we want to get into all of this in Perl6?
pugs currently has "Complex" as a built-in type, though it isn't explicitly
listed in S06.  I can't see any tests for them yet, though.
So, testing the Complex number functionality as well as detailed
exploration of the corner cases, and alignment with best practice will
surely be appreciated by people looking at doing Complex math in Perl 6.
I think this applies regardless of whether it ends up a "core" type
(whatever that means) or not.  Personally I don't think that Complex numbers
are so bizarre an entity that you wouldn't want sqrt(-1) to return one
out of the box.
It's likely that very little implementation changes will need to be done,
as no doubt the mathematically minded folk that write GHC will have been
through that before.  But it will be invaluable in testing compliance of
the different run-time engines.
I suggest you come to the IRC channel at #perl6 on irc.freenode.net, and
ask for a committer account.
Sam.


Re: [S29] uniq

2005-05-19 Thread Sam Vilain
Mark Overmeer wrote:
'uniq' differs from 'sort' because there is no order relationship between
the elements.  A quick algorithm for finding the unique elements in perl5
is
   sub uniq(@)
   {  my %h = map { ($_ => 1) } @elements;
  keys %h;
   }
...and an even quicker one is:
 use Set::Object;
 sub uniq(@)
 {
 set(@_)->members;
 }
or
 use v6;
 use Set;
 sub uniq([EMAIL PROTECTED])
 {
 set(@items).members;
 }
Sam.


Junctive and Higher order Types

2005-05-19 Thread Sam Vilain
Hi all,
While trying to convert Haskell statements like this to Perl 6:
 data Cxt = CxtVoid -- ^ Context that isn't expecting any values
  | CxtItem !Type   -- ^ Context expecting a value of the specified type
  | CxtSlurpy !Type -- ^ Context expecting multiple values of the
-- specified type
 deriving (Eq, Show, Ord)
I'd like to be able to write it something like this:
 type Cxt is CxtVoid
   | CxtItem of Type
   | CxtSlurpy of Type
  does (Eq, Show, Ord);
To be a shorthand for:
 type CxtVoid;
 type CxtItem of Type;
 type CxtSlurpy of Type;
 type Perl::Cxt is CxtVoid | CxtItem | CxtSlurpy
does Eq does Show does Ord;
Is this overloading the 'of' operator too far?
For many there will be a lot of new concepts there.  For a start, I'm assuming that "of" is being used as a higher order type 
definition, much like "Array of Wotsits" would declare.  Also, there is a type there - CxtVoid - which is nothing but a Type!  No 
representation.  Of course, if you have a variable of type Cxt, and it is a CxtVoid, then that will need to be represented in some 
way.  But you generally wouldn't care how.

An alternative might be to try to shoe-horn the concepts into Roles etc.  Who 
knows, perhaps they'll even fit!  :-)
Sam.


Re: Sets

2005-05-26 Thread Sam Vilain

Patrick R. Michaud wrote:
> The continuing exchanges regarding junctions, and the ongoing tendency
> by newcomers to think of them and try to use them as sets, makes
> me feel that it might be worthwhile to define and publish a standard
> C class and operations sooner rather than later in Perl 6

I agree.  See pugs/ext/Set.

It presents a set-like interface to Junctions.

eg,

  use Set;

  my $low = set( 0..4 );
  my $odd = set( (0..4).map:{ $_ * 2 + 1 } );

  say ($low ∩ $odd).members.join(",");  # 1,3
  say ($low ∪ $odd).members.join(",");  # 0,1,2,3,4,5,7,9

  # difference - not this is not a backslash, it's U+2216
  say ($low ∖ $odd).members.join(",");  # 0,2,4
  say ($odd ∖ $low).members.join(",");  # 5,7,9

  # symmetric difference - union of the above
  say ($low % $odd).members.join(",");  # 0,2,4,5,7,9

  # test for membership
  say $low ∋ 4;   # true
  say $low ∌ 5;   # true
  say $odd ∋ 4;   # false
  say $odd ∌ 5;   # false

  # set relations
  say ( $low ∪ $odd ) ⊇ $low;   # true

Well, actually the above doesn't work yet.  But there are ASCII versions
and english methods for those that like coding something that actually
works today ;).

Here's a directed graph traversal that handle cycles correctly; this is
largely why I'd like to see a common Role to all containers... so that
.values can be expected to DTRT.  OTOH, maybe Maps with object keys would
"miss out" in this algorithm so another method name is more appropriate.

  use Set;
  my @stack = ($root);
  my $seen = set(@stack);

  while (my $item = shift @stack) {
  # do something with $item

  if $item.can("values") {
  push @stack, $item.values.grep:{ $seen.insert($_) };
  }
  }

Caveats for the above probably abound, but you get the picture.

Note that the Set::Object module for Perl 5 is useful for the same thing
(assumes that $root is a ref):

  use Set::Object qw(set);
  use Scalar::Util qw(reftype blessed);
  use Perl6::Junction qw(any);
  my @stack = ($root);
  my $seen = set(@stack);

  while (my $item = shift @stack) {
  # do something with $item

  if (blessed $item and $item->can("members")) {
  push @stack, grep { ref $_ && $seen->insert($_) } $item->members;
  }
  if (reftype $item eq "HASH") {
  push @stack, grep { ref $_ && $seen->insert($_) } values %$item;
  }
  elsif (reftype $item eq "ARRAY") {
  push @stack, grep { ref $_ && $seen->insert($_) } @$item;
  }
  elsif (reftype $item eq any(qw(REF SCALAR)) ) {
  push @stack, $$item if $seen->insert($$item);
  }
  }

As you can see, this sort of thing ends up an anti-design pattern.

Sam.


Re: function signatures?

2005-05-29 Thread Sam Vilain

Ingo Blechschmidt wrote:

Are signatures going to be an exposed first class object in Perl 6?

I hope so, too.
  ~&foo.signature;
  # Signature objects should stringify to a canonized form, e.g.:
  # ~sub (Str $bar, CoolClass $z where {...}) {...}.signature ==>
  # 'Str $bar, ANONCLASS(0xDEADBEEF)'
  # (BTW, I don't think it's possible to display anonymous subtypes more
  # friendly, as the where-clause may contain arbitrary code, and Code
  # objects are not (yet?) fully introspectable -- i.e.
  # &foo.statements[3].line doesn't work.)

  +&foo.signature.required_args;
  # Number of required args
  &foo.signature.required_args;
  # Hash name -> class

  &foo.signature.positional_args;
  &foo.signature.named_args;
  # etc.
Thoughts?


Translations of the corresponding Pugs types into Perl 6 code is at:

  ext/Perl-MetaModel/lib/Pugs/VCode.pm

However they are mostly still sketches.  If you have specific ideas about
the Code::Signature signature in Pure Perl terms, place it in;

  ext/Perl-MetaModel/lib/Code/Signature.pm

These objects will eventually be what you get from &foo.meta, etc.  Or at
least I assume that the way to get to the object's signature will be .meta.
Maybe the "Code" class will define a ".signature" method as an alternative
to .meta.signature.

Sam.


Re: Strongly typed containers?

2005-05-30 Thread Sam Vilain

Yuval Kogman wrote:
> We already have the Set class, how do we say what it contains?
> class Set {
>has $.type;
>method members returns $.type () { ... }
> }
> my Set of Int $s = Set.new; # is this how you call it?

You are describing "Higher Order" types, also called Generic Algebraic Data 
Types (GADTs) in Haskell.

Please refer to the earlier discussions

 Parts 1 and 2 of http://xrl.us/f9re

I also started a similar post on a related note that was "warnocked", though the post was more to demonstrate an apparent syntax 
isomorphism between Haskell and Perl 6 than posing a particular question (probably why it was unanswered).


  http://xrl.us/f9rg

I think there has probably been other discussions, including one where Autrijus specifically asked this question for the Set module, 
but I can't find that one.


Sam.


Re: Unicode Operators cheatsheet, please!

2005-05-31 Thread Sam Vilain

Rob Kinyon wrote:

I would love to see a document (one per editor) that describes the
Unicode characters in use and how to make them. The Set implementation
in Pugs uses (at last count) 20 different Unicode characters as
operators.


I have updated the unicode quickref, and started a Perlmonks discussion node
for this to be explored - see http://www.perlmonks.org/index.pl?node_id=462246

Sam.


Re: date and time formatting

2005-05-31 Thread Sam Vilain

Rob Kinyon wrote:

What I'm trying to get at isn't that DateTime's API should be
preserved. I'm saying that the concept of DateTime should be ported.
Core or not core - it doesn't matter. When use'd (or installed), it
should override now() (and anyone else we can think of) to return an
object that DWIMs, plus provides the interface you've outlined below.


I've made a start on this.  See ext/Date in pugs.  I don't think that
your views are necessarily contrary.

The biggest reason I didn't use DateTime was that I found it awkward
for the common case; most of the time I just want to stuff in an
ISO8601 date.  I also don't like implicit normalisation to seconds
underneath the hood when I'm doing basic date calculations, and
the way that the "DateTime" base class is inherantly based on the
Gregorian calendar.

The "Date" and "Duration" roles are extremely minimal; see

   http://svn.openfoundry.org/pugs/ext/Date/lib/Date.pm
   http://svn.openfoundry.org/pugs/ext/Date/lib/Duration.pm

The major API is described at:

   http://svn.openfoundry.org/pugs/ext/Date/lib/Date/Gregorian.pod

This module is supposed to be somewhere between DateTime and
Class::Date, with built-in ISO-8601 support (as it's the standard ;)).

With a bit of luck, all Date implementation can share this `Date'
Role, and Gregorian calendar modules share the `Date::Gregorian' Role,
so that the multitude of implementations that crop up will be mutually
exchangable, and the simple case fast, efficient and useful.

Sam.


Re: "returns" and context

2005-05-31 Thread Sam Vilain

Rod Adams wrote:

How do I specify the signature of a context-sensitive function?
sub foo() returns (what?) {
return want ~~ Scalar ?? cheap_integer_result :: List_of_Sheep;
}

I suspect a typed junction would look like : "Junction of Int|Str".


Not quite.  AIUI that means a Junction of which the members are Int or Str.

This is how I've been writing it:

  sub foo() returns Scalar|List {
  return want ~~ Scalar ?? cheap_integer_result :: List_of_Sheep;
  }

I think the default return type of unlabeled subs would be:

  returns Void|Scalar|List

but of course $?SELF =:= none(@Larry) ;)

Sam.


Software Transactional Memory interaction with Garbage Collection

2005-06-03 Thread Sam Vilain

Hi all,

While I must start this post out by saying that I've never implemented 
either STM or a garbage collector, during a discussion on #parrot (is 
that channel logged?), a similarity between the two processes occurred 
to me.


Would this be an adequate expression of a generational Garbage 
Collector, in terms of STM;


  1. start transaction for a memory region / "incubator"

  2. gather a set of objects for "update" (giving you a "consistent
 read" copy of them).

  3. commit memory transaction.  The consistent read copy becomes the
 master, and the old incubator is reaped.

There is the gaping gap in the above about how you know which objects to 
gather, of course.


I'm just thinking it would be "nice" if the implementation for these two 
 advanced technologies could share the same basic memory transaction 
API, to get two elusive birds with one stone.


Sam.


Re: What the heck is... wrong with Parrot development?

2005-06-06 Thread Sam Vilain

Fagyal Csongor wrote:
With all respect, I think this is a very important thing which needs 
attention, and I hope that you will help us to clarify the situation. I 
am pretty sure Dan did not leave because he had a bad day - we know he 


Dan's position was very stressful, he had people from all sides trying to
tear him down, even though many were also propping him up and he has a
great level of skill.

However, to altercate on the hows and whys of his action is premature; I
suggest a moratorium on such debate for at least as long as he was the
project leader, for correct perspective.

Please honour his decision to bow out gracefully without turning it into
a childish battle of egos.

In the meantime let us celebrate 5 years of Dan Sugalski's contribution
to the Parrot and Perl 6 project.

Three cheers for Dan!

Sam.


Re: reduce metaoperator on an empty list

2005-06-06 Thread Sam Vilain

Roger Hale wrote:
This is why I would rather the o -> [o] circumfixion left [o] an infix, 
not prefix operator.  I would rather be explicit about my identity:

$product = 1 [*] @array;


Hmm.  Not all operators *have* an identity.

You'd have to write, in that case;

  @array[0] [ƒ] @[EMAIL PROTECTED]

Which isn't great IMHO.

Sam.


Re: reduce metaoperator on an empty list

2005-06-06 Thread Sam Vilain

Damian Conway wrote:

What you want is:
$product = ([*] @values err 0);
Or:
$factorial = ([*] 1..$n err 1);


The "err" operator bind only to the point on the instruction it is
attached to, ie it's not a shortcut for eval(), right?

I'm just seeing some edge cases here for custom defined operators; you
don't want exceptions getting silently converted to default values...

Sam.


Re: New generational GC Scheme

2005-06-08 Thread Sam Vilain

Alexandre Buisse wrote:

So we add a level of indirection: objects consist of a header and the
actual data. Headers are allocated once and for all at object creation
and do not move. [...]
The big disadvantage of this approach is that we use one or two words
(if objects need to know where their header is, which seems
reasonable) per object.


AIUI, another effect of adding another indirection to every pointer lookup,
is that it will place a little extra stress on the memory caching systems,
as two regions will need to be accessed continually.

Sam.


Re: reduce metaoperator on an empty list

2005-06-07 Thread Sam Vilain

Luke Palmer wrote:

< and > still don't make sense as reduce operators.  Observe the table:
# of args   |   Return (type)
0   |   -Inf
1   |   Num  (the argument)
2   |   bool
... |   bool


Let's look at the type of one of the many `reduce' variants in Haskell;

  foldr1 :: (a -> a -> a) -> [a] -> a

This is the Perl6ish;

  sub reduce( ::Code{( ::(someType), ::(someType) ) returns ::(someType)} $func,
  Array of ::(someType) ) returns ::(someType);

ie, the function $func supplied must take and return arguments of a single
type.  So you have come to the same conclusion as the FP folk :-).

Here I'm using ::(foo) as a coined syntax for a parametric type to the
definition.  `someType' need not be defined anywhere else, but must be
the same within the application of a definition.

IMHO we still need to make some movements towards a specification for how
this sort of thing is specified...

>  I just think we have to give
> nonhomogeneous operators like < some special treatment.  So, from our
> somewhat lexical definition of reduce, I don't think an identity input
> is what we're looking for.  We really want an identity output.

When I last looked, in pugs, functions that return "bool" types are
currently setup to return one or the other argument when used with reduce;
like there is a similar;

  multi
  sub reduce( ::{Code( ::(someType) $a, ::(someType) $b ) returns bool} $func,
  Array of ::(someType) ) returns ::(someType);

This gives meaning to operators like [>], which would return the maximum
value from a list.

Sam.


Re: reduce metaoperator on an empty list

2005-06-09 Thread Sam Vilain

TSa (Thomas Sandlaß) wrote:

I'm not sure but Perl6 could do better or at least trickier ;)
Let's assume that < > <= >= when chained return an accumulated
boolean and the least or greatest value where the condition was
true. E.g.
  0 < 2 < 3   returns  0 but true
  1 < 2 < 1   returns  1 but false
  4 < 5 < 2   returns  2 but false


An interesting idea, but seems a bit heavy..


Is it correct that [min] won't parse unless min is declared
as an infix op, which looks a bit strange?
if 3 min 4 { ... }


Sure.  Again there is a Haskell example to heed closely here; for instance, the 
function:

   divMod :: (Integral a) => a -> a -> (a, a)

Can be written as either;

   divMod 42 9

or:

   42 `divMod` 9

The reverse direction is ();

   (+) :: (Num a) => a -> a -> a

   (+) 7 5

   7 + 5

Sam.


AUTLOAD and $_

2005-06-19 Thread Sam Vilain

From S10;

  In any case, there is no longer any magical $AUTOLOAD variable. The
  name being declared or defined can be found in $_ instead. The name
  does not include the package name. You can always get your own package
  name with $?PACKAGENAME.

So, what is the prototype of AUTOLOAD?  It is clearly called from the
relevant (package dispatcher & type & perl5_compat(stash) ) object, but
how?

 sub AUTOLOAD($_ = $CALLER::$_, [EMAIL PROTECTED]) {
 ...
 }

In a way, $_ forms part of the prototype definition, but is "out of band"
to the regular arguments on @_; it can't interfere with positional
characteristics, or you have to "shift" it off before you goto the right
sub.

OK, we could play tricks with localization of variables, but in the face
of continuations and coroutines, localization falls apart.  This is fine
for people writing `ordinary´ code (perhaps), but for a core language
feature it should be resolved IMHO.

Out-of-band arguments seem to have been a hot topic in the past;

   http://xrl.us/ggt7 - Long (50+ posts) thread

   http://xrl.us/ggua - suggestion from Damian;

 $foo = sub { print $_ } is given($_);

I actually quite like that syntax, or at least the idea of using a trait
of some kind to specify non-positional arguments.  It keeps them well
out of the way of `safe´ programming conventions :).

In fact, it has to do wierder things than just accept it out of band to
parameters - ideally it would not also interfere with another sub that
uses $CALLER::_.

Perhaps to avoid that mess, the AUTOLOAD function is simply expected to
call &func.goto if it wants all the effects of the presence of the
AUTOLOAD sub to go away.  Assuming that the prototype is re-checked on a
goto, to ensure that type guarantees specified in the function signature
are honoured, then the necessary side effects should just happen.

Sam.


Re: AUTLOAD and $_

2005-06-20 Thread Sam Vilain

Juerd wrote:

I think there exists an even simpler way to avoid any mess involved.
Instead of letting AUTOLOAD receive and pass on arguments, and instead
of letting AUTOLOAD call the loaded sub, why not have AUTOLOAD do its
thing, and then have *perl* call the sub?
sub AUTOLOAD ($w) { return our &::($w) := get_subref_for $w }


I like that.  Makes it more consistent with the AUTOSCALAR, etc methods -
returning a reference to the result (variable ref/code ref/sub name) rather
than the actual result (variable value/calling the sub).

After all, presumably the compiler might sometimes call the AUTOLOAD at
compile time; to get its signature.  So, for instance, you could AUTOLOAD
all the methods you optionally export, which are all pulled in at once when
a module imports a function and tries to use it in some code (as the
signature will need to be checked then).  I was going to bring that up
next, but I think this has already answered it.

Sam.


Re: AUTLOAD and $_

2005-06-20 Thread Sam Vilain

chromatic wrote:

Who says AUTOLOAD will always either call a loaded sub or fail?


Maybe it should be passed a continuation too, then?  Then it could
choose exactly what to do with it.

Sam.


AUTOLOAD, this time distinct from AUTOSUB etc (and spelt correctly)

2005-06-20 Thread Sam Vilain

OK, that last discussion was productive, but I think we all (including
myself) overlooked the fact that the AUTOLOAD and AUTOSUB methods are
implied to have different calling conventions;

  There is still an AUTOLOAD hook that behaves as in Perl 5.

  The (AUTO*) routines are expected to return a reference to
  an object of the proper sort (i.e. a variable, subroutine,
  or method reference), or undef if that name is not to be
  considered declared.

So, here are the prototypes of the (new) AUTO* methods:

  subtype Symbol of Str;

  sub AUTOSCALAR( Symbol $sym ) returns Ref of Scalar;
  sub AUTOARRAY ( Symbol $sym ) returns Ref of Array;
  sub AUTOHASH  ( Symbol $sym ) returns Ref of Hash;
  sub AUTOSUB   ( Symbol $sym ) returns Code;
  sub AUTOMETH  ( ::$type: Symbol $sym ) returns Code(::$type: *);

uh-oh, another sticky one; the implication is that AUTOMETH has an
invocant, which is either a Type or the object, and is expected to
return a sub whose signatute has the right type, but we don't care
to type check anything more than the invocant type.  And that's even
before we look at MMD, so for now we'll think of it as;

  sub AUTOMETH  ( Symbol $sym ) returns Ref of Code;

So, those are all well and good.  They can still do anything,
including return little micro-subs that perform arbitrary munging
of the argument stack before passing them on, or define the
sub/variable that was referred to, to avoid the AUTOFOO call the
next time around.  And they're being invoked at compile time so that
we can get their signatures, but that isn't a problem with people
doing selective loading because they're clever enough to know what
to do.  Great, we can all start using those.

But what about AUTOLOAD?  It has to "behave as in Perl 5", which had
different calling conventions and expected you to make the loaded
function call yourself.

This has some side-implications; the signature used for a Class'
AUTOLOAD will be used as the signature for all unknown function calls;
so, defining;

 sub AUTOLOAD {
 ...
 }

Will forfeit your right to apply signatures to the arguments of an
auto-loaded method, which is probably an acceptable penalty for someone
who is just expecting P6 to work like P5 did.  Method calls, too.

It seems these requirements are still in conflict;

   - Preserving AUTOLOAD thou-shalt-make-the-call semantics
   - Keeping the new $AUTOLOAD off the argument stack for AUTOLOAD()
   - Use of $_ as an out-of-band way of passing arguments to a function
 cannot be localised due to the non-stack-like characteristic of
 the call stack, in the face of continuations and coroutines
   - disallowing "explicit" out-of-band arguments

Time to re-think the out-of-band arguments idea?

Sam.


Re: AUTOLOAD, this time distinct from AUTOSUB etc (and spelt correctly)

2005-06-20 Thread Sam Vilain

Rod Adams wrote:
I never liked the idea of out-of-band arguments. Either something is 
passed, is available due to being in a broader scope, or can be gleamed 
from introspection.


ok.  First of all, I agree with the basic sentiment.

However, to play devil's advocate and re-interpret what you just said, it
does imply that there are some implicit lexicals being passed around -
? twigil variables.

These are effectively out-of-band arguments to a function, but not user-
modifyable.

So what we're saying is that out-of-band arguments must be passed via
language/grammar special variables, so to do that from Perl code you'll
have to extend the interpreter, quite a challenging task at present.
That'll stop them being used Where We Don't Want Them To Be Used™.  :->

In this case, I think introspection is the answer. Hang the info off 
&?SUB or caller. Something like "&?SUB.Invocation" or "caller.call" 
could be made to return something useful, I think. Also makes the info 
available for more than just AUTO.* methods, which opens the door up for 
all kinds of useful perversions, especially in the age of bindings and 
such.


Sure.  Structurally, and architecturally, I like this too.
But syntactically, $?LASTQUOTEDPARA.idea is a little overweight.  But no
big problem.

Perhaps the problem here is that sometimes you want to explicitly
specify which available lexical variable the topic refers to on an
arbitrary block.

Personally I'm of the leaning that there is no global $_ at all. There is
no such thing as a global topic of a program, after all.  I don't think
I'm contradicting the Synopses there, either.  ie, in the main program $_
should not be in scope.

In this manner, $_, instead of actually being a real variable, is simply
an alias which always has lexical scope and happens to be normally bound
to $?SELF in method calls, and to @_[0] in bare blocks, and an anonymous
temporary variable in for loops.

And in AUTOLOAD blocks, it's bound to the $?SUB.called_as (or whatever)
lexical, out-of-band variable.

But how does that happen?  What makes the AUTOLOAD sub special to get
this action?

Clearly, we don't want people to have to explicitly say so in their
AUTOLOAD signature:

  sub AUTOLOAD($_ = $?SUB.called_as) {

  }

Plus, the above still wouldn't do what we want because it's still
specifying a positional argument.

I'm seeing something like this; however it's still a bit awful for
various reasons.

  package Package;
  sub dispatcher {
  ...
  %symtable::.assuming($_ = $method)(@args);
  ...
  }

Perhaps it is simply a mistake to assume that the package dispatcher
will itself be simple, accessible Perl like that.

Anyone got any bright ideas?  :)

Sam.


Magic mutators and my $var is Proxy( ... );

2005-06-26 Thread Sam Vilain

To me it is a trivial case that you want to provide a fake attribute
which for all intents and purposes behaves exactly like there was a real
attribute there, backing against another attribute.

A Date object is a classic example of this; you want to provide 0-based
and 1-based attributes, which you want to present as equivalent to each
other.

So, we've got this "my $var is Proxy( ... )" construct in A06.
Say you've got this class:

  class MagicVal {
 has Int $.varies is rw;

 method varies returns Int is rw {
return my $var is Proxy ( :for($.varies),
  :FETCH{ $.varies += 2 },
  :STORE{ $.varies = $_ + 1 },
);
 }
  }

Firstly, would this be correct syntax?  In particular, what should
I call $.varies inside the :FETCH and :STORE subs?  Would they close
over $?SELF, too?

If they did, doesn't this mean that $var will be a new Proxy attribute
every time that the attribute is read, and will have side effects?

Such as;

 my $foo = MagicVal.new();
 $foo.varies = 5;# sets to 6;
 say $foo.varies;# says 8
 say $foo.varies;# says 10
 my $var = $foo.varies;  # $var is proxy for attribute
 say $foo.varies;# says 12
 say $var;   # says 14

It seems to me that the only time I'd want to actually return a
Proxy object is when taking a reference to the fake attribute.  In
all other situations, you'd simply want to dispatch to either an
accessor or a mutator, depending on the context.

ie, I'd like the design of this feature to be sufficient that most
of the time, the Proxy object need never be constructed, and instead
the relevant closure could be bound to that method instead.

In particular, I think this would mean making Proxy objects
automatically call FETCH when returned, unless in reference context.

In fact, I think I'd rather see the proxy as a closure trait;

  class MagicVal {
 has Int $.varies is rw;

 method varies returns Int is Proxy( :FETCH(&get_varies),
 :STORE(&set_varies) );

 method get_varies { $.varies += 2 };
 method set_varies { $.varies = $^v + 1 };
  }

Of course this wouldn't preclude the possibility of using the syntax
in A06 where it is more suited to the problem at hand.  Also, in the
case where you do take a reference of a $foo.varies, then a Proxy object
could be constructed to DTRT based on the information there.

This would make the "is Proxy()" construct effectively a compile-time
want() switch.

Any opinions on this?

Sam.


Re: takers wanted - a perl job

2005-06-26 Thread Sam Vilain

Joshua Juran wrote:

scalar
number (possibly complex)
real
rational
integer
Integer
BigInt
Ratio
Float
Complex
Quaternion
String
...


Trying to fit every problem into a rigid inheritance tree is perhaps the
failure of the strict Class-based Object Oriented paradigm; that is, if
you count multiple inheritance and interfaces as afterthoughts rather
than the intent of Class-based Inheritance.

With reference to this Venn diagram:

http://svn.openfoundry.org/pugs/ext/Perl-MetaModel/docs/number-types.png

Here are the corresponding Rule descriptions; structure stolen from Haskell;

   role Num;
   role Real does Num;
   role Fractional does Num;
   role Integral does Real;
   class Int does Integral;
   class int does Integral; # unboxed...
   role RealFrac does Real does Fractional;
   class Rational does RealFrac;
   class IntRatio does RealFrac;
   role Floating does Fractional;
   role RealFrac does Floating;
   role RealFloat does RealFrac does Floating;
   class Float does RealFloat;
   class Double does RealFloat;
   class ComplexFloat does Floating;
   class ComplexDouble does Floating;

I would suggest this as a good starting point.  One thing that Haskell
is good at is math.

Sam.


Re: Magic mutators and my $var is Proxy( ... );

2005-06-26 Thread Sam Vilain

Sam Vilain wrote:

To me it is a trivial case that you want to provide a fake attribute
which for all intents and purposes behaves exactly like there was a real
attribute there, backing against another attribute.

A Date object is a classic example of this; you want to provide 0-based
and 1-based attributes, which you want to present as equivalent to each
other.


FWIW, I think this question also applies to fetching members from a hash
collection.

For example, if you have a function;

  sub foo($foo) { $foo || "bar" }

And you call it, passing it a hash slot;

  foo(%hash);

Then it will be auto-vivified, as in Perl 5; because a reference to the
slot had to be taken.  Actually there is no reference taken; it's a
read-only binding of the hash slot.  But either way, it is a read-only
point in the signature that is affecting the input argument, which is
arguably (right^wrong).

By returning a Proxy object 'tied' to the slot, then this autovivification
could be circumvented and the straightforward implementation - passing
bound variables as transparent references, continues to be acceptable.
Albeit requiring that the Hash::postcircumfix:<{ }> method is a Proxy
method, too.

Sam.


Re: AUTLOAD and $_

2005-06-26 Thread Sam Vilain

Piers Cawley wrote:

For myself, I'd like to see AUTOLOAD with a signature along the lines of:
   sub AUTOLOAD (Symbol $sym, ArgumentCollection $args, Continuation $cc)
 returns (Code | Pair)
   {
 ...
   }
This presupposes a deal of support infrastructure, but also provides
flexibility. For the 'NullObject' case, you'd simply do C<$cc()> to return
directly to the caller, skipping over whatever Perl is up to.


That's an excellent suggestion.  After your very enlightening discussion
about continuations in IRC, this popped to mind as an interesting application
for them, along with exception handlers.

This would be great for at least AUTOSUB and AUTOMETH.

However, for AUTOLOAD we're looking for simple Perl 5 alikeness.  And in
Perl 5, the sub name was passed out of band.

So, we need a compromise somewhere, please @cabal.pick:

  - just go for old AUTOLOAD + $AUTOLOAD interface and spit warnings
profusely
-OR-
  {
  - allow topic to refer to variables in lexical scope, but not in @_
(and pick a good name for $?SUB.called_as)
-OR-
  - allow generic out-of-band parameters to be passed in
  }
  implies {
  - there needs to be a special subroutine calling method, similar to
.assuming that lets you do this
-OR-
  - the method prototype, and specify some way that methods
defined without a signature can inherit it from somewhere else.
  }
-OR-
  - declare the topic to be the only out-of-band parameter that does this.
To avoid it being an accidental global, it would need to be declared with
"my $_" when used in this manner (of course, other methods like for, given,
etc that set it have the declaration implicit).
-OR-
  - scrap complete AUTOLOAD interface compatibility
-OR-
  - insert solution here ;)

Sam.



Re: SMD is for weenies

2005-06-30 Thread Sam Vilain

Yuval Kogman wrote:

As I understand it SMD is now not much more than a mechanism to
place a constraint on the MMD, saying that there can only be one
method or subroutine with the same short name.
Why is this the default?


Otherwise you lose this quite useful warning if the signatures didn't
match;

   method foo redefined at ...

I agree with you MMD is very cool, and I use it a lot.  But I don't
mind clarifying the intent with "multi"; this "overloading" is
considered by some to be surprising to new programmers.

Sam.


Re: DBI v2 - The Plan and How You Can Help

2005-07-03 Thread Sam Vilain

Hey Tim.

> I've kept an eye on Perl 6 and Parrot developments but I'm no expert in
> either. What I'd like *you* to do is make proposals (ideally fairly
> detailed proposals, but vague ideas are okay) for what a Perl 6 DBI API
> should look like.
> Keep in mind that the role of the DBI is to provide a consistent
> interface to databases at a fairly low level. To provide a *foundation*
> upon which higher level interfaces (such as Class::DBI, Tangram, Alzabo
> etc. in Perl 5) can be built.

OK, well based on my experience, here's a few things that would be nice;

  - optional treatment of the statements as an AST, similar in concept to
SQL::Routine, or Tangram::Expr.  Death to SQL templating systems!

Ideally there should be no need for a module like DBD::CSV or even,
eventually, DBD::SQLite to actually generate SQL strings for queries;
the AST is enough for them to go away and run the query.

It should be possible to use either, though - and use /named/
placeholder arguments for either, something like:

use DBI-2;
my $dbi = DBI->connect(...);
my $sth = $dbi->prepare("select * from foo where bar = :bar");
$sth->execute(:bar($bar));

my $table = $dbi->table("foo");
my $sth = $dbi->select
(:all
 :from($table),
 :where($table.bar == $dbh.placeholder("bar"))
);
$sth->execute(:bar($bar));

Virtually every major DB abstraction tends to build this, whether or
not they know they're doing it ;).

  - support for automatically pulling database DSN information from a
~/.dbi (or similar) file.  This is constantly re-invented poorly.
Let's just do a connect by logical application name and let the
SysAdmins sort out which DB that connects to, in a standard way.

  - object-oriented modelling of core database objects, so that schema
operations can be made portable, a la Rosetta.  This should really
just constitute re-thinking the existing interfaces, and leaving it
up to the DBD authors to finish them up.

This may also open the door for unifying the way that relationships
such as foreign key constraints, etc are dealt with.

  - make it easier to get ACID right; steal Tangram's `tx_do` transaction
interface; though I'd suggest a name including the perl6-ish `try'

 $dbh.tx_try {

 # ... transaction ...

 };

in fact, if you were to wrap the closure in an atomic{ } block, then
you could probably easily support replaying the transaction in the
event of a forced rollback (so long as the code in the closure has no
side effects ... )

Also there is the nested transction interface;

$dbh.tx_start;
$dbh.tx_start;
$dbh.tx_commit;
$dbh.tx_commit;  # commit happens here

Some databases can even support nested transactions internally via
SQL SAVEPOINTS.

  - asynchronous/event-based processing of queries, so that we don't need
yet another sub-process when in POE-like environments (which might
include a standard Perl 6 event programming system).

In terms of making things Perl6-ish, you probably want to look at technology
such as coroutines for cursors, and continuations for exception handling, for
their implications to writing transactional applications.

Perl 6 will be able to serialise continuations and probably also coroutines,
so it should be possible for a continuation serialised with an active cursor
in a coroutine to automatically resume itself once the continuation is thaw'ed.

This might happen by simply leaving the transaction open (I hear screams!) in
a single threaded context, or by rolling back, replaying the transaction's
queries on the continuation resume and checking all the database responses
match what was previously read.  At the first sign of discrepancies, the
next database operation would throw a fake ROLLBACK; which would even be
caught and the application transaction replayed from the beginning, if they
used .tx_try :retry(3), :{ ... }

This would make some of the "old problems", such as object versioning,
potentially a lot easier to solve.

Allow me to illustrate with some application code;

  my $mvc;

  if ($mvc.controller.action eq "edit") {
 my $id = $mvc.controller.edit_id;
 my $object;
 $dbi.tx_try {
$object = $fetch_query.select_only(:id($id));

$mvc.view(:state("edit"), :object($object))
   until $mvc.controller.action eq "commit";

$update_query.execute(:id($id));

CATCH {
$mvc.view(:state("error"),
  :message("object modified by another!"));
}

 }, :retry(3);
 $mvc.view(:state("edit"), :object($object));
  }

So, depending on the MVC system in use, when you wrote "$mvc.view()", it
will have done one of the following things;

Session-based continuations:

1. Serialise the continuation - when it comes across the DBH with an

Re: DBI v2 - The Plan and How You Can Help

2005-07-04 Thread Sam Vilain

Richard Nuttall wrote:

  - support for automatically pulling database DSN information from a
~/.dbi (or similar) file.  This is constantly re-invented poorly.
Let's just do a connect by logical application name and let the
SysAdmins sort out which DB that connects to, in a standard way.
This reminds me one one thing I hate about DB access, and that is having 
the DB password

stored in plain text.


Sadly, there is really nothing that can be done about this, other than
"casual" obscuring of the real password like CVS does in ~/.cvspass

However, making it in a file in $HOME/.xxx means that the sysadmin can
set it up to be mode 400 or something like that, to ensure other users
can't access it if someone forgot to set the permissions right on the
application code (or, hopefully, configuration file).

Of course, for more secure access schemes like kerberos, etc, the file
is really just being a little registry of available data sources.

On a similar note could be allowing overriding the data source used by
an application by setting an environment variable.  That way, the
SysAdmin has got lots of options when it comes to managing different
production levels - Oracle has this with TWO_TASK, and while it's a
PITA when it's not there (no doubt why DBD::Oracle allows this to be
specified in the DSN string), it's also useful for what it's intended
for - switching databases from an operational perspective.

Sam.


Re: DBI v2 - The Plan and How You Can Help

2005-07-04 Thread Sam Vilain

Darren Duncan wrote:
3. Redefine prepare() and execute() such that the first is expressly for 
activities that can be done apart from a database (and hence can also be 
done for a connection handle that is closed at the time) while all 
activities that require database interaction are deferred to the second.


That would be nice, but there are some DBDs for which you need the database
on hand for $dbh.prepare() to work.  In particular, DBD::Oracle.

I think that what you are asking for can still work, though;

  # this module creates lots of SQL::Statement derived objects, without
  # necessarily loading DBI.
  use MyApp::Queries <%queries>;

  # not connect, so doesn't connect
  my $db = DBI.new( :source("myapp") );

  # prepare the objects as far as possible
  my %sths;
  for %queries.kv -> $query_id, $query_ast_or_template {
  %sths{$query_id} = $db.prepare($query_ast_or_template);
  }

  # connect
  $db.connect;

  # now proceed as normal
  my $sth = %sths;
  $sth.execute( :param("foo"), :this("that") );

So, effectively the prepare can happen at any time, and it's up to the
DBD to decide whether to actually do anything with it immediately or not.
ie, on Pg the STHs would be built before the DB is connected, and on Oracle
they are built the first time they are used (and then cached).

Now I realize that it may be critically important for an application to 
know at prepare() time about statically-determinable errors, such as 
mal-formed SQL syntax, where error detection is handled just by the 
database.  For their benefit, the prepare()+execute() duality could be 
broken up into more methods, either all used in sequence or some 
alternately to each other, so users get their errors when they want 
them.  But regardless of the solution, it should permit for all 
database-independent preparation to be separated out.


OK, so we have these stages;

  1. (optional) generate an AST from SQL
  2. (optional) generate SQL string from an AST
  3. generate a handle for the statement, sans connection
  4. prepare handle for execution, with connection
  5. execute statement

I think these all fit into;

  1. SQL::Statement.new(:sql("..."));
  2. $statement.as_sql;
  3. $dbh.prepare($statement) or $dbh.prepare($statement, :nodb);
  4. $dbh.prepare($statement) or $sth.prepare while connected
  5. $sth.execute

In particular, I don't think that the DB driver should automatically
get a chance to interfere with SQL::Statement; if they want to do that,
then they should specialise SQL::Statement.  IMHO.

Perhaps you have some other examples that don't fit this?

5. All details used to construct a connection handle should be 
completely decomposed rather than shoved into an ungainly "data 
source".


I interpret this as asking that the detailed parameters to the DBI
connection are expanded into named options rather than simply bundled into
a string.

That, I agree with, and I guess it would be useful occasionally to be
able to specify all that rather than just setting it up once and labelling
those connection parameters with a "source" that comes from ~/.dbi.
Particularly for writing gui dialogs for interactive database utilities.

Either way, you don't want most applications dealing with this complexity
at all, really.

6. DBI drivers should always be specified by users with their actual 
package name, such as 'DBD::SQLite', and not some alternate or 
abbreviated version that either leaves the 'DBD::' out or is spelled 
differently.  Similarly, the DBI driver loader should simply try to load 
exactly the driver name it is given, without munging of any type.  This 
approach is a lot more simple, flexible and lacks the cludges of the 
current DBI.  DBI driver implementers can also name their module 
anything they want, and don't have to name it 'DBD::*'. A DBI driver 
should not have to conform to anything except a specific API by which it 
is called, which includes its behaviour upon initialization, invocation, 
and destruction.


Is this useful?

I can't see a reason that the DBI.new() / DBI.connect() call shouldn't be
flexible in what it accepts;

  $dbh = DBI.new( :driver );   # means DBD::Rosetta
  $dbh = DBI.new( :driver ); # specify full package
  $dbh = DBI.new( :driver(Rosetta::Emulate::DBD) ); # pass type object
  $dbh = DBI.new( :driver(DBD::SQLite.new(:foo)) ); # pass driver object

Sam.


Re: DBI v2 - The Plan and How You Can Help

2005-07-04 Thread Sam Vilain

Darren Duncan wrote:
Okay, considering that using the same name prepare() like this may 
confuse some people, here is a refined solution that uses 3 methods 
instead; please disregard any contrary statements that I previously made:


I think I'm beginning to like it.

Allow me to suggest one or two further refinements...


  # Opt 1: A user that wants the most control can do this (new feature):

  my $sth1 = $dbh.compile( $sql_or_ast ); # always sans connection
  $sth1.prepare(); # always with connection, even if DBD doesn't use it
  $sth1.execute(); # always with connection


To me, the "compiled" form of the STH is related to the driver, but
re-usable between connections; you should be able to use something like;

  my $sth1 = DBD::SQLite.compile( $sql_or_ast );
  $sth1 = DBI.compile( :statement($sql_or_ast), :driver );

This would give you a STH which is divorced from the actual DB connection
instance.  Because you constructed it like this, without reference to a
(possibly unconnected) connection object, then $sth1.prepare is not
available.

You'd then need to use something like;

  $sth1.prepare($dbh);
  $dbh.prepare($sth1);

Note I also think what you wrote should work, too.

The new feature is if you decide to use compile(); you then give that 
method the arguments you would have given to prepare(), and you invoke 
prepare() on the result with no arguments; each DBD would decide for 
itself how the work is divided between compile() and prepare() with the 
limitation that compile() is not allowed to access the database; ideally 
the DBD would place as much work there as is possible, which would vary 
between Oracle/Pg/etc.


Agreed.


In particular, I don't think that the DB driver should automatically
get a chance to interfere with SQL::Statement; if they want to do that,
then they should specialise SQL::Statement.  IMHO.
I am operating under the assumption here that while the new DBI is 
designed to effectively support wrapper modules, the wrapper modules 
would also be altered from their current DBI-1-geared designs to 
accomodate DBI-2.

But still, what do you mean by "interfere"?


Well, when you parse the statement into an AST, the flavour of SQL will
affect how it is parsed and what is allowed.  Eg, Oracle has significant
features in some comments (query hints).  It also has quirky and somewhat
useless keywords like CONNECT BY.

So, when you ask a DBH connected to a driver to parse something, then it
will use that driver's SQL dialect, if one exists, but I still want to be
able to deal with SQL ASTs without implying a SQL flavour.


Either way, you don't want most applications dealing with this complexity
at all, really.
I am operating under the assumption that this system should work if 
there are no external config files that the DBI/DBD would read, and the 
application would provide that information; if its in a file, the 
application would read it in, or would explicitly tell DBI where it is.  
Or at least it should be possible for this to happen, even if a DBD 
defaults to look in a default location when it doesn't get the 
equivalent from the application.


Absolutely, that must work.  But it would still be nice to be able to
config this without digging through the application to see where the
password is written.

Unless there is a design flaw in DBI, we should not have to update that 
module just because a new driver came into existence whose name has not 
yet been hard-coded into DBI.

See this block for example, from DBI.pm v1.48:
 my $dbd_prefix_registry = {
  ad_  => { class => 'DBD::AnyData',},

  [...]

  yaswi_   => { class => 'DBD::Yaswi',},
 };
I mean, what's up with that?  I assume DBI 1 has this for legacy app 
backwards compatability, but DBI version 2 should never have to 
accomodate such abhorrent computer programming practices in its core.


Such a great word, abhorrent.  So fitting for this case.  It sure does
look like an (over&premature&misguided)-optimisation to avoid using the
full module name in an internal hash or something like that.  But then
maybe (I&we&none(Gaia)) are missing some context there.

Sam.


Re: Time::Local

2005-07-05 Thread Sam Vilain

Darren Duncan wrote:
Actually, there was a big oversight in my last message.  It does not 
handle approximate or relative dates, such as when you don't know the 
details.


FWIW, this is handled by DateTime::Incomplete, and also will be natively
supported by Date::Gregorian.

You're describing with this and other messages very much how the `Date'
distribution in pugs is being designed.  I'd very much appreciate input
on that interface.

Sam.


Re: Time::Local

2005-07-05 Thread Sam Vilain

Craig DeForest wrote:

Using the TAI epoch of 1958-01-01 00:00:00 has several advantages:
- TAI is recognized by international standards-setting bodies (BIPM).
	- Perl6 will then shake out the 31-bit time rollover a full 12 years before 


I like this in principle, however I wonder of the merits of professing to
return something of more accuracy than can actually ever be realistically
assured from any of the platforms Perl runs.

For a start, to convert from the available time source - the system clock
- to TAI, you need to know;

  a) current adjustments, or when the lack of adjustments is considered
 valid up to (after that date, of course, if the list of adjustments
 is not updated, getting the time or converting from a time to a date
 on a calendar is an exception).

  b) whether or not the system clock is automatically correcting for
 leap seconds, ie when ntpd is running and sync'ed up.

In any case, I'll add "to_TAI" as one of the marshalling methods for
Date objects in Date.pm

I guess it comes down to what guarantees we decide to make on the nature
of time().  If a leap second passes while the script is running, can the
value returned by time() regress?

In fact, do we even need a fixed epoch?  Why not just free-wheel it and
make 0 the time the script started, get it to count seconds, and let
interfaces for the system clock / orson database solve the hard problems.

Sam.


  1   2   >