Meta programming

Agenda

  1. What is meta programming?
  2. How does it work?
  3. Can i use?
  4. Conclusion.
  5. Quiz.

 Sources

What is meta programming?

Programming

  • Base level
  • Meta level

Base level

At the base level (also called: application level), code processes user input.

Meta level

At the meta level, code processes base level code.

Examples

eval

ECMA

This function is the %eval% intrinsic object.

It performs the following steps when called:

Return ? PerformEval(x, false, false).

MDN

The eval() function evaluates JavaScript code represented as a string and returns its completion value. The source is parsed as a script.

Proxy

Object

Methods

Function

Member of the Object type that may be invoked as a subroutine.

A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, BigInt, String, and Symbol; an object is a member of the built-in type Object; and a function is a callable object. A function that is associated with an object via a property is called a method.

Symbol

Kinds of meta programming

  • Introspection
    • we have read-only access to the structure of a program.
  • Self-modification
    • we can change that structure.
  • Intercession
    • we can redefine the semantics of some language operations.

Introspection

Self-modification

Intercession

How does it work?

Proxy

Proxies are special objects that allow us to customize some of these operations. A Proxy is created with two parameters: Target and Handler.

Target

If the handler doesn’t intercept an operation, then it is performed on the target. That is, it acts as a fallback for the handler. In a way, the Proxy wraps the target.

Handler

For each operation, there is a corresponding handler method that – if present – performs that operation. Such a method intercepts the operation (on its way to the target) and is called a trap – a term borrowed from the domain of operating systems.

Function-specific traps

  • apply: Making a function call. Triggered via:
    • proxy(···)
    • proxy.call(···)
    • proxy.apply(···)
  • construct: Making a constructor call. Triggered via:
    • new proxy(···)

Intercepting method calls

If we want to intercept method calls via a Proxy, we are facing a challenge: There is no trap for method calls. Instead, a method call is viewed as a sequence of two operations:

 - A get to retrieve a function

 - An apply to call that function

 

Therefore, if we want to intercept method calls, we need to intercept two operations:

 - First, we intercept the get and return a function.

 - Second, we intercept the invocation of that function.

Revocable Proxies

Proxies as prototypes

Forwarding intercepted operations

GET

Pitfalls

Target associates information with this via a mechanism that is not controlled by Proxies, we have a problem: things fail, because different information is associated depending on whether the target is wrapped or not.

Instances of most built-in constructors also use a mechanism that is not intercepted by Proxies. They therefore can’t be wrapped transparently, either. We can see that if we use an instance of Date

The mechanism that is unaffected by Proxies is called internal slots. These slots are property-like storage associated with instances. The specification handles these slots as if they were properties with names in square brackets. For example, the following method is internal and can be invoked on all objects O: O.[[GetPrototypeOf]]()

 

In contrast to properties, accessing internal slots is not done via normal “get” and “set” operations. If .getFullYear() is invoked via a Proxy, it can’t find the internal slot it needs on this and complains via a TypeError.

 

For Date methods, the language specification states:

Unless explicitly defined otherwise, the methods of the Date prototype object defined below are not generic and the this value passed to them must be an object that has a [[DateValue]] internal slot that has been initialized to a time value.

A work-around

Arrays can be wrapped transparently

Why?

The reason for Arrays being wrappable is that, even though property access is customized to make .length work, Array methods don’t rely on internal slots – they are generic.

Proxy limitations

Symbol

Symbol.iterator

Symbol.isConcatSpreadable

Symbol.toStringTag

Symbol.hasInstance

Symbol.species

Symbol.toPrimitive

The others

  • Symbol.match (RegExp)
  • Symbol.unscopables (with)
  • Symbol.keyFor & Symbol.for (Checking for Symbols)

Can i use?

There are more use cases for Proxies

  • Remoting: Local placeholder objects forward method invocations to remote objects. This use case is similar to the web service example.

  • Data access objects for databases: Reading and writing to the object reads and writes to the database. This use case is similar to the web service example.

  • Profiling: Intercept method invocations to track how much time is spent in each method. This use case is similar to the tracing example.

VDOM

  • Immer (by Michel Weststrate) helps with non-destructively updating data. The changes that should be applied are specified by invoking methods, setting properties, setting Array elements, etc. of a (potentially nested) draft state. Draft states are implemented via Proxies.

  • MobX lets you observe changes to data structures such as objects, Arrays and class instances. That is implemented via Proxies.

  • Alpine.js (by Caleb Porzio) is a frontend library that implements data binding via Proxies.

  • on-change (by Sindre Sorhus) observes changes to an object (via Proxies) and reports them.

  • Env utility (by Nicholas C. Zakas) lets you access environment variables via properties and throws exceptions if they don’t exist. That is implemented via Proxies.

  • LDflex (by Ruben Verborgh and Ruben Taelman) provides a query language for Linked Data (think Semantic Web). The fluid query API is implemented via Proxies.

Vue

  • Data bind
  • Computed
  • Refs(Reactive)
  • Watch(WatchEffect)
  • Lifecycle hooks
  • etc.

Conclusion

Quiz

How to check if a function was executed with new?

Meta Programming

By Cyril Mialik

Meta Programming

  • 22