Comments (2)
Thank you, @domenic. I did enjoy studying it. Here is my notes/lessons from it:
The C++ metaclasses proposal is an imperative way to define class decorators (just like this proposal). There is no other kinds of decorators — everything is done at a class level.
While it is based on two other proposals (concepts, and reflections), they appear to be superficial in JavaScript:
- Concepts deal syntactic possibility of certain code, essentially "would this code compile given certain types of variables? true or false?", which is always true for JavaScript. "Would it run?" is a different question, which requires actual instantiation of variables, and running the code in question.
- Reflection mostly used with declarations (not definitions, like in JavaScript), and can provide an information along these lines:
- Type of a declared variable. JavaScript has one "declaration" type:
var
AKAlet
AKAconst
AKA anything. Run-time variables can be inspected withtypeof
,instanceof
, and a host of property descriptor-related methods defined by ES5. - Signature of a method. JavaScript has two pieces of information: name, and number of declared parameters. The latter is mostly superficial, because a function can access any arguments without declaring them. On top of that we have rest parameters.
- Lists of different kinds of class elements. This is directly a subject of this proposal. Presently it is one big array of elements, which I found unwieldy (see #12).
- Type of a declared variable. JavaScript has one "declaration" type:
Cool feature. The C++ metaclass proposal proposes a simple compiler-integrated diagnostics, which we may want to have too. In fact any language with meta-programming should have it: two procedures, which help to report a problem to programmers. They look like that:
compiler.error("message", source_location);
compiler.require(cond, "message", source_location);
// defined is:
if constexpr(!cond) compiler.error("message", source_location);
source_location
is an optional object we are annotating. If it is present, the location of its definition is provided in an output:
class X { /* ... */ }
// ...
compiler.required(typeof X.prototype.render == 'function',
"method render() is required!", X);
It should print something like that:
Line 1: class X: method render() is required!
Obviously compiler.error()
should work together a compiler to provide location information. OTOH, we already collecting source text of user-defined functions. Why not remember the last definition position.
Let's continue with class decorators.
Another cool features are to use metaclasses (class decorators) as duck-typing tests and adapters for existing classes. It is done with is()
and as()
.
is()
takes two parameters: a class, and a meta-class (a class decorator), and applies the latter to the former. It returns true
if a decorator can be applied to the class without errors, and the resulting type has no new members in it.
Illustration in pseudo-JS borrowing the first example and syntax of #12:
// class decorator
const ensureRender = (proto, stat, own) => {
if (!proto.render && !own.render) {
proto.render = {value: (() => {}), configurable: true, writable: true};
}
};
// class
class Widget { /* ... */ };
if (widget instanceof Widget && is(Widget, ensureRender)) {
widget.render();
}
as()
is less interesting in the context of JS: it is more of a helper to apply a class decorator to a class dynamically producing another class:
const RenderingGadget = as(Widget, ensureRender);
In order to do its magic, meta-classes can emit arbitrary code using -> { some code }
construct. It emits some code
at the current point. Example (adds missing comparison operators):
$class C {
constexpr {
if (!requires(C a) { a != a })
-> { friend bool operator != (const C& a, const C& b) { return a != b; } }
if (!requires(C a) { a > a })
-> { friend bool operator > (const C& a, const C& b) { return b < a; } }
if (!requires(C a) { a <= a })
-> { friend bool operator <= (const C& a, const C& b) { return !(b < a); } }
if (!requires(C a) { a >= a })
-> { friend bool operator >= (const C& a, const C& b) { return !(a < b); } }
}
};
As you can see the example injects friend operator definitions right in class using -> {}
, if missing.
It can be used while defining methods. In this case, the method definition includes constexpr
, which may emit code. Effectively it is a template, which is verified by a compiler. JS can do it with generating code using a template, then eval()
it. Obviously, the ergonomics of the whole process can be improved, yet the facilities are here.
The paper provides a lot of interesting examples:
- Simple inspection: issues errors on violations, flips some properties, like public/private.
*interface
: all methods are public and virtual, no data members.base_class
: no instance data, not copyable, special destructor (either public virtual, or protected non-virtual).final
: cannot be derived.
- Generating default methods.
ordered
: adds==
,!=
,<
,<=
,>
,>=
, when missing specifying in terms of other operators.basic_value
: value semantics including public default construction, copy/move construction/assignment, no protected nor virtual methods.
- Combining metaclasses (applying several class decorators in a cascade), where one depends on another.
value
: totallyordered
type based onbasic_value
. Different types of ordering are possible.
- Reflecting and selectively combining metaclasses.
plain_struct
: emulates built-instruct
of C++ with meta-programming. Usesas()
dynamically to define ordering type of a structure depending on ordering types of data members.copyable_pointer
: defines smart pointers, and matches withis()
existing smart pointers.
- Generating additional data members:
enum_class
: emulates built-inenum
of C++ with meta-programming.flag_enum
: emulatesenum
used as bitfield flags.bitfield
: allows to treat sequences of contiguous bits as primitive types, like integers.safe_union
: emulatesunion
of C++ with meta-programming.namespace_class
: emulatesnamespace
of C++ with meta-programming.
- Eliminating specialized pre/post processors.
- Apparently Qt moc, C++/CX, C++/WinRT IDL processors can be replaced with the proposed meta-programming.
Some proposal's details:
- A meta-class name (a class decorator) should be used instead of
class
keyword to apply:// regular class class X { /* ... */ } // define `interface` $class interface { /* ... */ } // use `interface` interface Y { /* ... */ }
- Several meta-classes can be combined (with defining their dependencies) using the familiar C++ syntax (remember that C++ uses multiple inheritance):
$class value : ordered, basic_value { };
I feel that using a class decorator syntax is more versatile in JS than a special meta-class syntax proposed for C++. Combining decorators is something that should be addressed in JS.
Another fine point: C++ meta-classes rely strictly on existing meta-data of members. There is no way to mark a member, and associate it with an arbitrary data, which can be used later by a class decorator. In all honesty it can be done, but using static members associated by a convention. Example: member name
is described by static member metaName
or using some other equally peculiar trick. I think it is the biggest weakness of the C++ meta-class proposal.
To sum up the most interesting things:
compiler.error()
. It will help programmers immensely.is()
andas()
are very cool helpers based on class decorators. I want them.- Class decorators can be combined. Two fine points about it:
- They may depend on each other, and used strictly in order.
- Duplicates should be eliminated. (C3MRO?)
- Class decorators worked all their magic through perusing lists of meta objects describing members. Changes to existing members were done in place.
- See #12 for that.
from proposal-decorators.
Thanks for the reference--this paper was definitely interesting.
from proposal-decorators.
Related Issues (20)
- Timeline / proposal for extensions? HOT 8
- Using accessors makes code less clean and readable HOT 21
- Counterintuative ordering when using `accessor` in combination with `init` methods HOT 37
- Can't dynamically set private field in initializer HOT 17
- Context.private doesn't seem to support group accessor HOT 1
- Support changing the backing field used by auto-accessors HOT 2
- Towards stage 4 HOT 14
- Field and Accessor initializers should run after the field/accessor has been defined HOT 12
- Stage 3 cannot access the class for static method decorator HOT 3
- Idea: syntax for decorator composition. HOT 3
- How to exclude methods from class decorator HOT 2
- Add target class to the context HOT 6
- Order of execution HOT 3
- It isn't clear when `addInitializer` functions are called on class decorator HOT 2
- feature request (separate proposal?): `context.addPostInitializer()` HOT 18
- Readme text and types are outdated against actual spec HOT 2
- Field decorator initializer should support configurable field HOT 8
- Was there a purpose for non-lexical ordering of decorator applications? HOT 2
- Write upgrade guide for previous iterations to Stage 3
- Clarification on field vs. method destination HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from proposal-decorators.