Re: MMD and VTABLE_find_method
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)
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
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
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)
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)
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)
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
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
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
# 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
# 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