Prototypal Inheritance from Native base

215 views
Skip to first unread message

Henrik Lindqvist

unread,
Mar 15, 2010, 6:35:15 PM3/15/10
to v8-users
To my knowledge, inheritance in JavaScript should be written:

function Base () {
// Initialize Base
}

function Derived () {
Base.call(this); // call Base constructor and initialize Base
"parts"
// Initialize Derived
}
Derived.prototype = new Base;
Derived.prototype.constructor = Derived;


How do I allow for this to work if Base is a wrapped native instance
with an internal field, and Derived is a script only object?

When using Signature, args.Holder() seems to contain the prototype
instance of Base, not the inherited script Derived instance.

Anton Muhin

unread,
Mar 16, 2010, 12:10:12 AM3/16/10
to v8-u...@googlegroups.com
From the right address this time.

yours,
anton.

On Tue, Mar 16, 2010 at 7:07 AM, Anton Muhin <ant...@google.com> wrote:
> That's expected behaviour.  Roughly: for native methods to operate
> properly they assume holder naturally holds native data.  But you
> always have This() at your disposal to either find Derived or just
> read properties in normal JS way.
>
> hth and yours,
> anton.

>> --
>> v8-users mailing list
>> v8-u...@googlegroups.com
>> http://groups.google.com/group/v8-users
>>
>

Henrik Lindqvist

unread,
Mar 16, 2010, 10:01:20 AM3/16/10
to v8-users
I've finally got this working by using the internal field on
args.This() instead.

But a new problem arose. If the user should forget to call the Base
constructor in the Derived constructor, my native Base constructor is
never called for the newly created Derived instance!

Is there a callback for "new", when an instance of the prototype is
created?

If I do:

function Array2 () {}
Array2.prototype = new Array;
Array2.prototype.constructor = Array2;

The Array2 is correctly initialized, without having to
Array.call(this) in the constructor.

Henrik Lindqvist

unread,
Mar 16, 2010, 9:44:30 PM3/16/10
to v8-users
I've made a little test, see source below, that highlight my problem,
here is the output:

--- test 1 ---
Constructor: pointer=0x1 << prototype = new Base
Test: pointer=(nil)
Test: pointer=(nil)
--- test 2 ---
Constructor: pointer=0x2 << prototype = new Base
Constructor: pointer=0x3 << new Derived2
Test: pointer=0x3
Constructor: pointer=0x4 << new Derived2
Test: pointer=0x4
--- test 3 ---
Constructor: pointer=0x5 << prototype = new Base
Constructor: pointer=0x6 << new Derived3
Test: pointer=(nil)
Constructor: pointer=0x7 << new Derived3
Test: pointer=(nil)


Test 1:
If I'd like my native instance (Base) to be inherited as regular built-
in types like Array etc. Where should I
initialize it when the constructor is never called? Where does Array
initialize it's native parts when inherited?

Test 2:
Work. But only because the Base constructor i called. Built-in's don't
require this.

Test 3:
This is really wierd. Why does adding a property to the Derived
instance make the Constructor create/return, and/or the test function
be called with another "this". Bug?


I'm writing a runtime library for v8. I only want the users to be able
to use all the language features, including correct inheritance.


// g++ -m32 -Iinclude -L. test.cc -lpthread -lv8

#include <v8.h>

using namespace v8;

char* pointer = NULL;

Handle<Value> Constructor (const Arguments& args) {
args.This()->SetPointerInInternalField(0, ++pointer);
printf("Constructor: pointer=%p\n", pointer);
return args.This();
}

Handle<Value> Test (const Arguments& args) {
printf("Test: pointer=%p\n", args.This()-
>GetPointerFromInternalField(0));
return Undefined();
}

int main (int argc, char* argv[]) {
HandleScope scope;
Handle<ObjectTemplate> global = ObjectTemplate::New();
Persistent<Context> context = Context::New(NULL, global);
Context::Scope context_scope(context);

// native Base
Handle<String> class_name = String::NewSymbol("Base");
Handle<FunctionTemplate> constructor =
FunctionTemplate::New(Constructor);
constructor->SetClassName(class_name);
Handle<ObjectTemplate> prototype = constructor->PrototypeTemplate();
prototype->Set("test", FunctionTemplate::New(Test));
Handle<ObjectTemplate> instance = constructor->InstanceTemplate();
instance->SetInternalFieldCount(1);
Context::GetCurrent()->Global()->Set(class_name, constructor-
>GetFunction());

puts("--- test 1 ---");
Script::Compile(String::New(
"function Derived1 () {} \n"
"Derived1.prototype = new Base; \n"
"Derived1.prototype.constructor = Derived1; \n"
"(new Derived1).test(); \n"
"(new Derived1).test(); \n"
))->Run();

puts("--- test 2 ---");
Script::Compile(String::New(
"function Derived2 () { \n"
" Base.call(this); \n"
"} \n"
"Derived2.prototype = new Base; \n"
"Derived2.prototype.constructor = Derived2; \n"
"(new Derived2).test(); \n"
"(new Derived2).test(); \n"
))->Run();

puts("--- test 3 ---");
Script::Compile(String::New(
"function Derived3 () { \n"
" Base.call(this); \n"
" this.foo = true; \n"
"} \n"
"Derived3.prototype = new Base; \n"
"Derived3.prototype.constructor = Derived3; \n"
"(new Derived3).test(); \n"
"(new Derived3).test(); \n"
))->Run();

V8::Dispose();
return 0;
}

Stephan Beal

unread,
Mar 17, 2010, 6:38:50 AM3/17/10
to v8-u...@googlegroups.com
On Wed, Mar 17, 2010 at 2:44 AM, Henrik Lindqvist <henrik.l...@gmail.com> wrote:
   "Derived2.prototype = new Base;             \n"
   "Derived2.prototype.constructor = Derived2; \n"

IIRC, this isn't the way to do it in v8. i remember going through similar pain when i wrote my ncurses wrappper for v8, and now i find that i documented it:


see the section called "Inheritance...", near the end of the table of contents.

i hope that helps.

--
----- stephan beal
http://wanderinghorse.net/home/stephan/

Henrik Lindqvist

unread,
Mar 17, 2010, 9:11:25 AM3/17/10
to v8-users
"IIRC, this isn't the way to do it in v8"

I don't want to force users to do it the V8 way, I want them to do it
the JavaScript way.

You write in your derived constructor:
function MyPanel() {
var argv = Array.prototype.slice.apply(arguments,[0]);
this.prototype = this.__proto__ = new ncurses.NCPanel(argv);
// ...
return this;
}

What is the property this.prototype?
In the constructor, isn't "this" the instance, then it has no
"prototype" property, that is on the constructor (function).
I don't see why I should use the "__proto__" property to change the
prototype chain after the instance was created, the prototype chain
has already been specified.


On Mar 17, 11:38 am, Stephan Beal <sgb...@googlemail.com> wrote:
> On Wed, Mar 17, 2010 at 2:44 AM, Henrik Lindqvist <
>

Lasse R.H. Nielsen

unread,
Mar 17, 2010, 11:06:14 AM3/17/10
to v8-users
It won't work.

In JavaScript, the prototype based inheritance is only property inheritance. It does not extend to internal fields, like [[Class]] or internal values of, e.g., Date, Number, String, or Boolean.

You will have the exact same behavior if you try to inherit from, e.g., Date.
The internal time value of a Date object belongs to the Date object only, it is not inherited along the prototype chain.
That means that an object created using:
  function Foo(){};
  Foo.prototype = new Date();
  var foo = new Foo;
does not function as a Date object - it's internal [[Class]] property isn't "Date" and the Date specific functions will throw exceptions if called, e.g.:
  print(Object.prototype.toString.call(foo));  // prints [object Object], not [object Date].
  print(foo.getTime()); // throws "TypeError: this is not a Date object."


My guess at the problem of test 3 is that you are using the  Base constructor on an object that isn't created from the Base object template. That means that the object doesn't have an internal field slot 0 (or if it has, it's being used for something else), and you are just reading and writing some other field of the object that is later overwritten again, possibly by the foo property. The same happens in test 2, but the field just happens not to be overwritten before it's read.
(I.e., the code is unsafe, since it assumes an internal field count, but doesn't check that the object is created from the correct template).

Best of luck.
/L


2010/3/17 Henrik Lindqvist <henrik.l...@gmail.com>



--
Lasse R.H. Nielsen
l...@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K -
Denmark - CVR nr. 28 86 69 84

Henrik Lindqvist

unread,
Mar 17, 2010, 12:12:05 PM3/17/10
to v8-users
So I'am wrong that inheritance in JavaScript should be written:

function Base () {}
function Derived () {
Base.call(this);


}
Derived.prototype = new Base;
Derived.prototype.constructor = Derived;

If so, how do I allow for natives to be inherited in v8?
Is this a v8 or JavaScript limitation, or it just can't be done?

> 2010/3/17 Henrik Lindqvist <henrik.lindqv...@gmail.com>

Stephan Beal

unread,
Mar 17, 2010, 1:15:21 PM3/17/10
to v8-u...@googlegroups.com
On Wed, Mar 17, 2010 at 5:12 PM, Henrik Lindqvist <henrik.l...@gmail.com> wrote:
If so, how do I allow for natives to be inherited in v8?
Is this a v8 or JavaScript limitation, or it just can't be done?

Just a fore-warning... inheriting natives from JS can be tricky, depending on how the native "this" object is decoded from the incoming JS "this" handle. When multiple levels native inheritance are involved, it's possible to end up with JS classes where calling one member function might work but the next one (via a parent class somewhere else in the inheritance the chain) might not be able to find its "this" pointer. (Been there, done that.) Working around this type of problem requires, in my experience, special care to be taken when implementing the C++ wrappers. There are class-wrapping frameworks out there to help simplify this process. Mine, e.g., is:


i know a few other listers here have others, though.

Henrik Lindqvist

unread,
Mar 17, 2010, 3:13:48 PM3/17/10
to v8-users
In my library, not the test code above, I walk the prototype chain
looking for a native instance with an internal field. Your v8-juice
seems to do the same. If v8 dont allow for the regular inheritance
syntax, I'll look into the __proto_ property.


On Mar 17, 6:15 pm, Stephan Beal <sgb...@googlemail.com> wrote:
> On Wed, Mar 17, 2010 at 5:12 PM, Henrik Lindqvist <
>

Stephan Beal

unread,
Mar 17, 2010, 3:18:36 PM3/17/10
to v8-u...@googlegroups.com
On Wed, Mar 17, 2010 at 8:13 PM, Henrik Lindqvist <henrik.l...@gmail.com> wrote:
In my library, not the test code above, I walk the prototype chain
looking for a native instance with an internal field. Your v8-juice
seems to do the same.

Exactly, but it's a template-defined option, whether or not to walk the prototype chain. (It's only needed for inheritance, so it can be toggled off as an optimization for classes which don't need it.)

Henrik Lindqvist

unread,
Mar 17, 2010, 5:01:45 PM3/17/10
to v8-users
On Mar 17, 8:18 pm, Stephan Beal <sgb...@googlemail.com> wrote:
> On Wed, Mar 17, 2010 at 8:13 PM, Henrik Lindqvist <
> henrik.lindqv...@gmail.com> wrote:
> > In my library, not the test code above, I walk the prototype chain
> > looking for a native instance with an internal field. Your v8-juice
> > seems to do the same.
>
> Exactly, but it's a template-defined option, whether or not to walk the
> prototype chain. (It's only needed for inheritance, so it can be toggled off
> as an optimization for classes which don't need it.)

How would the native code know if walking the prototype chain is
needed or not? Whouldn't it depend on how the user calls functions in
JavaScript code?

Stephan Beal

unread,
Mar 17, 2010, 6:00:45 PM3/17/10
to v8-u...@googlegroups.com
On Wed, Mar 17, 2010 at 10:01 PM, Henrik Lindqvist <henrik.l...@gmail.com> wrote:
How would the native code know if walking the prototype chain is
needed or not? Whouldn't it depend on how the user calls functions in
JavaScript code?

Good question:


In short: the developer wrapping the native class decides for the user whether the feature is enabled or not (on a per-native-class basis). Most cases don't need prototype walking, but of course if inheritance is used then it must be enabled. The option is, in that library, togglable because a specific client suggested it as a performance optimization (they were using it in a high-load server environment).

:)

Lasse R.H. Nielsen

unread,
Mar 18, 2010, 4:25:28 AM3/18/10
to v8-u...@googlegroups.com
No, you are correct, this is how prototype base property inheritance works in JavaScript. However, prototype based inheritance is not the same as class based inheritance, and it doesn't work the way inheritance works in, e.g., Java.

This is a JavaScript limitation. Inheritance in JavaScript is *property* inheritance only. In class based inheritance, the inheriting class copies all structure from the base class, wheras in prototype based inheritance the inheriting object does not inherit any structure. It merely has a pointer to another object, and property lookups (only!) follow this pointer. In all other ways, the inheriting object is completely unrelated to the prototype.
Another way to say the same is that there are no classes in JavaScript (in the sense of class based OO). Using constructors and prototypes can give something that emulates classes, but it is not the same.

You can have your functions on the Base prototype follow the prototype chain of its "this" value to find an object that does implement the internal structure it needs (if any exist). However, that object will be shared between all instances of Derived, so the internal state will essentially be "static" (in class-based terms).

You might be able to use __proto__ to create a new Base object that inherits Derived.prototype. E.g.:

 function Derived(args) {
   var base = new Base();
   base.__proto__ = Derived.prototype;
   return base;
 }
 Derived.prototype = {__proto__: Base.prototype, constructor: Derived };  // [1]

This ensures that 
   new Derived() instanceof Derived
   new Derived() instanceof Base
   Object.toString.call(new Derived) == "[object Base]"
and new Derived() has the necessary internal structure to support the functions inherited from Base.prototype.
I.e., you need an object that is created using the ObjectTemplate you created for Base for the associated functions
to work, so you must create one of those - which you can only do (from JavaScript) using "new Base".
I think it should work (although I haven't actually checked yet).

/L
[1]  I prefer this to using Derived.prototype = new Base(). If emulating class based inheritance, one should inherit from the class, not from an instance, and the prototype represents the class (more than the constructor function does).

Henrik Lindqvist

unread,
Mar 18, 2010, 11:04:35 AM3/18/10
to v8-users
Thanks for you thorough reply.

I now understand that users have to use __proto__. Then I can rely on
Signature's and Holder.

> <henrik.lindqv...@gmail.com>wrote:

Seiji Sam Lee

unread,
Mar 19, 2010, 6:17:26 PM3/19/10
to v8-u...@googlegroups.com
Hi!!

I have a problem with two nested context, one is a master context, and the
other one is a child context.

Some like this:

//This is how use the master context
void UserContext::execute()
{
PageContext*pc=new PageContext();
{
HandleScope hscope;
Context::Scope context_scope(_context);
_context->Global()->Set(String::New("hello"),String::New("hello
world!!"));
_context->Enter();
pc->run();
_context->Exit();
}
delete pc;
}

pc->run() use other context, both share same SecurityToken (sure!!, an
string with an UUID) and child context have got an object ($) with is a
reference of master global object.

Well, a code executed into the child context doesn't have access to $ member
'hello', in fact $ is undefined or empty (depends of the code). Never I
couldn't see 'hello' member into $ (or master global object).

Is it normal? (sure not, but I don't know the solution)

Reply all
Reply to author
Forward
0 new messages