By way of introduction, we quickly hit the law of diminishing returns when we spend a lot of time justifying the existence of Parrot. Especially when we could be spending that time finishing off Parrot. At the end of the day, no amount of talking will convince the skeptics. A completed virtual machine in production use will convince more, and make the remaining skeptics irrelevant.

That said, I've spent some time here in the hope that this can work its way into a document, so next time these questions come around we can say "read the FAQ".

Will Coleda wrote:
1. Why Parrot?

http://www.parrotcode.org/docs/intro.html:

"Parrot is designed with the needs of dynamically typed languages
(such as Perl and Python) in mind, and should be able to run programs
written in these languages more efficiently than VMs developed with
static languages in mind (JVM, .NET). Parrot is also designed to
provide interoperability between languages that compile to it. In
theory, you will be able to write a class in Perl, subclass it in
Python and then instantiate and use that subclass in a Tcl program."

a. What, precisely, about Parrot makes possible more efficient
execution of a dynamically typed language than would be the case with
the JVM or the CLR?

This is an old FAQ entry that needs to be updated. At the time it was written, there was an enormous gap between Parrot and the performance of the JVM/CLR in handling dynamic languages. (Note: not just "dynamically typed languages". Dynamic typing is one small aspect of dynamic languages in general.)

The JVM & CLR have made progress, but they're still not all the way to full handling of dynamic languages. They think they are, and are quite happy to sit back and declare that they have the dynamic languages problem licked. The only way they're ever going to tackle the full problem is if someone else does it first to show them how. Just like the only reason they ever tried working on dynamic languages in the first place was because Parrot was there to show that a virtual machine could do more than they imagined possible.

Back to the specific question: dynamic typing is probably one of the least interesting features of Parrot. It's handled by the fact that a PMC container can hold any type of PMC, and assignment between types is handled by a set of standard vtable functions on the source PMC for retrieving its value and on the destination PMC for setting its value.

b. Whatever that is, how will it adversely impact the execution of
statically typed languages, including type-inferred languages?

Since type declarations are not required, implementing a statically typed language on a dynamically typed virtual machine means adding additional code to do the type checking. This is likely less efficient than implementing a statically typed language on a statically typed virtual machine (though, likely not much less efficient, since the statically typed virtual machine still has to do the type checking). Someday we'll run some benchmarks to compare.

c. How will this impact the execution of statically typed code in
Perl, Python and other targeted languages?

That question doesn't make sense. Perl and Python don't have statically typed code. See 1b for comments on efficiency of statically typed languages.

In general, we aren't targeting static languages (again, I'm referring to a more general category than just "statically typed languages"). We may implement a few static languages on Parrot so they can use Parrot's libraries and tools. Static languages don't take advantage of the advanced features of a dynamic virtual machine. They may not be fast in an interpreted environment because they aren't designed for an interpreted environment. They're specifically designed to take advantage of a statically compiled environment by eliminating all dynamic features. I'm not going to get into a discussion of whether static languages or dynamic languages are "better". They're just different creatures, and comparing them is about as useful as comparing a hybrid car optimized for fuel economy with a race car optimized to win the Daytona 500.

2. General Features

a. How will Parrot support reflection and attributes?

Simply put, reflection is the ability for code to access information about itself and modify its own behavior. This is a concept so deeply ingrained in the design of Parrot that the hard part of answering the question isn't figuring out how Parrot supports reflection, but figuring out which particular features to highlight. How about the fact than instead of using a stack to control the flow of a program, it uses introspectable continuation objects? Or the fact that subroutines, exceptions, and namespaces are all introspectable, modifiable, and can be replaced by subclasses with different behavior as long as they respect the interface.

By "attributes" do you mean instance variables for objects (what Parrot calls an attribute), or do you mean auxiliary data attached to an object (what the CLR calls an attribute, and Parrot calls a property). Parrot implements both.

b. How will Parrot support generics types?

Generics are mostly a static language way of allowing a tiny bit of semi-dynamic behavior. There are many ways to do the same thing in Parrot. The most literal-minded parallel would be declaring a class that accepts a parameter on instantiation specifying the type of some element that it contains or operates on. For example, the following code might be used to instantiate a generic aggregate that holds elements of type MyElement:

$P0 = find_class MyGenericAggregate
$P1 = $P0.new(elementtype=>'MyElement')

c. How will Parrot support interface types?

An interface is a role with no attributes and no implementation for its methods (or, more specifically, it has implementations for its methods that throw an exception complaining that the method needs to be implemented).

d. What kind of security models will Parrot support?

The architecture is still in early stages. (Let us know if there's a particular model you need.) In general we're taking a sandbox approach.

e. How will Parrot support small-footprint systems?

The absolute minimum needed to run Parrot is a bytecode interpreter. We're aiming to fit a bytecode interpreter in 32M. Extremely small, but that's what's needed to run on most modern cell phones. There isn't currently active development work in this area.

f. How will Parrot support direct access to "unmanaged" resources?

My original answer was that "unmanaged" resources are a notion from the CLR, and not really meaningful in the Parrot context. But from your followup message it sounds like you actually mean access to C-level resources. UnmanagedStruct (which Joshua mentioned) is one way, and provides a Parrot interface to a C structure that isn't memory managed by Parrot. NCI is another way, allowing calls into and returns from C functions. In general, Parrot will never provide direct access to C-level resources, it will only provide access through an interface, where the interface handles the translation between C-like behavior and Parrot-like behavior. As much as possible, those interfaces are defined in a standard way so that using a new external resource from within Parrot doesn't require writing an entirely new interface layer from scratch, but only requires reusing, or easily extending an existing interface layer.

g. How will Parrot facilitate distributed processing?

Parrot will provide a standard set of tools for concurrency. And, the fact that Parrot provides a standard interface across multiple platforms is an advantage to distributed processing. Distributed code can be written to run on the Parrot virtual machine, abstracting away from the details of the particular hardware or operating system. We'll also provide a standard set of networking protocols, and tools for managing some of the standard distributed "messaging" systems (SOAP, JSON, AJAX, etc). We don't currently have any plans to support more advanced forms of serializing an execution state to carry between systems, but they could be hooked into the core (extensible) concurrency framework.

3. Parrot PMC Issues

The Parrot PMC vtable provides a large number of optional functions,
which PMCs can either implement or not. If not implemented, they will
throw an exception at runtime.

Or, will fall back to a default implementation.

a. What support will Parrot provide a compiler to interrogate a PMC at
compile time to know what it actually implements?

Some custom vtable functions like "can", "does", and "isa", but when all else fails, you can fall back on "inspect" which gives you all the nitty-gritty details about a PMC/object.

All of these functions appear to be predefined because there is no
mechanism for extending this functionality at runtime. It appears that
compilers will be limited to implementing functionality that is
defined in the vtable. The vtable contains the common operations
required by certain languages.

What kind of dynamic virtual machine would we be if we didn't allow functionality to be extended at runtime? PMCs are just objects. To extend the functionality at runtime, subclass the PMC and extend the subclass. Or, add a runtime role to the object.

b. How will Parrot handle languages with operations that are not
provided?

Parrot provides low-level operations. If the HLL has a more complex feature, the compiler translates it down to a series of low-level operations. Ultimately all languages compile down to machine code, so I'm not at all likely to be convinced that an HLL may come up with a feature that can't be implemented as a combination of low-level operations.

http://www.parrotcode.org/docs/vtables.html:

"To be perfectly honest, this is a slightly flawed example, since it's
unlikely that there will be a distinct "Python scalar" PMC class. The
Python compiler could well type-inference variables such that a would
be a PythonString and b would be a PythonNumber. But the point remains
- incrementing a PythonString is very different from incrementing a
PerlScalar."

This document is very old, and currently being replaced.

c. How will Parrot address cross-language semantics?

All languages are implemented in terms of low-level Parrot operations. A given language can have any semantics it wants, it just composes that behavior from low-level components. When one language is interacting with objects from another language, it performs standard Parrot operations on those objects, so the objects can respond in the same way they would respond to the same operations called from their own language.

(I once spent an hour trying to explain this to the CLR guys and they just couldn't understand it.)

d. Will each language have to provide its own support for interacting
with PMCs for other languages?

No, all they need to do is call standard opcodes on the PMC from other languages. Each PMC provides its own vtable functions for (as an example) returning a string, integer, number, or PMC value.

e. How will a PerlScalar interact with a PythonString?

Interact how? If you assign the value of a PythonString to a PerlScalar, the value will be extracted by a standard vtable function on the PythonString, and assigned by a vtable function on the PerlScalar.

f. What will happen when a PythonString is incremented in Perl code?

The code will call the increment vtable function on the PythonString PMC.

Comparing the vtable for a PMC to the JVM and CLR base Object classes,
the PMC is essentially an "abstract" class with dozens of
"unimplemented" methods, while Java's Object provides (and implements)
the following public methods:

  equals getClass hashCode notify notifyAll toString wait

This doesn't make any sense. Are you comparing Parrot's "default" PMC to Java's Object? It would make more sense to compare Parrot's Object to Java's Object.

Discounting the methods related to Java's peculiar threading
implementation, that's:

  equals                 getClass hashCode    toString

Similarly, the CLR's CTS Object provides:

  Equals ReferenceEquals GetType  GetHashCode ToString

And Parrot's Object provides:

isa can does get_attr set_attr get_class inspect name find_method

g. Why is it a good thing that PMCs essentially non-contractual
abstract base classes that define a lot of functionality without
implementing it?

Parrot implements sane defaults for the majority of PMCs. But considering the wide range of types implemented as PMCs (scalars, aggregates, subroutines, coroutines, continuations, namespaces, exceptions, threads, iterators, STM, etc) there really isn't a sane default for most operations that will apply to all PMC types. So, instead, the sane defaults are built up by a chain of inheritance. For example, all the different array types inherit sane defaults from a core array type.

Perhaps what you're trying to ask is why we define a standard set of vtable operations, instead of allowing a PMC to create any arbitrary vtable entries. This goes back to the core design of interoperability across languages. All PMCs are guaranteed to provide a sane response to the standard vtable operations, even if that response is a "not implemented" exception.

h. Why is there no first-tier depth in Parrot's type system, such as:

  PMCString, PMCIntger, PMCNumber, ...

At the time the initial PMC system was implemented, Parrot had no notion of namespaces. That is changing now. (Though, we'll never have a namespace hierarchy level called "PMC", as that's an implementation detail, not type information.) And yes, types are connected to namespace hierarchies, though it's not always a one-to-one correspondence.

4. Parrot VM Issues

Parrot provides what it calls "registers" with no guarantee that these
map to hardware registers.

a. Will any registers ever map, in a Parrot-controlled way, to hardware
registers?

Well, of course they sometimes map to hardware registers underneath.

b. How can a compiler efficiently allocate registers if it does not
know which ones will map to hardware registers?

Hand-rolled allocation is never as efficient or as reliable as programmatic allocation. The virtual machine handles the efficient allocation of registers. The HLL compiler running on the virtual machine doesn't pay any attention to it. This is an advantage of Parrot, allowing new HLLs to be quickly and easily implemented without reinventing low-level wheels like garbage collection and register allocation.

5. Parrot Design Issues

Parrot has many operators and number of Core PMC types for them to
operate on. Parrot has so many operators that it appears to be using
them instead of having a standard library. This is markedly different
than the CLR and JVM systems.

a. Why was this done this way?

By operator, I'm assuming you mean opcode.

Since this is a *virtual* machine, the only real difference between an opcode and a function is how you call it. See the last two entries in <http://www.parrotcode.org/faq/>

b. What is the basis for deciding what will be an operator?

It's essentially a design decision of how core the operation is, how frequently it will be used, and how standard it will be across all the languages implemented on Parrot. Non-core, rarely used, or behavior that varies widely between languages isn't canonized as an opcode (or is canonized as an opcode that simply calls the relevant vtable function on a PMC).

c. How can substantial quantities of additional functionality be added
to this design cleanly?

As libraries: dynamically loaded opcode libraries, libraries of low-level functions, or libraries written in PIR or an HLL and compiled to bytecode.

Allison

Reply via email to