Closing in on finishing chapter 3

This commit is contained in:
Rolf Martin Glomsrud 2024-04-25 16:45:23 +02:00
parent f8ceb8de30
commit ce31069119
2 changed files with 154 additions and 9 deletions

Binary file not shown.

View file

@ -54,7 +54,7 @@ See that in \ref{ex:proposal} the change is optional, and is not applied to the
\subsection{Discard Bindings}
The proposal \discardBindings is classified as a Syntactic Proposal, as it contains no change to the semantics of EcmaScript. This proposal is created to allow for discarding objects when using the feature of unpacking objects/arrays on the left side of an assignment.
The proposal \discardBindings is classified as a Syntactic Proposal, as it contains no change to the semantics of EcmaScript. This proposal is created to allow for discarding objects when using the feature of unpacking objects/arrays on the left side of an assignment. The whole idea of this proposal is to avoid declaring unused temporary variables.
Unpacking when doing an assignment refers to assigning internal fields of an object/array directly in the assignment rather than using a temporary variable. See \ref{ex:unpackingObject} for an example of unpacking an object and \ref{ex:unpackingArr}.
@ -79,7 +79,107 @@ let b = tempArr[1] // 2
let [a, b, _1, _2] = [ 0, 2, 3, 4 ]; // a = 0, b = 2, _1 = 3, _2 = 4
\end{lstlisting}
The core idea of the proposal is sometimes when using unpacking of objects/arrays one does need all parts of the
In EcmaScripts current form, it is required to assign every part of an unpacked object/array to some identifier. The current status quo is to use \_ as a sign it is meant to be discarded. This proposal suggests a specific keyword \textit{void} to be used as a signifier whatever is at that location should be discarded.
This feature is present in other languages, such as Rust wildcards, Python wildcards and C\# using statement and discards. In most of these other languages, the concept of discard is a single \_. In EcmaScript the \_ token is a valid identifier, therefore this proposal suggests the use of the keyword \textit{void}. This keyword is already is reserved as part of function definitions where a function is meant to have no return value.
This proposal allows for the \textit{void} keyword to be used in a variety of contexts. Some simpler than others but all following the same pattern of allowing discarding of bindings to an identifier. It is allowed anywhere the \textit{BindingPattern}, \textit{LexicalBinding} or \textit{DestructuringAssignmentTarget} features are used in EcmaScript. This means it can be applied to unpacking of objects/arrays, in callback parameters and class methods.
\begin{lstlisting}[language={JavaScript}, caption={Example discard binding with variable discard}]
using void = new UniqueLock(mutex);
// Not allowed on top level of var/let/const declarations
const void = bar(); // Illegal
\end{lstlisting}
\begin{lstlisting}[language={JavaScript}, caption={Example Object binding and assignment pattern}]
let {b:void, ...rest} = {a:1, b:2, c:3, d:4}
rest; // {a:1, c:3, d:4};
\end{lstlisting}
\begin{lstlisting}[language={JavaScript}, caption={
Example Array binding and assignment pattern. It is not clear to the reader that in line 8 we are consuming 2 or 3 elements of the iterator. In the example on line 13 we see that is it more explicit how many elements of the iterator is consumed
}]
function* gen() {
for (let i = 0; i < Number.MAX_SAFE_INTEGER; i++) {
console.log(i);
yield i;
}
}
const iter = gen();
const [a, , ] = iter;
// prints:
// 0
// 1
const [a, void] = iter; // author intends to consume two elements
// vs.
const [a, void, void] = iter; // author intends to consume three elements
\end{lstlisting}
\begin{lstlisting}[language={JavaScript}, caption={Example discard binding with function parameters. This avoids needlessly naming parameters of a callback function that will remain unused.}]
// project an array values into an array of indices
const indices = array.map((void, i) => i);
// passing a callback to `Map.prototype.forEach` that only cares about
// keys
map.forEach((void, key) => { });
// watching a specific known file for events
fs.watchFile(fileName, (void, kind) => { });
// ignoring unused parameters in an overridden method
class Logger {
log(timestamp, message) {
console.log(`${timestamp}: ${message}`);
}
}
class CustomLogger extends Logger {
log(void, message) {
// this logger doesn't use the timestamp...
}
}
// Can also be utilized for more trivial examples where _ becomes
// cumbersome due to multiple discarded parameters.
doWork((_, a, _1, _2, b) => {});
// vs.
doWork((void, a, void, void, b) => {
});
\end{lstlisting}
The grammar of this proposal is precicely specified in the specification found in the \href{https://github.com/tc39/proposal-discard-binding?tab=readme-ov-file#object-binding-and-assignment-patterns}{proposal definition} on github.
\begin{lstlisting}[language={JavaScript}, caption={Grammar of Discard Binding}]
var [void] = x; // via: BindingPattern :: `void`
var {x:void}; // via: BindingPattern :: `void`
let [void] = x; // via: BindingPattern :: `void`
let {x:void}; // via: BindingPattern :: `void`
const [void] = x; // via: BindingPattern :: `void`
const {x:void} = x; // via: BindingPattern :: `void`
function f(void) {} // via: BindingPattern :: `void`
function f([void]) {} // via: BindingPattern :: `void`
function f({x:void}) {} // via: BindingPattern :: `void`
((void) => {}); // via: BindingPattern :: `void`
(([void]) => {}); // via: BindingPattern :: `void`
(({x:void}) => {}); // via: BindingPattern :: `void`
using void = x; // via: LexicalBinding : `void` Initializer
await using void = x; // via: LexicalBinding : `void` Initializer
[void] = x; // via: DestructuringAssignmentTarget : `void`
({x:void} = x); // via: DestructuringAssignmentTarget : `void`
\end{lstlisting}
\subsection{Pipeline Proposal}
@ -195,7 +295,7 @@ In order to identify snippets of code in the users codebase where a proposal is
In order to allow for the utilization of the users code. We have to identify snippets of the users code that some proposal is applicable to. In order to do this, we have designed a DSL called \DSL JavaScript Template Query Language. This DSL will contain the entire definition used to identify and transform user code in order to showcase a proposal.
\subsection{Identifying}
\subsection{Matching}
In order to identify snippets of code a proposal is applicable to, we use templates of JavaScript. These templates allow for \textit{wildcard} sections where it can match against specific AST nodes. These \textit{wildcard} sections are also used to transfer the context of the code matched into the transformation.
@ -209,6 +309,17 @@ let variableName = << expr1: CallExpression | Identifier >>;
In \ref{ex:wildcard} a wildcard section is defined on the right hand side of an assignment statement. This wildcard will match against any AST node classified as a CallExpression or an Identifier. The DSL reuses the AST node-types from Babel.
\subsection{Transforming}
Observe that once the a matching template has been defined, a definition of transformation has to be created. This transformation has to transfer over the code matched to a wildcard. This means a way to refer to the wildcard is needed. We do this in a very similar manner as defining the wildcard, since we have an internal DSL identifier, all that is needed is to refer to that identifier. This is done with a similar block definition (<<>>) containing the identifier.
\begin{lstlisting}[caption={
See \ref{ex:wildcard} contains identifier expr1, and we refer to the same in this example, the only transformation happening here is rewriting let to const.
}]
const variableName = <<expr1>>;
\end{lstlisting}
\subsection{Structure of \DSL}
\DSL is designed to mimic the examples already provided by a proposal champion in the proposals README. These examples can be seen in each of the proposals described in \ref{sec:proposals}.
@ -228,7 +339,7 @@ proposal Pipeline_Proposal{
Each proposal will have 1 or more definitions of a template for code to identify in the users codebase, and its corresponding transformation definition. These are grouped together in order to have a simple way of identifying the corresponding pairs. This section of the proposal is defined by the keyword \textit{pair} and a block to contain its related fields. A proposal will contain 1 or more of this section. This allows for matching many different code snippets and showcasing more of the proposal than a single concept the proposal has to offer.
\begin{lstlisting}[caption={Example of pair section}]
pair {
pair PAIR_NAME {
}
\end{lstlisting}
@ -259,7 +370,7 @@ Taking all these parts of \DSL structure, defining a proposal in \DSL will look
\begin{lstlisting}[caption={\DSL definition of a proposal}]
proposal PROPOSAL_NAME {
pair {
pair PAIR_NAME {
applicable to {
}
@ -267,7 +378,7 @@ proposal PROPOSAL_NAME {
}
}
pair {
pair PAIR_NAME {
applicable to .....
}
@ -275,12 +386,46 @@ proposal PROPOSAL_NAME {
}
\end{lstlisting}
\
\section{\DSL}
In order to match ......
\section{Using the \DSL with an actual syntactic proposal}
\subsection{Pipeline Proposal}
The Pipeline Proposal is the easiest to define of the proposals presented in \ref*{sec:proposals}. This is due to the proposal being applicable to a very wide array of expressions, and the main problem this proposal is trying to solve is deep nesting of function calls.
\begin{lstlisting}[language={JavaScript}, caption={Example of Pipeline Proposal definition in \DSL}]
proposal Pipeline{
pair 1 {
applicable to {
<<someFunctionIdent>>(<<someFunctionParam: Expression | Identifier>>);
}
transform to {
<<someFunctionParam>> |> <<someFunctionIdent>>(%);
}
}
pair 2 {
applicable to {
<<someFunctionIdent>>(
<<firstFunctionParam : Expression | Identifier>>,
<<restOfFunctionParams: anyRest>>
);
}
transform to {
<<firstFunctionParam>> |> <<someFunctionIdent>>(%, <<restOfFunctionParams>>);
}
}
}
\end{lstlisting}
This first pair definition of the Pipeline proposal will apply to any \textit{CallExpression} with a single parameter. And it will be applied to each of the deeply nested callExpressions.