Open kphillisjr opened 9 years ago
After a little bit of thought, I figured I could outline some example C code for use by applications implementing this feature. Keep in mind this is mostly end user API and does not define any actual source changes to implement this though.
// new Generalized functions.
void duk_get_constructor(duk_context *ctx, duk_idx_t index);
void duk_set_constructor(duk_context *ctx, duk_idx_t index);
These functions work the same as duk_get_finalizer and duk_set_finalizer but are intended to make it easier for a program to access a constructor.
duk_idx_t duk_push_c_class(duk_context *ctx, const char* base);
This Function works a lot like your duk_push_object, and the base parameter can be set to NULL (0) when this class does not inherit from anything.
/* These Functions usually will go in a Header */
duk_ret_t duk_class_shape_constructor(duk_context *ctx);
duk_ret_t duk_class_shape_finalizer(duk_context *ctx);
duk_ret_t duk_class_shape_staticFunc(duk_context *ctx);
duk_idx_t duk_register_shape_class(duk_context *ctx)
{
/* Creat Shape Base Class */
duk_idx_t shape_idx;
duk_push_global_object(ctx); // Push Global Space.
shape_idx = duk_push_c_class(ctx, 0);
duk_push_c_function(ctx, duk_class_shape_constructor, 3 /*nargs*/);
duk_set_constructor(ctx, shape_idx);
duk_push_c_function(ctx, duk_class_shape_finalizer, 1 /*nargs*/);
duk_set_finalizer(ctx, shape_idx);
/* Define a Static Member */
duk_push_c_function(ctx, duk_class_shape_default,0);
duk_put_prop_string(ctx, shape_idx, "createDefaultShape");
duk_put_prop_string(ctx, -1, "Shape"); // Class is now defined as Shape.
return shape_idx;
}
duk_ret_t duk_class_shape_constructor(duk_context *ctx)
{
int id = duk_require_int(ctx,0);
int x = duk_require_int(ctx,1);
int y = duk_require_int(ctx,2);
/* This Constructor assumes that the object is already Created */
/* Current Method requires a call to duk_push_object */
duk_push_this(ctx);
duk_push_int(ctx, id);
duk_put_prop_string(ctx, obj_idx, "id");
duk_push_int(ctx,x)
duk_put_prop_string(ctx, obj_idx, "x");
duk_push_int(ctx,y)
duk_put_prop_string(ctx, obj_idx, "y");
duk_pop(ctx);
return 0;
}
duk_ret_t duk_class_shape_finalizer(duk_context *ctx)
{
/* Take care of New object Clean up Here */
return 0;
}
duk_ret_t duk_class_shape_staticFunc(duk_context *ctx)
{
/* Do something that is normally done in static functions */
return 0;
}
duk_bool_t duk_has_parent(duk_context *ctx); // super is set.
void duk_push_parent(duk_context *ctx); // Pushes Parent to top of stack.
duk_has_parent - returns false if parent is set to a value other than Null. duk_push_parent - This works a lot like duk_push_object, but instead sets the parent object to the top of the stack.
duk_ret_t duk_class_rectangle_constructor(duk_context *ctx);
duk_ret_t duk_class_rectangle_finalizer(duk_context *ctx);
duk_ret_t duk_class_rectangle_default(duk_context *ctx);
duk_idx_t duk_register_rectangle_class(duk_context *ctx)
{
/* Create Rectangle Class */
duk_idx_t rectangle_idx;
duk_push_global_object(ctx); // Push Global Space.
rectangle_idx = duk_push_c_class(ctx, "Shape");
duk_push_c_function(ctx, duk_class_rectangle_constructor, 5 /*nargs*/);
duk_set_constructor(ctx, rectangle_idx);
duk_push_c_function(ctx, duk_class_rectangle_finalizer, 1 /*nargs*/);
duk_set_finalizer(ctx, rectangle_idx);
/* Define a Static Member */
duk_push_c_function(ctx, duk_class_rectangle_default,0);
duk_put_prop_string(ctx, rectangle_idx, "createDefaultRectangle");
duk_put_prop_string(ctx, -1, "Rectangle"); // Class is now defined as Rectangle.
return rectangle_idx;
}
duk_ret_t duk_class_rectangle_constructor(duk_context *ctx)
{
int id = duk_require_int(ctx,0);
int x = duk_require_int(ctx,1);
int y = duk_require_int(ctx,2);
int w = duk_require_int(ctx,3);
int h = duk_require_int(ctx,4);
duk_push_this(ctx);
if(duk_has_parent(ctx)) {
/* Call parent Constructor */
duk_push_parent(ctx);
duk_get_constructor(ctx, -1);
duk_push_int(ctx, id);
duk_push_int(ctx,x)
duk_push_int(ctx,y)
duk_call(ctx);
duk_pop(ctx); // Done with Parent.
}
duk_push_int(w);
duk_put_prop_string(ctx, -2, "width");
duk_push_int(h);
duk_put_prop_string(ctx, -2, "height");
/* Take care of New object Here */
return 0;
}
duk_ret_t duk_class_rectangle_finalizer(duk_context *ctx)
{
/* Take care of Current Object clean up */
return 0;
}
duk_ret_t duk_class_rectangle_default(duk_context *ctx)
{
/* Do something that is normally done in static functions */
return 0;
}
Is this expected to land any time soon? This feature would make my life a whole lot easier.
I completely forgot I made this bug report. Anyways, I recently noticed another stack based scripting language that makes use of classes that has some basic functionally similar what ECMAScript 6 classes require. This language is called Squirrel. I probably should mention that the licensing on this is compatible with Duktape's License because it also uses the MIT License.
@svaarala any chance we'll see this in duktape any time soon?
@s1341 There's no set plan for adding ES6 features yet. ES6 will require some groundwork in the lexer and compiler before it'll be possible to implement ES6 features comfortably.
@svaarala, Node.js and SpiderMonkey already have this feature.
The normal syntax for class declarations - this is something that is very lacking in the JavaScript.
Why not use an ES6 transpiler such as Babel JS?
@brodybits, This is inconvenient workaround
@brodybits You might be just asking about using babel to solve only this specific issue/request, but I am going to assume you really mean it in general, for a lot of the opened ES6 feature request issues. In general, even though transpilers can solve a lot of these ES6 requests, there are several things to take into consideration:
One is that transpiled solutions for certain features can be slightly slower to execute at runtime than if the engine supported them natively. This issue is a bad example of that, of course, but features like default arguments, destructuring, rest params, and things like Array#from
make better cases. The strongest cases I can think of at the moment are Set
s and Map
s, for which the native implementation would be much faster than anything spit out by a transpiler.
Another consideration is that a lot of things can't be transpiled or even polyfilled properly, and thus native solutions must exist for support to be present.
Lastly, some users of duktape are unable to use transpilers (as pointed out by @ricardobeat in #273), so implementing
@rosshadden Fully agree that transpiling is not ideal, and there's no disagreement whether full ES2015 support should be provided (it is intended to be eventually fully supported). However, the changes needed are not trivial and take time to implement, especially those requiring compiler rework (like destructuring).
Haha yeah, of course! I was just trying to answer what I envisioned as the generalized version of his question, shedding some light in places that not everyone might know about. For instance, I did not even consider use cases where people were unable to use a transpiler until I read #273.
Covering transpiling in practice (including its limitations) would make a good Wiki Howto BTW.
Anyway, just wanted to make clear supporting ES2015 is a project goal. It's not a given because some ES2015 features conflict a bit with keeping a low footprint and memory usage. In practice the approach will be such that the low memory baseline is an ES5-like configuration where you can enable individual ES2015 features that you specifically need. However, even with that approach some things like compiler architecture potentially conflict with footprint goals.
So there are definitely challenges ahead (which is good :-). In the meanwhile ES2015 features have been implemented little by little where they don't require significant structural rework. For example, 2.0.0 adds support for Reflect, Symbols, more Math built-ins, new object literal property formats, hex/octal literals, etc.
Added this for the Wiki: https://github.com/svaarala/duktape-wiki/issues/157.
@svaarala I wonder how difficult it would be to implement classes with the current parser. My initial thought is that it shouldn't be too different from parsing an object literal (and hence require minimal hacking, which I know is something you want to avoid), but there are probably complications that I'm not accounting for.
Whats the status of this, I guess this is still a missing feature?
Wil this ever be implemented?
Provided that I (or others) have time to spend on the implementation, it's definitely a goal. Please note that this project is (originally) a personal off-hours project. It has no commercial backing, and no dedicated development resources, so progress depends entirely on the free time available.
True but this issue has almost been there for 5 years hahaha
Bump, any updates on this?
This is one of the more advanced ES6 Features. I also believe this is probably an area where Duktape can definitely make some vast improvements. The examples for this are from the es6 Features website and more information can be found on the 2ality blog.
[ ] Classes ( class keyword )
[ ] Class Function definition without function keyword
[ ] Class Inheritance ( extends and super keywords)
[ ] Base Class Access(super and extends keywords:
[ ] TypeOf Operator Interaction.
[ ] instanceof Operator Interaction.
[ ] Static Members:
[ ] Variable Getters and Setters