Add a new class registration API using static inheritance
Motivation
We now have !679 (merged) which allows static inheritance and with !700 (merged) we will enable support for class fields in GObject derived classes.
- Static inheritance allows us to build APIs on the class object instead of in the namespace
GObject
- Class fields were designed to operate on the instance level, the existing
registerClass
API assumes access to the instance. The eventual design of class fields (to define them after super) prevents this, unfortunately.
GObject.registerClass
Differences with GObject.registerClass
was designed as a decorator or wrapped function which would transform a passed class, .register()
is designed to have no side-effects on the instance and generally follow a "what you see is what you get" pattern. The API is designed to be more natural to use with current JavaScript features such as class fields. For example, defining a class field won't overwrite a GObject property or child widget.
There are two primary differences:
- Accessors are not automatically generated. Instead of auto-generating accessors with camel and underscore variants,
register()
class only binds to existing getters/setters.this.bindPropertyFields
(#451) supports "binding" GObject properties to class fields. - Gtk.Widget children are not defined automatically. They are still initialized on the template. Instead,
register()
supports loading children viathis.get_template_child
.Gtk.defineChildren
(#452) andthis.get_template_children
(#450) are two proposed overrides to improve this experience.
Proposed API Additions
namespace Gtk {
export class Widget {
static register({ CssName, Properties, Signals, ... }): void;
}
}
namespace GObject {
export class Object {
static register({ Properties, Signals, ... }): void;
}
}
Example
class MyObject extends GObject.Object {
}
MyObject.register();
class Foo extends GObject.Object {
#bar;
constructor() {
super();
}
get bar() { return this.#bar; }
}
Foo.register({
Properties: {
bar: GObject.ParamSpec.boolean(...)
}
});
With #451
class Foo extends GObject.Object {
bar;
constructor() {
super();
this.bindPropertyFields();
}
}
Foo.register({
Properties: {
bar: GObject.ParamSpec.boolean(...)
}
});
With "accessors" (https://github.com/tc39/proposal-decorators#class-auto-accessors, https://github.com/tc39/proposal-grouped-and-auto-accessors)
class Foo extends GObject.Object {
accessor bar;
constructor() {
super();
}
}
Foo.register({
Properties: {
bar: GObject.ParamSpec.boolean(...)
}
});