GithubHelp home page GithubHelp logo

Comments (2)

uhop avatar uhop commented on August 16, 2024

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 AKA let AKA const AKA anything. Run-time variables can be inspected with typeof, 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).

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: totally ordered type based on basic_value. Different types of ordering are possible.
  • Reflecting and selectively combining metaclasses.
    • plain_struct: emulates built-in struct of C++ with meta-programming. Uses as() dynamically to define ordering type of a structure depending on ordering types of data members.
    • copyable_pointer: defines smart pointers, and matches with is() existing smart pointers.
  • Generating additional data members:
    • enum_class: emulates built-in enum of C++ with meta-programming.
    • flag_enum: emulates enum used as bitfield flags.
    • bitfield: allows to treat sequences of contiguous bits as primitive types, like integers.
    • safe_union: emulates union of C++ with meta-programming.
    • namespace_class: emulates namespace 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() and as() 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.

littledan avatar littledan commented on August 16, 2024

Thanks for the reference--this paper was definitely interesting.

from proposal-decorators.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.