From: Leopold Toetsch <[EMAIL PROTECTED]> Date: Thu, 31 Mar 2005 09:38:15 +0200
Bob Rogers <[EMAIL PROTECTED]> wrote: > From: Leopold Toetsch <[EMAIL PROTECTED]> > Date: Wed, 30 Mar 2005 08:57:55 +0200 > > ... , is that you are assuming (as I did not) that each and > every language built on top of Parrot will define its own PMC classes, > even for primitive arithmetic types, when necessary to get the right MMD > operator semantics. Is this correct? Not necessarily. I'd like to have core scalar types with the most common functionality, which - e.g. for Integer PMCs - seems to be an arbitrary integer type with automatic promotion to bigint. If your language is happy with that type and all semantics are the same, there is no need to subclass the PMC. That sounds good, but I'm not sure that can be used in all situations. After all, the notion of "all semantics" is much broader with MMD. For instance, even if Int+Int=>(Int or Bigint) was what was wanted, there would then be no way to disallow Int+String, since I assume an Int+String=>Number method will exist that coerces the string to a number first. I imagine you could do this by creating a subclass of Int, e.g. LispInt, and then defining a LispInt+String method that throws an error. But even then, you still lose Lisp semantics if calls into other code return PerlInt's, or whatever. But normally all these dynamic languages have some kind of introspection. E.g. $ python >>> 1+2j (1+2j) The string representation of a different language could be "1+2i". Not to speak about different semantics like using "+" for string concatenation. That is a good point, but subclassing isn't the only way to skin this particular cat. To follow your example, the Lisp syntax for this particular complex number is "#C(1 2)", but this is produced only by printing operators; there is no "coerce-to-string" operation per se. So Lisp could define "__lisp__print_object" methods on each of the base arithmetic classes, and then it would be able to get away without subclassing them (at least as far as this issue is concerned). This also has the advantage that this same (eq_addr) number will appear as "(1+2j)" when printed by Python code and "#C(1 2)" when printed by Lisp code, which is (IMHO) as it should be. > One of my motivations for exploring Common Lisp in Parrot is summed up > in four letters: CPAN. So I expect to want to call Perl[56] code and > get back Perl data types for further mungery in Lisp (if I ever get that > far). It might be the right thing in that case to accept the additional > Perl semantics, but I'm not completely convinced. I tend to think of > operator semantics as being "language scoped," but perhaps this is just > personal bias, as I can't think of a really compelling reason why it > should be so. I don't know. But Perl scalar operator semantics seems to be to morph the destination PMC to the value of the operation: .language perl a = Undef a = b + c # a maybe promoted to bigint Python semantics are that scalar operators always create a new result. Python scalars including strings are immutable. .language python a = b + c # new "a" value created The question now is, what happens, when you call a Perl module that happens to return the scalar "b": .language lisp a = b + c Lisp works here AFAIK like Python, e.g. a new destination should be created. That is correct. So it seems that under the pragma "lisp" or "python" this should translate to: n_add a, b, c # not existing op that creates new "a" and within perl semantics add a, b, c # reuse "a" Yes. And, now that you mention it, I can see headaches when Perl scribbles on Lisp or Python constant values. So it may be necessary (shudder) to have interface routines between Perl code and the rest of the world in order to avoid this. I hope I'm wrong. > But I am also concerned that a proliferation of low-level PMC types > will be an obstacle to interoperability. It seems simpler to me to > represent each distinct kind of mathematical object as a single PMC > class I don't get that. I'm sorry; I'm not sure how to explain it better. Except perhaps to say that I think that numbers as mathematical objects ought to be represented in a way that is independent of the programming language that spawned them, to the greatest extent possible. Also, the Int+String example above seems to point to a situation where code could behave one way with its "native" numeric values, but very differently with "foreign" numbers that represent the same mathematical values. Admittedly, this particular example seems like a corner case, but on the other hand it seems very odd, and a source of more debugging headaches, that the "same" numbers could give different results. > ... You wouldn't want the result of MMD dispatch to change > because the compiler got cleverer about assigning things to registers, > would you? Parrot itself doesn't do this optimization. Only the HLL compiler can emit such code, if the language provides a type system. Perl6 allows: my int ($i, $j, $k); # use natural integer $i = $j + $k # I0 = I1 + I2 This integer $i can't promote to a bigint for example. Oops; I forgot about promotion. So now I think I understand why Parrot needs to distinguish between situations where a machine integer can be promoted to a bigint, and ones where it can't. But in this case the choice not to promote has already been made by the compiler. Presumably, assignment to an integer register includes an implicit "mod" operation, so the compiler can't possibly have wanted to promote there. And writing P0 = I1 + I2 should probably be seen as a request to permit promotion on overflow. So isn't the promotion choice always determined by the destination register type? If that is so, then it seems to me that you really have a total of four addition MMD operators: * __addi produces a native integer in an I register. * __addn produces a float in an N register. * __add stores into an existing destination PMC. * __n_add creates a new destination PMC. The latter two might promote to BigInt -- or produce anything else, depending on what they are given. Would that work? If so, please pick saner names; I was trying to reuse the existing names, but that gives rise to "n confusion." The more important case is: my int @ints; # array of plain integers There are a few rare cases, where the HLL to parrot translator could optimize to natural types though: for i in xrange(1..10): print i Python's xrange produces only natural ints. So that is sufficient to bind the type of i. The Lisp idiom is actually quite close, but people frequently declare indices of various sorts to be machine integers[1] for speed, which makes it not at all rare. And so even in Lisp, you would want (and expect) different behavior for "int" vs. "Int". It's a pity I wasn't thinking more clearly yesterday . . . -- Bob Rogers http://rgrjr.dyndns.org/ [1] Actually, "fixnums", which are a few bits smaller.