dunno if this is the kind of thing that is on-topic/of-interest here, I will
see...
figured I would include it (this being from an email to someone I know):
---
did start a little bit implementing some of the things I mentioned a
few days ago (restructuring the MI mechanism, making initial plans for the
implementation of delegation, ..).
I am wondering if a hybrid of class/instance and prototype OO (as I
am imagining it) is at all interesting
It can be if you are breaking new ground. I am wondering about all the
restrictions and problems/bugs such a language has. Thats the first thing to
look at.
I am not sure if I am breaking new ground or not...
I have not really seen anything in this area before of late.
yeah, it is odd at least...
well, clearly at least some of the object system internals have become a
little horrid...
class/instance and delegation don't really like mixing.
I believe V8 uses classes shadowed behind objects. This is the approach I
would probably take, so an object methods or slots are altered in definition
then a new cloned class is created with the modifications made to it, and
the objects class pointer is then pointed to this new class.
This seems the most logical and sensible approach and could also support
classes.
yes.
I have anonymous classes, but I did not use them this way in my case, the
main reason being that classes are not exactly free (they have a number of
fields, tables, and sub-pieces). so, creating lots of specialized classes
would waste lots of memory...
so, my trick is that the base class stores most of the fields (the
class-defined fields), and a special side-object holds any new slots. in
this way, the storage and performance overhead is not much worse than other
use of prototype objects, however accessing prototype object slots, in
general, incur worse costs than class-slots (slot has to be looked up,
rather than consisting simply of a few pointer operations).
granted though, much of this can be sped up via hash tables.
now, however, if one were going to make a whole lot of these objects
(bunches of copies of a single tupple, ...), then the use of anonymous
classes makes more sense.
the use of prototype features then makes more sense for dictionaries and
dynamically constructed/modified objects.
actually, the more 'elegant' option would be to basically implement
class/instance as an abstraction over a prototype system, exposing some of
the internals at least as far as features go. my system is, however, going
the reverse and hacking prototype features on top of a class-instance model.
I like V8's approach its the one I would take, it seems most logical for
both prototype and class based approaches.
yes, ok.
well, I don't specify the internals, only that there are objects and it is
possible to add slots at runtime, and that these will not effect the base
class.
there is a slight issue related to the semantics though, namely it
would be possible to make the delegation model completely formal/provable,
but at a certain cost:
new slots/methods in delegated-to objects, beyond the delegated base
class, would remain effectively hidden.
conventional prototype/delegate semantics will remain possible
within the implementation, but at the cost of not being statically
checkable.
examples (again, hypothetical language):
class A {
double x, y;
delegates double len() { return(sqrt(x*x+y*y)); }
}
class A1 extends A {
double z;
delegates double len() { return(sqrt(x*x+y*y+z*z)); }
}
class B {
delegates A a;
void B(A ra) { a=ra; }
}
B obj=new B(new A1);
obj.x //OK
obj.y //OK
don't you mean 'obj.a.x' ? Or just 'class B { deleages A; ...}' ... or
something ?
this is the whole thing with delegation.
the accesses see "through" 'a', as if the contents of class 'A' were
incorporated into 'B', only that the state for 'A' is located in a different
object.
and so, writing 'obj.a.x' is not needed (this is not delegation, but
would be allowable), whereas leaving out the name would make it essentially
no longer possible to reference or modify the delegates.
so, basically, the behavior of delegation is essentially analogous to
runtime assignable inheritence (this is actually the role it typically
serves in many prototype-based languages, such as Self).
Okay so you still have a handle to the delegate.
My only worries are name clashes, what happens there is there are two
delegates and a subscribing class that all have an 'x'. How do you resolve
that logically ?
I suppose at least you still have the handle and can explicitly access it
and its sub objects.
yes, one can explicitly access it...
as for name lookup, usually it is looked up according to rules similar to
Self:
first the current object is checked;
then any delegates are checked in-turn.
at present, it first checks the first delegate, then the next, ...
the rule is that the first found match is used.
like Self, the lookup allows cyclic graphs (a stack is used to prevent
infinite recursion), and like Self, multiple delegates are allowed
per-object.
so, basically I am trying to merge together the object models from Java
and Self...
Yeah. V8 was developed by Lars Bak who did the Java HotSpot engine, and
Self too.
may need to look into this...
obj.z //BAD, A1::z is not statically visible from B
obj.len(); //OK, A1::z is provably visible from the method
A1::len()
now, a big question is one of interfaces:
interface C {
double x, y, z;
}
C obj1;
obj1=obj; //?, B not statically provable to conform to C
//?, B does not implement C (interface injection,
of sorts...)
obj1.x //OK
obj1.y //OK
obj1.z //?, would work in implementation, but is not
statically verifiable.
?, these features could be made to work in practice, but are
theoretically unsafe and could be rejected by a verifier (likely the default
case for 'secure' code).
also possible would be to allow these, but also allow an exception
to be thrown should the operation fail (VM level, the object system API
currently does not throw exceptions).
fully dynamic prototype OO may be possible in the implementation by
adding a feature similar to that used for implementing prototype objects:
the addition of a virtual "super-interface" capable of interfacing
with "any possible object" (in effect the interface would contain every
possible slot and method it has seen).
a similar mechanism might be needed for the VM-level implementation
of delegating methods (that or, as considered before, having an explicitly
defined interface associated with the method).
I can imagine a few points of awkwardness though in trying to make
ES3 efficiently operate on top of this system (by default ES3 may use a few
"cheap tricks" to make itself work, but absent specific declarations and
type annotations may be slower than is ideal).
some semantic restrictions may also be placed on objects created "ex
nihilo" is ES3 land, namely that these objects will not be compatible with
Java-land (likely even via interfaces), although it could be possible to
make them accessible via an API.
so, the same object system could be used in both cases, but not all
objects will be compatible due to language-level semantic differences.
a common superset language, such as likely ES4, could probably
handle these cases though (such as being able to produce usable objects and
utilize objects from both langs).
ES4 is going to be a damb site easier to implement now. But I would
still start with ES3.1
I would have to look into the specific differences...
but, whatever one has static types and classes is worth consideration.
actually, my last major script language included a lot of things that
have apparently been borrowed by ES4 (but, then again, I borrowed a lot of
ideas from JavaScript and ActionScript as well, so I guess ES4 had them
first in a way...).
ES3.1 is only 3 + things like object accessors (get/set) plus
Object.freeze and lambda coding which will be used by the _new_ ES4 called
"Harmony" to create classes.
ok, ok.
well at least they added lamba...
now this brings up a thought:
I thought ES3 already had closures?...
will have to look into this...
Here's Brendan Eich's email to the es-discuss list :-
https://mail.mozilla.org/pipermail/es-discuss/2008-August/006837.html
Just in case you did not read it.
And here's the es3.1 drafts :-
http://wiki.ecmascript.org/doku.php?id=es3.1:es3.1_proposal_working_draft
Have not read them myself yet.
yes, I will probably need to look into all this...
for many things though a "least common denominator" approach may be
needed.
or such...
I am now going back to looking at separate languages in a framework
much like .NET CLR & DLR but with Multiple Inheritance.
I still continue to study ES4 RI for a while longer though.
yeah...
I am writing a framework, but right at this point I don't intend to try
to innovate much with languages, more rather to try to implement a framework
that can handle several different languages.
as for .NET, well they have achieved a good deal more goals in this
direction, but as has often been noted NET makes a good deal more legal pain
as well...
Mono seems all right legally they are doing a moonlight to mirror
silverlight.
Mono itself has some legal issues.
it exists, but there are I think some MS liscense and patent issues in the
mix (many parts of the .NET framework are under MS patents), so Mono exists
more because MS allows it to exist, but it is not entirely free of legal
issues. I guess the current standing is that there is a an agreement between
MS and the Mono developers that MS will not sue over the patent issues.
I just don't really trust all this, I would much rather things stayed more
in "clear water" (ie: well away from patented technologies).
I guess this is actually a notable reason for Mozilla focusing more
attention on Tamarin, and generally not looking much into .NET or Mono...
Moonlight is going to be in Firefox soonish when its ready.
ok.
I would suspect probably as a plugin rather than a core component.
I read some things before over all this, namely that I guess their official
position was to develop and pursue Tamarin rather than Mono largely on the
grounds of concern over possible patent issues (ie: Mono may be ok, but
Firefox may not be, since FF is the primary competitor of IE, and so
although Mono itself is safe, FF may fall outside the agreement if Mono were
to be integrated as a core component, whereas for a plugin people can just
stop using it without compromising the whole project...).
similarly, for this and several other reasons, I have focused more
effort on using the JVM design as a base.
I never like the JVM, specs where not that great, or well defined, too
much like a toy machine for my liking. Only has single inheritance, generics
came late and were not that powerful, basically using type erasure I
believe.
generics exist at the language level, and I have not looked into how they
are implemented (the JVM, at the bytecode level, doesn't really care about
many things).
now, granted the JVM itself is a much smaller and in many ways cruftier
design, but it can be implemented in such a way that the interpreter runs
fairly efficiently, whereas both .NET and AVM2 would require JIT to run
efficiently (or, at least an internal bytecode rewrite pass).
the main difference is that the JVM fully specifies most types in the
bytecode, and focuses more on their concrete representation (after all, this
is why long and double are defined to require 2 stack elements, ...).
both .NET and AVM2 seem to define the bytecodes a little more abstractly,
requiring either a dynamically typed interpreter (slow), or recompiling the
bytecode into another representation (a lower-level bytecode, or full JIT).
so, as I view it, both MSIL and AVM2 are probably better as far as an IR
goes, but JBC is better as far as an interpreted bytecode goes.
JIT more or less "levels the field" though, since any likely effective JIT
will have to do much of the same things anyways (stack tracing, code
restructuring, ...).
if I ever produce something really usable/useful, it would be worthwhile
to have a fairly open and not "too" novel design...
if I can manage to get it implemented, and get several existing
languages targetted to it, this would be a worthwhile goal I think...
as well, it is good to have an implementation and design that is
clonable...
You need good specs for that.
yes, my specs thus far are not so good, but I document things where I can.
sadly, most of my documentation is strewn about various text files, and it
is not clear which parts are valid, which were just ideas, which are out of
date, ...
at one point, I had a convention for this (reviewing files and adding
special "marks" to the filenames), but I have not kept up with this...
sadly, properly documenting everything would be no small task...
as far as the JVM goes, the specs can hardly be called "good", but they are
understandable if one puts some effort into it (and goes in search of the
proper pieces of documentation...).
so, I am partly using it as a "base", but I am developing many of my own
things as well (in its full form, my VM will use a somewhat modified
bytecode, ...).
also, the major emphasis is not on the bytecode (as is the case with most
VMs), rather a good deal of emphasis is placed on all the internal machinery
and frameworks, for which I am trying to develop clean and usable APIs.
so, it is not a centralized "ivory tower" design, but is intended to be more
of an open-ended toolbox of loosely coupled parts (much more like OpenGL or
POSIX).
what it "is" is what you make from it, not something intrinsic in the
"design"...
however, a bytecoded VM is itself a fairly powerful tool, and so is being
developed to be added to the "toolbox", however many of the parts this VM
will depend on are also independent and exposed elsewhere with their own
APIs...
of course, the big catch is that all of this is C based, and so not of as
much use if one doesn't like C, or wants a centrally-integrated "whole".
sadly, the JVM, as are most other VMs in existence, is by default a very
centralized and "ivory tower" design, but oh well, I can try to make it work
as a component, and maybe generalize it so that it can interoperate nicely
with my other stuff...
in most VMs, the "toolbox" AKA "framework" is built on top of the VM,
whereas in this case the idea is that it "is" the VM, and that the design
more "digs downwards" than builds upwards.
so, rather than getting all this flexibility by building yet another "layer
of abstraction", one tries to dig through what things already exist, to be
able to handle all of this already existing stuff (common APIs, ...) as one
big and reflective piece of machinery.
for example, I would want, for example, ECMAScript, rather than having
everything wrapped up nicely for itself, is able to play in the bigger
"outside world" of all of the code that already exists (C land and similar).
a capable script may well have access to the same VM and machinery used to
implement itself, and the C compiler, so for example a piece of JS code
could very well construct a piece of code that compiles itself to machine
code and accesses C API's, or FWIW is self-modifying.
now, granted such capabilities are as much dangerous as they are useful, and
so it is my eventual plan to integrate a fairly strict security model into
everything as well (bytecode also has this use as well, as I realize that
strictly enforcing a security model within C code would be nearly
impossible, but bytecode makes this kind of thing far more plausible without
compromising the power of the system).
also this is another reason why static typing and formal checking is being
pursued for many components (beyond performance and optimization reasons).
as well, bytecode may also allow higher performance, at least in terms of
dynamic facilities, since it adds more capabilities for both separation of
issues and optimization, vs a more traditional linear-compilation design
(where nearly everything has to go through the whole compiler tower).
for example, the one-off results of an eval expression need not get compiled
all the way down to machine code (wasting both time and creating potentially
non-collectable garbage), and as well, bytecode fragments can be crafted
explicitly (rather than having to go through preprocessing and having to
grind though a whole bunch of contents from various system headers, ...).
so, in some ways, bytecode could also fill a similar role to what I am doing
in many places with dynamically crafting specialized chunks of assembler
(but at a much higher level of abstraction).
ok... granted I would probably need an abstraction over the bytecode, such
as it would be far more convinient to craft a chunk of PostScript-like code
than a JBC class-file, but yeah...
so, yeah, FWIW I will probably need to add a specialized PostScript-like VM
somewhere in the mix as well...
hmm, I could partly/temporarily redirect my efforts since this would be
probably of more immediate use (and less work) than a JVM anyways...
a few notes:
I have used specialized PostScript like languages in the past to good
effect, only that PS is not good for a script language IME (too damn
awkward, and then later one forgets just what the hell their scripts were
doing anyways).
internally, the upper and middle/lower stages of my C compiler communicate
using a somewhat PS-infuenced language as the IR, and in general a PS-like
structure is very convinient for dynamically crafted code, only that it is
rather poor for end-user scripts, where a more conventional syntax (C-style)
is by far more preferable.
however, as-is, my compiler IR is not particularly suitible for use in
non-compiled dynamic crafting, where something far more similar to proper PS
is needed (non-modular, includes an external visible scope rather than
having to declare everything, ...). oh yes, and likely being compiled to
bytecode rather than necessarily going all the way down to machine code...
very likely, such a language will have visibility of the C toplevel and
functions (my framework already has this, but for different reasons), and as
such would need little or no explicit FFI (although granted external
function calls would use a different syntax than internal block-based
calls).
potentially, it would also make sense for it to have access to the object
system.
note, further:
this would not halt or redirect the JVM effort (just as the JVM effort did
not entirely halt my plans to get an ECMAScript VM working, this goal having
somewhat infuenced the design of the object system).
rather, it would be a much smaller effort than either of these 2, and will
likely have much more immediately useful effects (aka: serving a similar
role to, but being distinct from, specialized ASM crafting...).
or such...
_______________________________________________
fonc mailing list
fonc@vpri.org
http://vpri.org/mailman/listinfo/fonc