Re: MMD and VTABLE_find_method

2004-12-23 Thread Luke Palmer
Sam Ruby writes:
 In the general case, a call to a subroutine with three arguments can 
 have four possibilities: anywhere from zero to three arguments may be 
 involved in the dispatch.
 
 I also read this to say that whatever code is generated by a subroutine 
 call is independent of the number of arguments involved in the dispatch. 
  If you read this differently, perhaps we can get a ruling from the 
 Perl6 language folks.  If I am correct, this will have the nice side 
 benefit that any such methods can be invoked transparently by all languages.

A ruling: The caller might not know that it's calling a multimethod at
all at compile time, much less how many invocants it has.

A PMC that hides the fact that we're doing a multimethod seems like the
best way to allow multiple language semantics.  If we were OO designers,
I doubt we would have thought of any other way.

Luke


MMD and pdd03 (was: MMD and VTABLE_find_method)

2004-12-23 Thread Leopold Toetsch
Luke Palmer wrote:
A ruling: The caller might not know that it's calling a multimethod at
all at compile time, much less how many invocants it has.
This seems to invalidate calling conventions aka pdd03, *if* multi subs 
with native types are allowed. The register setup of calling these two 
multisubs is identical:

  multi sub infix:+(int $l, Int $r) {...}
  multi sub infix:+(Int $l, int $r) {...}
There is no way to detect the ordering of call arguments (I5, P5).
A PMC that hides the fact that we're doing a multimethod seems like the
best way to allow multiple language semantics.  If we were OO designers,
I doubt we would have thought of any other way.
Yes, basically. The question is which PMC. On the surface of a function 
call there is (in Python assembly terms):

  LOAD_NAME foo
  CALL_FUNCTION
where the LOAD_NAME searches (lexicals, globals, builtins) for the name 
foo. The question is, if Perl6 (or Parrot) can create a multi sub PMC 
with the short name (S12) foo, or if only the long names exist. 
The problem I see is namespace pollution, as it is totally valid that a 
locally defined subroutine foo hides outer multi subs of that name.

So, where does that OOish dispatcher PMC jump in?
Luke
leo


Re: MMD and VTABLE_find_method

2004-12-23 Thread Sam Ruby
Leopold Toetsch wrote:
Sam Ruby wrote:
First, a few things to note: the semantics of add vary from language 
to language.  In particular, add is not guaranteed to be commutative 
in Python (think string addition).
Yes, of course.
It seems obvious, but it leads to surprises.  Example:
  '1' + '2'
The result will depend on what the actual types are of the inputs 
perhaps even what the context is of the caller.

As my proposal is primarily focused on where the logic is placed in 
the system, not how it works, I'll like to use your proposal 
http://xrl.us/egvp as a starting point.  Just to make sure that I 
don't mischaracterize your proposal, can you take a look at the 
attached and either agree that it represents a reasonable first 
approximation of what you had in mind, or modify it so that it is?
It's a reasonable respresentation, yes. Finding the right functions is 
more complex, though, as described in my proposal.

I'd just outline the functionality of the add opcode like this:
  inline op add (out PMC, in PMC, in PMC) :base_core {
  PRESERVE_CONTEXT;
  add_func = mmd_find(__add...) // via VTABLE_find_method
  REG_PMC(5) = $2;
  REG_PMC(6) = $3;
  VTABLE_invoke(interp, add_func, 0);
  res = REG_PMC(5);
  RESTORE_CONTEXT;
  $1 = res;
  }
Cool see below.
the basics are:
* the destination PMC $1 is created by the opcode
I don't want to dwell on this point, but it would be rather handy if the 
caller were able to pass in an object which was responsible for 
producing the desired destination PMC on request.

It would accept requests like give me an Integer and would respond 
with things like here's a PyInt.

At the moment, we have a fairly good approximation of this with 
VTABLE_morph.  Make yourself a BigInt...OK, (P.S. I'm really a PyLong).

This won't work for languages which have a notion of singletons, unless 
the language uses a double-reference system... like Ruby and Perl 5 do 
today (per Dan's previous statements).

* no other registers are changed, nor the context
* finding the __add method uses VTABLE_find_method to
  find all possible __add methods and a distance
  function to get the best match
* the best matching function is invoked
The word best here should be setting off alarm bells in everybody's 
head.  What is the chance that we can get Larry, Guido, Matz, Brenden 
and others to agree on such a thing?  Particularly when they can't even 
agree on what + means when dealing with strings (actually, in the list 
above, Larry is the lone hold out... ;-)  (and apologies to all involved 
for personifying this))

Once that's done, I'll sketch out all of the changes required to 
enable Perl and Python to each have their own separate semantics for 
this operation, and yet be able to have meaningful interop when it 
comes to adding a PerlInt and a PyInt, or vice versa.
OK, here's what the proposal would look like, hypothetically assuming 
that all of your proposed changes get in:

inline op add (out PMC, in PMC, in PMC) :base_core {
$1 = VTABLE_add(interp, $2, $3);
}
pmclass default abstract noinit {
PMC* add (PMC* left, PMC* right) {
PRESERVE_CONTEXT;
add_func = mmd_find(__add...) // via VTABLE_find_method
REG_PMC(5) = left;
REG_PMC(6) = right;
VTABLE_invoke(interp, add_func, 0);
res = REG_PMC(5);
RESTORE_CONTEXT;
return res;
 }
}
That's it.  From an external point of view, add is called in exactly the 
same way.  Whether MMD is involved or not, the caller shouldn't know and 
shouldn't care.  A similar approach can be taken in the more general 
case of the foo subroutine that we were talking about previously... no 
need to introduce new opcodes or a change to the Perl6 syntax.

Now, lets take a look at a hypothetical PyString implementation of add:
pmclass PyString extends PyObject dynpmc group python_group {
 PMC* add (PMC* right) {
 if (!VTABLE_does(right, const_string(STRING))
real_exception(INTERP, NULL, E_TypeError,
TypeError: cannot concatenate '%Ss' and '%Ss' 
objects,
SELF-vtable-whoami, right-vtable-whoami);

 PMC *dest = pmc_new(INTERP, dynclass_PyString);
 PMC_str_val(dest) = string_concat(INTERP,
 PMC_str_val(SELF), VTABLE_get_string(INTERP, value), 0);
 return dest;
 }
}
Note: no MMD.  In fact, no need to preserve context.  Either the second 
parameter does string, or a Type error is thrown.  This would 
presumably interoperate with PerlString, but not with PerlInt.  How 
would this work when called from Perl instead?  Well, PyInt need to be 
based on from Parrot's Integer, and the MMD implementation that Perl 
settles on will need to be aware of inheritance.

Now let's look at a second hypothetical example:
 pmclass PyClass dynpmc group python_group {
  PMC* add (PMC* 

Re: MMD and VTABLE_find_method

2004-12-23 Thread Leopold Toetsch
Sam Ruby wrote:
[ a lot - I'll split answers ]
Leopold Toetsch wrote:
Sam Ruby wrote:

It seems obvious, but it leads to surprises.  Example:
  '1' + '2'
The result will depend on what the actual types are of the inputs 
perhaps even what the context is of the caller.
Ehem, given that and ... (from below)
 Note: no MMD.
 and VTABLE_add()
it seems that you are still missing the power of MMD. Just because the 
result and semantics of the add operation are different, we are doing MMD.

The MMD dispatch looks at the left and right types of the infix 
operation, locates a function that matches and call the function.

You can look at it like a matrix:
  PyStringPyIntPyNum  Integer  ...
--
PyString  py_add_sadd_err   add_err   add_err
PyInt add_err add_i add_n add_i
PyNum add_err add_n add_n add_i
Integer   add_err add_i add_n add_i
...
There are four incarnation of the add multi sub:
py_add_s   := concat (function name Parrot_PyString_add_PyString)
add_err:= emit a TypeError : cannot concat ...
add_i  := integer add (Parrot_Integer_add_Integer)
add_n  := float   add (Parrot_Float_add_Float)
So what actually need to exist in Python scalar classes is a constructor 
and:

in pystring.pmc
pmclass PyString extends PyObject extends String {
  METHOD PMC* add(PMC *right) {
MMD_PyString: {  ... do a concat }
MMD_DEFAULT:  {  ... emit TypeError }
  }
}
in pyint.pmc  (and pyfloat analog)
pmclass PyInt extends PyObject extends Integer {
   // inherit add
}
The METHOD specifier shall install all given variants with 
VTABLE_add_method, i.e. register the NCI functions so that 
VTABLE_find_method can locate the entry.

But the matrix implementation doesn't work, because it's too static, 
inheritance can't be described easily (or not at all) in terms of it.

As my proposal is primarily focused on where the logic is placed
And that's the main problem of your approach. You are forgetting MMD.
inline op add (out PMC, in PMC, in PMC) :base_core {
$1 = VTABLE_add(interp, $2, $3);
}
With that you are already calling an add function that depends on the 
 left type - this is not MMD and it forces the left operand to handle 
all possible cases of add/concat with int/float/string ... This is 
exactly the point, where interoperbility is violated. The left type 
doesn't know all possible right types to deal with them correctly.

With that you get a cascade of ifs that handle the different types. We 
had that earlier. It was discarded in favor of MMD.

pmclass default abstract noinit {
PMC* add (PMC* left, PMC* right) {
PRESERVE_CONTEXT;
add_func = mmd_find(__add...) // via VTABLE_find_method
and here it becomes horribly slow and weird. You are already in one 
add. What do you want to find here?

REG_PMC(5) = left;
REG_PMC(6) = right;
VTABLE_invoke(interp, add_func, 0);
and redispatching - no and no - sorry.
I know that Leo keeps telling me that I need to map __add__ to __add at 
compile time, but there are tests like t/pie/b3.t that indicate that 
such tests need to be made at runtime.
When I say, that __add__ maps to Parrot's __add at compile time, it 
doesn't preclude that you have to do something at runtime too. E.g. you 
emit code for:

  foo.__add__ = myadd(or __dict__.__add__)
then the user is installing an overridden version of the add method. 
You have to know that, or you can't do the right thing when it comes to

  foo + x
So you have to call
  VTABLE_add_method(class_of_foo, __add, myadd).
If you don't do that, VTABLE_find_method(... __add) will fail later or 
return the wrong function.

But and that's the big difference of our porposals: nothing more has to 
be done. The MMD dispatch at the runloop (and not inside every class) 
handles the selection of the correct subroutine, being it a C function 
(wrapped into NCI) or PASM/PIR user code. This just doesn't matter and a 
class doesn't need to know about that.

Allowing me to subclass, extend, and replace how methods like add works 
gives me a place to insert any logic I find necessary. 
Which logic would you insert in add(PyInt, PyInt)? What for?
... And, when I find 
out that something is not as necessary as I once thought, it can be 
removed just as easily.
No because you are duplicating the method dispatch. You can't remove 
that. And that's the big problem with your approach - besides that it'll 
be around a factor 10 slower then the dispatch at the opcode level like 
now. We can't afford a factor ten in speed decrease.

Arguements can be made against each individual example (perhaps I could 
create a small function that raises Type Error and register it dozens of 
times to handle the PyString.add example, and yes,
Instead of the check (if right.type isnt a PyString) you are already in 
the MMD method Py_String_add 

MMD distance (was: MMD and VTABLE_find_method)

2004-12-23 Thread Leopold Toetsch
Sam Ruby wrote:
Leopold Toetsch wrote:

* finding the __add method uses VTABLE_find_method to
  find all possible __add methods and a distance
  function to get the best match
* the best matching function is invoked

The word best here should be setting off alarm bells in everybody's 
head.  What is the chance that we can get Larry, Guido, Matz, Brenden 
and others to agree on such a thing?  Particularly when they can't even 
agree on what + means when dealing with strings (actually, in the list 
above, Larry is the lone hold out... ;-)  (and apologies to all involved 
for personifying this))
Finding the best matching function can be HLL dependent, there can be 
different schemes, even user code that influences it.

But I think that using the function with a minimum value of
  left.class_search_depth**2 + right.class_search_depth**2
should do it.
WRT the '+' operation: You just need a PyString_add_* and 
PyString_add_PyString (the same with PyList). If the class isa PyString 
(which includes derived classes), one of these methods will be called.

It just needs a working find_method implementation not much more.
leo


add (out PMC ... (was: MMD and VTABLE_find_method)

2004-12-23 Thread Leopold Toetsch
Sam Ruby wrote:
Leopold Toetsch wrote:

the basics are:
* the destination PMC $1 is created by the opcode

I don't want to dwell on this point, but it would be rather handy if the 
caller were able to pass in an object which was responsible for 
producing the desired destination PMC on request.

It would accept requests like give me an Integer and would respond 
with things like here's a PyInt.

At the moment, we have a fairly good approximation of this with 
VTABLE_morph.  Make yourself a BigInt...OK, (P.S. I'm really a PyLong).

This won't work for languages which have a notion of singletons, unless 
the language uses a double-reference system... like Ruby and Perl 5 do 
today (per Dan's previous statements).
Python's None is a singleton. False and True should be, but for 
compatiblity reasons this wasn't changed (yet). There's old code around 
that does:

  False, True = 0, 1
Anyway disallowing singletons as return results is major drawback of the 
current scheme.

Second: we have two different function signatures: overridden methods 
are returning new PMCs. Internal methods currently get the destination 
PMC. We'd need glue code to translate between these two schemes.

And there are of course performance considerations:
  Px = new Undef
  add Px, Py, Pz
If add is overridden, we are preconstructing a PMC for nothing. That 
increases pressure on GC. And morphing the Undef (or whatever) is a 
rather expensive operations - look at pmc.c:pmc_reuse().

WRT constructing the new type: Given that PyInt_add_PyInt is inherited 
from the Integer PMC, it should work if we do:

  dest = pmc_new(interp, SELF-vtable-base_type);
  VTABLE_set_integer_native(interp, dest, sum);
  return dest:
When e.g. a BigInt is created due to overflow, we could to
  dest = pmc_new(interp, SELF-vtable-base_type);
  VTABLE_set_bigint(interp, dest, left);
  VTABLE_inplace_add(interp, dest, right);  // d += r
  return dest;
Additionally it wouldn't harm, if there is a list of basic types per 
supported language, so that a destination of the HLL's flavor can be 
constructed.

leo


integer interning (was: MMD and VTABLE_find_method)

2004-12-23 Thread Leopold Toetsch
Sam Ruby wrote:
Oh, well, back to coding.  BTW, I'm committing the change to opcode 
issame to make use of the similarly named VTABLE entry as I need this in 
order to pass a test.  Oddly, in Python:

(1,2) == (1,2), (1,2) is (1,2)
(True, False)
1+2 == 1+2, 1+2 is 1+2
(True, True)
But:
 101+2 == 101+2, 101+2 is 101+2
(True, False)
Just forget it.
That are CPython internals (int interning, string interning). No 
real code is depending on that. Even Python people often give wrong 
answers on c.l.p, where the actual limits of interned integers are.

If there is a test for that, drop that test (one was testing the exact 
amount of compare operations in sort() - same weirdness).

- Sam Ruby
leo


Re: cvs commit: parrot/ops cmp.ops

2004-12-23 Thread Leopold Toetsch
Sam Ruby [EMAIL PROTECTED] wrote:
 cvsuser 04/12/23 04:44:05

   
   Note: change to op issame to make use of VTABLE_is_same.

inline op issame(out INT, in PMC, in PMC) {
   -$1 = $2 == $3;
   +if ($2 == $3)
   +$1 = 1;
   +else
   +$1 = VTABLE_is_same(interpreter, $2, $3);
goto NEXT();
}

This doesn't really help for what you might achieve:

 id(2) == id(1+1)
True
 id(101) == id(100+1)
False

Second: before such core changes I'd prefer some discussion
on the list about possible implications. Did you check that
all implementations of the is_same vtable are sane?
Such changes can break code, if suddenly a vtable is called
that wasn't before.

Please send non-trivial core Patches to the list for review.

Thanks,
leo


Re: MMD and VTABLE_find_method

2004-12-23 Thread Leopold Toetsch
Leopold Toetsch wrote:
  PyStringPyIntPyNum  Integer  ...
--
PyString  py_add_sadd_err   add_err   add_err
PyInt add_err add_i add_n add_i
PyNum add_err add_n add_n add_i
^
Sorry, typo add_n of course.
leo


[perl #33171] IMCC Error When Reading Past EOF

2004-12-23 Thread via RT
# New Ticket Created by  Matt Diephouse 
# Please include the string:  [perl #33171]
# in the subject line of all future correspondence about this issue. 
# URL: http://rt.perl.org:80/rt3/Ticket/Display.html?id=33171 


Reading past the EOF in PIR results in the following error:

   File not found
   in file '(unknown file)' near line -1

That's less than helpful. Or at least less helpful than it could be. A 
better error would be really nice.

--
matt diephouse
http://matt.diephouse.com



[perl #33172] Missing examples subsection in PDD16

2004-12-23 Thread via RT
# New Ticket Created by  Simon Glover 
# Please include the string:  [perl #33172]
# in the subject line of all future correspondence about this issue. 
# URL: http://rt.perl.org:80/rt3/Ticket/Display.html?id=33172 



 In PDD16 (NCI conventions and definitions), the examples subsection
 contains very little text and stops in the middle of a line, i.e.:

-

=head2 Examples

Most of the function parameters are reasonably self-evident. Some,
however, merit additional explanation. The

-

 This section should either be completed (by someone who understands NCI,
 which rules me out...) or removed, as it's useless as it stands.

 Simon