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.

Reply via email to