how to return an object from a getter.

66 views
Skip to first unread message

vlad

unread,
Nov 21, 2008, 3:10:20 PM11/21/08
to v8-users
I have implemented 2 Javascript classes in C++, Camera and Point. I
can currently do this:

[code]
var camera = new Camera;
var point = new Point(x, y, z);
camera.position = point;
[/code]


I can get the values of point, inside Camera:position and set the
position of the camera fine.
My issue is that i don't know how to return a Point object when I do:

[code]
var point = camera.position;
[/code]


This is what I current have for setting and getting the
Camera::position variable, which is of type Point.


/**
* Get the position of camera.
*
* <javascript>
* usage: var vector = $camera.position;
* </javascript>
*/
v8::Handle<v8::Value>
jsi_Camera_get_position(v8::Local<v8::String> property, const
v8::AccessorInfo& info)
{
JSCamera* camera = jsi_internal_Camera_unwrap_camera(info.Holder());

// Change the camera.
std::stringstream ss;
ss << "Camera.position (get)";
BBB::log(ss.str());

// How to return a Point?

return v8::True();
}

/**
* Set the position of camera.
*
* <javascript>
* usage: $camera.position = new Point(5.0, 5.0, 10.0);
* </javascript>
*/
void
jsi_Camera_set_position(v8::Local<v8::String> property,
v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
JSCamera* camera = jsi_internal_Camera_unwrap_camera(info.Holder());

// ------------------------------------- //
// Make sure we have an object.
if (!value->IsObject()) {
std::stringstream ss;
ss << "Camera:position -- Argument must be of type [object Point].";
BBB::log(ss.str());
return;
}

// Get the C++ class in this javascript object.
v8::Local<v8::Object> pointObj = value->ToObject();
v8::Local<v8::External> external = v8::Local<v8::External>::Cast
(pointObj->GetInternalField(0));
C4::Point3D* point = static_cast<C4::Point3D *>(external->Value());
// ------------------------------------- //

// Set the position of the node.
camera->SetNodePosition(*point);

// Change the camera.
std::stringstream ss;
ss << "Camera:position (set)";
BBB::log(ss.str());
}

vlad

unread,
Nov 25, 2008, 11:11:39 AM11/25/08
to v8-users
Is there no one that knows about this?

luiskarlos

unread,
Nov 25, 2008, 12:21:24 PM11/25/08
to v8-users
Maybe you can try this:

// create the C++ Point to be wrapped
Point* p = new Point();
p->x = args[0]->Int32Value();
p->y = args[1]->Int32Value();

// make a persistant handle for the instance and make it
// weak so we get a callback when it is garbage collected
v8::Persistent<v8::Object> persistentPoint =
v8::Persistent<v8::Object>::New(args.Holder());
persistentPoint.MakeWeak(p, v8::WeakReferenceCallback
(Point_Destroy));

// set internal field to the C++ point
persistentPoint->SetInternalField(0, v8::External::New(p));

return persistentPoint;

I take this from http://home.cfl.rr.com/filedump/v8test.zip, I guess
it should work in the same way. :)..

vlad

unread,
Jan 16, 2009, 8:47:51 PM1/16/09
to v8-users
I'm trying to use this method, but the object it returns is
interpreted in the Javascript side as the class which is whold this
variable, not as the type of variable it is. For instance, if I'm
doing this:

alert(this.instanceOfSomeClass,someVar);

the return value is assumed to be of type:
SomeClass

not of type 'someVar'.

How can I change this so that the return value is seen as being of
type 'someVar'?

On Nov 25 2008, 12:21 pm, luiskarlos <luiskar...@gmail.com> wrote:
> Maybe you can try this:
>
>      // create the C++ Point to be wrapped
>         Point* p = new Point();
>         p->x = args[0]->Int32Value();
>         p->y = args[1]->Int32Value();
>
>         // make a persistant handle for the instance and make it
>         // weak so we get a callback when it is garbage collected
>         v8::Persistent<v8::Object> persistentPoint =
> v8::Persistent<v8::Object>::New(args.Holder());
>         persistentPoint.MakeWeak(p, v8::WeakReferenceCallback
> (Point_Destroy));
>
>         // set internal field to the C++ point
>         persistentPoint->SetInternalField(0, v8::External::New(p));
>
>         return persistentPoint;
>
> I take this fromhttp://home.cfl.rr.com/filedump/v8test.zip, I guess

vlad

unread,
Jan 22, 2009, 10:56:49 AM1/22/09
to v8-users
I am still having problems returning an object from a getter, or from
any function from that matter.

I can't just call the same constructor callback that I use to create
the object, because v8::Arguments constructor is private. And it
doesn't seem like proper approach either.
I also tried the solution that luiskarlos sudgested, but that's not it
either. Some is returned, but there's no way to tell V8 that the
return object is of X type -- it always seems to believe that the
returned object is of the type doing the returning. Plus, if this were
the way to return an object instance, then it would mean that you have
to REdeclare destructor callbacks for those object instances.
I would have though that FunctionTemplate would have some method of
instantiating an instance, but I don't see any methods of doing this.

Can someone please shine some light on this?

How can one return an object instance of type X from a function or
method?

vlad

unread,
Jan 22, 2009, 11:43:26 AM1/22/09
to v8-users
Also, I've been looking over the Google Chrome source code, but can't
find examples of this. If anyone knows where I can find example under
the Chrome source tree, please speak up.

Matthias Ernst

unread,
Jan 22, 2009, 3:53:21 PM1/22/09
to v8-u...@googlegroups.com
Create a static ObjectTemplate for "Points" and set accessors and
functions on it.
From the function, you return an pointTemplate->NewInstance().

Here's an example I have handy for "Prices", the object being backed
by a C++ "Price" object:

+Handle<ObjectTemplate> PriceTemplate() {
+ Handle<ObjectTemplate> result = ObjectTemplate::New();
+ result->SetAccessor(String::New("amount"), GetPriceAmount);
+ result->SetAccessor(String::New("currency"), GetPriceCurrency);
+
+ result->SetInternalFieldCount(1);
+ return Persistent<ObjectTemplate>::New(result);
+}
+
+Handle<Object> WrapPrice(const Price *p) {
+ static Handle<ObjectTemplate> price_template = PriceTemplate();
+
+ Handle<Object> result = price_template->NewInstance();
+ result->SetInternalField(0, External::New(const_cast<Price *>(p)));
+ return result;
+}

vlad

unread,
Jan 23, 2009, 1:25:57 PM1/23/09
to v8-users
Thank you very much for the info, Matthias. Although, I have to admit
I haven't been able to get it working properly, yet.

Is there a way to pass arguments when creating new instances using
this method? I'm running in to issues where I define the constructor
for a function:

... = FunctionTemplate::New(constructor_callback);


Handle<Value> constructor_callback(const Arguments& args[])
{
if (args.Length() != 3)
{
return throwArgLengthException(3);
}
}


------
Now, when I call NewInstance() on the ObjectTemplate, I guess it calls
the callback function. That in turn complains that the object needs 3
arguments (as it should).

On Jan 22, 3:53 pm, Matthias Ernst <ernst.matth...@gmail.com> wrote:
> Create a static ObjectTemplate for "Points" and set accessors and
> functions on it.
> From the function, you return an pointTemplate->NewInstance().
>
> Here's an example I have handy for "Prices", the object being backed
> by a C++ "Price" object:
>
> +Handle<ObjectTemplate> PriceTemplate() {
> +  Handle<ObjectTemplate> result = ObjectTemplate::New();
> +  result->SetAccessor(String::New("amount"), GetPriceAmount);
> +  result->SetAccessor(String::New("currency"), GetPriceCurrency);
> +
> +  result->SetInternalFieldCount(1);
> +  return Persistent<ObjectTemplate>::New(result);
> +}
> +
> +Handle<Object> WrapPrice(const Price *p) {
> +  static Handle<ObjectTemplate> price_template = PriceTemplate();
> +
> +  Handle<Object> result = price_template->NewInstance();
> +  result->SetInternalField(0, External::New(const_cast<Price *>(p)));
> +  return result;
> +}
>

Matthias Ernst

unread,
Jan 24, 2009, 2:55:07 AM1/24/09
to v8-u...@googlegroups.com

On Fri, Jan 23, 2009 at 7:25 PM, vlad <mega...@gmail.com> wrote:
>
> Thank you very much for the info, Matthias. Although, I have to admit
> I haven't been able to get it working properly, yet.
>
> Is there a way to pass arguments  when creating new instances using
> this method?

This is your guide: http://v8.googlecode.com/svn/trunk/include/v8.h

*/
class EXPORT Function : public Object {
public:
 Local<Object> NewInstance() const;
 Local<Object> NewInstance(int argc, Handle<Value> argv[]) const;
 Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
 void SetName(Handle<String> name);
 Handle<Value> GetName() const;
 static Function* Cast(Value* obj);
private:
 Function();
};
Reply all
Reply to author
Forward
0 new messages