Built-in Macro object

The decorator proposal brings new meta programming capabilities to JavaScript, but it also has some limitations, as mentioned by @aclaymore.
I'm not proposing a fix / alternative solutions to decorators rather a way to extend their capabilities. I'm suggesting a static constructor called Macro which holds utility functions that could serve as native decorators. These native decorators / macros can provide extra meta programming features that can / can't be achieved by the userland decorators.
This could also help avoid adding new operators / keywords every now and then and provide consistent solutions using existing syntax.
Now the question is;

What should be the methods exposed by this Object?

for starters, it let's consider various ideas that we've discussed in this discourse.

(Note: these are just suggestions & pseudo code)

Readonly Modifier

class Foo {
@Macro.readonly bar = "baz"

Type Fixing

let @Macro.fix foo = "bar"

Expression Error Handling

let [ exe, err ] = @Macro.try bar()

Abstract Classes

class Foo {
	foo = "bar"
	constructor() { ... }
	bar() { ... }

new Foo() // error


class Foo extends @Macro.mixin(m1, m2) Bar { ... }


@Macro.assert x === y

Parameter Properties

class {
	// prop - property, hprop - hidden property
	constructor(@Macro.prop foo, @Macro.hprop bar) { ... }

And many more...
The major criticism against this would be: It makes code look a little ugly with @Macro.whatever syntax😯.
I think destructuring might help a bit :)

const { readonly, fix, try: try_, abstract } = Macro

Have any additions, concerns or other things?? :blush:Feel free to let me know!

1 Like

How do you propose the macros are defined?

That's the catch they can't be defined by the user; They are implemented in native code by the browser. They are native decorators without the limitations of standard userland decorators.

Those limitations are requirements by implementations, for performance reasons. It’s not about native vs userland.

1 Like

yes and that's why I proposed the Macro object. It's implementation is native and need not be similar to that of decorators. However it exposes its capabilities through the familiar syntax of decorators. You can think of it as a wolf in a sheep's skin. They are fundamentally different yet similar at the surface level. Macro as opposed to a Decorator.

The capability itself is what implementors object to, not "userland implements the capability".

So ... it sort of sounds to me like this "macro" is nothing more than providing the requested features, but with a "@" tagged at the front of them? For example, what's the value in doing @Macro.assert x === y over just providing a new assert operator? Or Macro.try bar() over just providing the requested try-as-expression operator? It sounds like implementation would be just as difficult either way.

let me get this straight:
Macro - has the capability to transform the provided expression / statement
Decorator - wraps additional functionality over something

Arguably Macros are more powerful than Decorators but often complicated and difficult to implement. They can transform the AST of the provided source. It's not worth the performance loss and added complexity to consider them over decorators. The performance loss is due to the dynamic nature of JS; but in a compiled language like Rust & Julia, they can actually help in optimisations and improve performance. The methods of the Macro object is native so performance loss might not be a problem.

Even if you're skeptical of the it's capabilities over normal decorators, it can be used as a harbour for utility decorators that cover common use cases.

adding a new syntax feature is often more difficult than providing something using existing solutions.

const frozen = Object.freeze([1, 2, 3])
// the Object.freeze() was relatively straightforward to implement as opposed to
const frozen = [1, 2, 3] as const

I'm currently into Haxe, here's how parameter properties are defined using macros; just to illustrate the profound difference and the huge potential they can offer through native APIs.