Bob Rogers wrote:

   +{{ There seems to be an implied basic assumption here that language
   +interoperability is the responsibility of the language
   +implementor. It is not.  We cannot require that language
   +implementors design and implement their languages according to some
   +global specification.

If you are not happy with that assumption, then I'm surprised you
bothered to commit this draft at all, even as a starting point.

Design is a process. If you don't understand what I'm getting at, then it means I haven't explained it well enough yet. And, revising the draft to help you understand also produces a design document, so it's doubly useful.

Even
then, surely, it must *still* be the responsibility of the language
implementor not to introduce gratuitous barriers to interoperability?

   As a case in point, consider keyword (named) parameters in Lisp.
Kea-CL does not use Parrot named parameters to implement "&key", partly
for ANSI compliance and partly for efficiency.  This currently makes it
problematic (though not impossible) for other languages to call Lisp
functions that accept keywords.  You can either say I'm a bad boy for
not fully using Parrot features and "require" me to "design and
implement ... according to some global specification," forcing me to
solve the performance vs. compliance vs. interoperability tradeoff in
each sub, or allow me to do my own thing internally and accept the need
for glue around the edges (which in turn requires compliance with
another specification).

Well, my main question from that is what it is about Parrot named parameters that don't work for Kea-CL. (It may be something we can fix.)

But, what I expect from Kea-CL with a unique parameter-passing style is that your libraries clearly document how to call the subroutines. That's all. If people find libraries written in your language too obtuse to bother with, then they simply won't use them.

There are an awful lot of "must"s in the draft, where there should be only free will.

   Another example is object system metamodel compatibility.  I am not
an expert on metamodels, but all the ones I *think* I know make it very
hard for me to imagine inheritance across language boundaries without
some very careful design and coding on the part of language implementors
on both sides of the boundary.  (Who will no doubt be grateful for "some
global specification" to help them in that work.  ;-)

The interoperability infrastructure is the vtable functions. You can have absolutely any metamodel you want, just provide a minimal set of functionality so Parrot can instantiate objects from your class, invoke methods, and get and set attribute values.

Inheritance across language boundaries works by proxying and delegation. It's true that a class in one language won't know how to, for example, look up a method in a parent class from another language. So, it can't poke directly into the parent and do the lookup, but it can ask the parent to do the lookup. Poking directly into the parent breaks encapsulation anyway, generally a bad idea.


Do you really think that Parrot can subsume all object system metamodels
well enough to provide all the infrastructure?  Just the CLOS and Perl 6
MOPs are each complicated enough on their own; I'm tempted to advocate
$n^2$ metamodel interfaces in order to break the problem down into
manageable chunks.  (And, not incidentally, push the problems onto the
people who understand them.)

If you mean "Do you think Parrot can build an enormous and complex interoperability infrastructure that handles all possible language semantics now and in the future?", the answer is "absolutely not", and "let's avoid that like the plague". The point is to keep it as barebones as possible, and leave each language to implement whatever custom behavior they need behind the vtable function interface.


   +{{ It's not possible to define a sub that can't be called externally 
--allison }}

Not now, true.  Except that we currently support ".sub foo :anon ..."
for compilation-unit scoping.  Are you saying you object to language
scoping of subs?

Sure, but if that scoped sub was returned as a subroutine object to another language, it could be invoked as a subroutine by that language.


   +{{ Exporting is very much a Perl idea, not much applicability for exporting
   +outside of Perl. --allison}}

Eh?  I think we are having another terminology issue.  By "export" I
meant "make public."  Perl is not the only language to use this term;
just off the top of my head I can think of CL and Erlang.

Ah, by "export" I mean "inject into the caller's namespace" (Perl terminology). Any subroutines stored in a namespace are already public, so I'm not sure what you meant.


I *could* represent CL strings explicitly as vectors of characters
instead of using the String type.  But that would mean that I couldn't
use the wealth of Parrot string ops, and would be inviting more
interoperability problems to boot.  Ditto for Integer and Float, which
are exactly what I need in terms of representation.  CL does not need
new types for these.  And that is a good thing.

If the Parrot implementations work for you out-of-the-box, that's certainly a plus.

   But I suppose it doesn't matter.  If language implementers believe
that is OK, then they can accept whatever the builtin returns.  If not,
they can use MMD to define any exceptions they require.

You're relying far too heavily on MMD. It's not a cure-all for cross-language interoperability. For the most part, unless a language expects the semantics of dispatching based on multiple invocants, MMD won't do what they need.

You are not persuaded by my argument that PMC classes are about
representation, and "multi variants" are about operation semantics?

No, PMCs are data and behavior. It's the fundamental definition of OO.

   In any case, language-specific PMC classes are not needed for this
purpose, only language-specific operations.

Language-specific operations *are* language-specific classes.

   +{{ It is perfectly fine for a Lisp arithmetic operator to return a RATIONAL
   +subtype. Please don't define methods for a pile of operations that already 
have
   +vtable functions --allison }}

When I said "methods" here, I was actually speaking of defining "multi
variants" for that Lisp arithmetic operator.  Does that help?

Yes. Though, the point still holds that you shouldn't be writing extra code to make sure that your Lisp functions never return Lisp-typed values to languages other than Lisp.

   +{{ The default multi for a common operation like division will call the 
PMC's
   +C<get_number> vtable function, perform a standard division operation, and
   +return a standard Integer/Number/BigNum. --allison }}

???  C<get_number> always returns a float, which would force the answer
to be a float (in all languages I can think of).  But, yes, this is a
reasonable default.

Yes, it's only a default, and any language can do otherwise.

    {{ We can define multimethods on another language without loading it, can't
    we?  If not, then making this work may require negotiation between language
    implementors, if it is feasible at all.  -- rgr, 31-Jul-08. }}

   +{{ I'm not sure what you mean by defining multimethods on another language.
   +Perhaps you're asking if it's possible to declare a multisub for a type that
   +doesn't exist yet?  --allison }}

I would like to be able to define a "multi variant" on another language
that handles my language's types, without loading the other language, so
that *if* the other language is ever loaded, it handles the new types
gracefully.

The communication problem here seems to be with the phrase "on another language". If you're asking "Can I insert code into the namespace of another HLL just in case it's ever loaded?" the answer is: Yes, but do you realize how many languages you may have to do that for? Potentially hundreds. This is not a good path to language interoperability.

The same answer applies if you're asking "Can I store a large set of multi variants in the global multi dispatch table using the other language's types?"


   @@ -301,20 +366,31 @@
    Define language-specific operations using multimethods (to avoid conflict 
with
    other languages).

   +{{ Clarify? How would non-multi's conflict?  --allison }}

Method dispatch is done by string lookup on the operation name; there
are no package names to bind the operation to a language implementation.

Regular method dispatch never conflicts between languages, because it only looks in the class of the one invocant. Multis are what's likely to conflict across languages.

    =item 2.

    Define them on the highest (most general) possible PMC classes (in order 
that
    they continue to work if passed a subclass by a call from a different
    language).

   +{{ Define them on the class that makes sense. There's no point in targeting 
any
   +particular level of the inheritance hierarchy. --allison }}

Yes, but I'm trying to explain what makes sense.  But I'll add "... the
highest ... PMC classes that make sense" if you like.

There isn't a universal pattern that makes sense for all languages and all inheritance hierarchies.


   +{{ The scalar decides when to morph, not the language. All the languages 
that
   +have morphing scalars implement them in such a way that they know how to
   +handle, for example, morphing when a string value is assigned to an integer
   +scalar, and what to do if that value is later used as an integer again.
   +--allison }}

This is not about assignment, but about use:  If you pass a "5" from
Perl to a Lisp function that tries to use it as a number, Lisp would
normally barf.  Arguably, it should just coerce it to a number (not
least because it may be hard to control the representation from the Perl
side), but that still leaves the question:  How does Lisp recognize that
it's OK in this case?

If you pass a literal value "5", then Lisp shouldn't treat it any differently just because it was passed in from Perl. If you pass a Perl variable with the value "5", and Lisp calls 'get_number' on it, the Perl variable will know how to return "5.0" instead of the integer "5", and Lisp will be happy.


   @@ -383,6 +482,9 @@
    hand, if a language doesn't support functional arguments, then there is no
    hope of using an API written in another language that requires them.

   +{{ Hmmm? They're just subs, how would they not be callable from another
   +language? --allison }}

If the *calling* language doesn't have a syntax for "pass this function
to this other function," then there's no hope of using a foreign API
that requires that.  (Not that there are many such languages targeted by
Parrot.)

Well, functions are just objects. The calling language might not have the syntax to store a subroutine object in a variable, but it could certainly get a function object from the other language and pass it as an argument to another function in the other language.


   @@ -397,6 +499,10 @@
    could Ruby do with a Scheme list when it can't even get to the Scheme C<car>
    function?

   +{{ Except that Ruby would never even get a Scheme list in the first
   +place if it hadn't loaded a Scheme library of some sort. And, being
   +a list, the Scheme list would still support the standard vtable
   +functions for lists. --allison }}

???  What "standard vtable functions for lists"?  What's a "standard
list" in this context?

Keyed access to elements of the list. And optionally also push, pop, shift, and unshift.

A list is any aggregate data type that contains a (ordered or unordered) collection of values.

   @@ -430,10 +545,20 @@
    necessary) around it.  It is therefore not expected that all compilers will
    provide a way to define methods on all foreign classes for all language 
pairs.

   +{{ These should generally be handled by subclassing the parent
   +language class, and adding your method to the subclass.

Possibly.  But you may have trouble getting the called module to create
instances of your new class.

If the class implements the 'instantiate' vtable function, then any language can create instances of it.

If that's true, then great.  It may be that I'm being too pessimistic,
worrying about how to achieve CL AMOP compliance *and* be
Parrot-friendly at the same time.  (But that only affects multis, since
Lisp doesn't do single-dispatch per se.)

Ah, this explains a lot.

Again, by "method" I meant "multi variant."  If the new variant defined
in the called-language multisub is specialized on at least one
calling-language class, then it can only be invoked by code that is
already aware of both languages, and less care is required.  (I think.)

Well, maybe. It depends on the inheritance hierarchies of the multi-invocants to the call.

   +{{ That's "multiple dispatch" and "single dispatch". In general,
   +defining code in one language and injecting it into the namespace of
   +another language isn't the primary focus of language
   +interoperability. Using libraries from other languages is.
   +--allison }}

I don't see a sharp boundary between "using libraries" and "injecting
[code] into the namespace" myself.

With OO libraries there's a huge difference. With strictly procedural libraries, where the particular language involved doesn't have any way of calling subroutines in any namespace other than its own, then there's not so much difference.

Allison

Reply via email to