Reading List
The most recent articles from a list of feeds I subscribe to.
Mass function overloading: why and how?
One of the things I’ve been doing for the past few months (on and off—more off than on TBH) is rewriting Bliss to use ESM 1. Since Bliss v1 was not using a modular architecture at all, this introduced some interesting challenges. Bliss is essentially a collection of helper functions. Most of these functions have a number of different signatures, to allow for more compact, readable code. The functions can be used for single things (one element, one set of arguments) or they can operate en masse (arrays of elements, object literals with multiple key-value pairs). As you might guess, this practice has been strongly inspired by the heavy use of overloading in jQuery, which was one of the driving factors behind its huge success.
For example, let’s take $.style(). It can be used to set a single CSS property, on a single element, being a rather thin abstraction over element.style:
$.style(element, "top", rect.top);
It can also be used to set a single CSS property on multiple elements:
$.style($$(".popup"), "top", rect.top);
It can also be used to set multiple properties on a single element:
$.style(element, {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
);
Or to set multiple properties on multiple elements:
$.style($$(".popup"), {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
});
I’m a strong believer in overloading for handling both aggregate operations, as well as singular data. Supporting only aggregate operations would mean that developers have to pointlessly wrap single values in object literals or arrays. E.g. if $.style() only accepted arrays and object literals, our first example would be:
$.style([element], {top: rect.top});
Not the end of the world, but certainly annoying and error-prone. Developers would often try setting the pair as separate arguments because it’s more natural, remember it doesn’t work, then adjust their code.
The opposite situation is much worse. If $.style() only supported singular operations, our last example would be:
let values = {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
};
for (let element of $$(".popup")) {
for (let property in values) {
$.style(element, property, values[property]);
}
}
Yikes! You don’t need a library for that! Just using element.style and Object.assign() would have actually fared better here:
for (let element of $$(".popup")) {
Object.assign(element.style, {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
});
}
$.style() is not unique here: any Bliss function that accepts a main target element (the function’s subject as it’s called in the Bliss docs) also accepts arrays of elements. Similarly, any Bliss function that accepts key-value pairs as separate arguments, also accepts object literals with multiple of them.
In talks about API Design, I have presented this pattern (and overloading in general) as an instance of the Robustness principle in action: “Be liberal in what you accept” is good practice for designing any user interface, and APIs are no exception. An analog in GUI design would be bulk operations: imagine if e.g. you could only delete emails one by one?
In JS, overloading is typically implemented by inspecting the types and number of a function’s arguments in the function, and branching accordingly. However, doing this individually on every function would get quite repetitive. Consider the following, very simplified implementation of $.style() with the overloading logic inlined:
style(subject, ...args) {
if (Array.isArray(subject)) {
subject.forEach(e => style(e, ...args));
}
else if ($.type(args[0]) === "object" && args.length = 1) {
for (let p in args[0]) {
style(subject, p, args[0][p]);
}
}
else {
subject.style[args[0]] = args[1];
}
return subject;
}
Note that the actual code of this function is only 1 line out of the 13 lines of code it contains. The other 12 are just boilerplate for overloading. What a nightmare for maintainability and readability!
In Bliss v1, all functions were contained a single file, so they could be defined in their most singular version (one element, a single key-value pair as separate arguments etc), and the aggregate signatures could be automatically generated by looping over all defined functions and wrapping them accordingly.
However, in Bliss v2, each function is defined in its own module, as a default export. There is also a module pulling them all together and adding them on $, but people should be able to do things like:
import style from "https://v2.blissfuljs.com/src/dom/style.js";
And style() would need to support its full functionality, not be some cut down version allowing only single elements and one property-value pair. What use would that be?
This means that the overloading needs to happen in the module defining each function. It cannot happen via a loop in the index.js module. How can we do this and still keep our code maintainable, short, and easy to change? I explored several alternatives.
(We are not going to discuss the implementation of overload() in each case below, but if you’re interested in the current one, it’s on Github. Do note that just like everything in Bliss v2, it’s subject to heavy change before release)
Option 1: Inside each function
export default function style(subject, ...args) {
return overload(subject, args, (element, property, value) => {
element.style[property] = value;
})
}
While this at first seems like the most natural way to abstract the inlined code we previously had, it’s the most verbose and hard to read. Furthermore, it adds extra code that needs to be executed every time the function is called and needs us to pass the current execution context through. It’s far better to go with a solution that takes the singular function as input, and gives you a modified function that just works. That’s what the next two options use.
Option 2: Wrap with overload()
export default overload(function style(element, property, value) {
element.style[property] = value;
});
Option 3: Overload at export
function style(element, property, value) {
element.style[property] = value;
}
export default overload(style);
Options 2 and 3 are very similar. I was originally inclined to go with 2 to avoid typing the function name twice, but I eventually concluded that it made the code harder to read, so I went with option 3: Declaring the function, then overloading it & exporting it.
I wasn’t super happy with any of these options. Something inside me protested the idea of having to include even a line of boilerplate in every single module, and almost every Bliss function depending on another module. However, in the large scheme of things, I think this boilerplate is as minimal as it gets, and certainly beats the alternatives.
Have you had to perform a transform on a number of different modules in your code? How did you abstract it away?
1 You can see the rewrite progress in the v2 branch on Github, and even use v2.blissfuljs.com to import modules from and experiment. Note that at the time of writing, all of the progress is in the code, the docs and tests are still all about v1.
Mass function overloading: why and how?
One of the things I’ve been doing for the past few months (on and off—more off than on TBH) is rewriting Bliss to use ESM 1. Since Bliss v1 was not using a modular architecture at all, this introduced some interesting challenges. Bliss is essentially a collection of helper functions. Most of these functions have a number of different signatures, to allow for more compact, readable code. The functions can be used for single things (one element, one set of arguments) or they can operate en masse (arrays of elements, object literals with multiple key-value pairs). As you might guess, this practice has been strongly inspired by the heavy use of overloading in jQuery, which was one of the driving factors behind its huge success.
For example, let’s take $.style(). It can be used to set a single CSS property, on a single element, being a rather thin abstraction over element.style:
$.style(element, "top", rect.top);
It can also be used to set a single CSS property on multiple elements:
$.style($$(".popup"), "top", rect.top);
It can also be used to set multiple properties on a single element:
$.style(element, {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
);
Or to set multiple properties on multiple elements:
$.style($$(".popup"), {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
});
I’m a strong believer in overloading for handling both aggregate operations, as well as singular data. Supporting only aggregate operations would mean that developers have to pointlessly wrap single values in object literals or arrays. E.g. if $.style() only accepted arrays and object literals, our first example would be:
$.style([element], {top: rect.top});
Not the end of the world, but certainly annoying and error-prone. Developers would often try setting the pair as separate arguments because it’s more natural, remember it doesn’t work, then adjust their code.
The opposite situation is much worse. If $.style() only supported singular operations, our last example would be:
let values = {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
};
for (let element of $$(".popup")) {
for (let property in values) {
$.style(element, property, values[property]);
}
}
Yikes! You don’t need a library for that! Just using element.style and Object.assign() would have actually fared better here:
for (let element of $$(".popup")) {
Object.assign(element.style, {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left
});
}
$.style() is not unique here: any Bliss function that accepts a main target element (the function’s subject as it’s called in the Bliss docs) also accepts arrays of elements. Similarly, any Bliss function that accepts key-value pairs as separate arguments, also accepts object literals with multiple of them.
In talks about API Design, I have presented this pattern (and overloading in general) as an instance of the Robustness principle in action: “Be liberal in what you accept” is good practice for designing any user interface, and APIs are no exception. An analog in GUI design would be bulk operations: imagine if e.g. you could only delete emails one by one?
In JS, overloading is typically implemented by inspecting the types and number of a function’s arguments in the function, and branching accordingly. However, doing this individually on every function would get quite repetitive. Consider the following, very simplified implementation of $.style() with the overloading logic inlined:
style(subject, ...args) {
if (Array.isArray(subject)) {
subject.forEach(e => style(e, ...args));
}
else if ($.type(args[0]) === "object" && args.length = 1) {
for (let p in args[0]) {
style(subject, p, args[0][p]);
}
}
else {
subject.style[args[0]] = args[1];
}
return subject;
}
Note that the actual code of this function is only 1 line out of the 13 lines of code it contains. The other 12 are just boilerplate for overloading. What a nightmare for maintainability and readability!
In Bliss v1, all functions were contained a single file, so they could be defined in their most singular version (one element, a single key-value pair as separate arguments etc), and the aggregate signatures could be automatically generated by looping over all defined functions and wrapping them accordingly.
However, in Bliss v2, each function is defined in its own module, as a default export. There is also a module pulling them all together and adding them on $, but people should be able to do things like:
import style from "https://v2.blissfuljs.com/src/dom/style.js";
And style() would need to support its full functionality, not be some cut down version allowing only single elements and one property-value pair. What use would that be?
This means that the overloading needs to happen in the module defining each function. It cannot happen via a loop in the index.js module. How can we do this and still keep our code maintainable, short, and easy to change? I explored several alternatives.
(We are not going to discuss the implementation of overload() in each case below, but if you’re interested in the current one, it’s on Github. Do note that just like everything in Bliss v2, it’s subject to heavy change before release)
Option 1: Inside each function
export default function style(subject, ...args) {
return overload(subject, args, (element, property, value) => {
element.style[property] = value;
})
}
While this at first seems like the most natural way to abstract the inlined code we previously had, it’s the most verbose and hard to read. Furthermore, it adds extra code that needs to be executed every time the function is called and needs us to pass the current execution context through. It’s far better to go with a solution that takes the singular function as input, and gives you a modified function that just works. That’s what the next two options use.
Option 2: Wrap with overload()
export default overload(function style(element, property, value) {
element.style[property] = value;
});
Option 3: Overload at export
function style(element, property, value) {
element.style[property] = value;
}
export default overload(style);
Options 2 and 3 are very similar. I was originally inclined to go with 2 to avoid typing the function name twice, but I eventually concluded that it made the code harder to read, so I went with option 3: Declaring the function, then overloading it & exporting it.
I wasn’t super happy with any of these options. Something inside me protested the idea of having to include even a line of boilerplate in every single module, and almost every Bliss function depending on another module. However, in the large scheme of things, I think this boilerplate is as minimal as it gets, and certainly beats the alternatives.
Have you had to perform a transform on a number of different modules in your code? How did you abstract it away?
1 You can see the rewrite progress in the v2 branch on Github, and even use v2.blissfuljs.com to import modules from and experiment. Note that at the time of writing, all of the progress is in the code, the docs and tests are still all about v1.
Writable getters
Writable getters
Writable getters

Setters removing themselves are reminiscent of Ouroboros, the serpent eating its own tail, an ancient symbol. Media credit
A pattern that has come up a few times in my code is the following: an object has a property which defaults to an expression based on its other properties unless it’s explicitly set, in which case it functions like a normal property. Essentially, the expression functions as a default value.
Some examples of use cases:
- An object where a default
idis generated from itsnameortitle, but can also have custom ids. - An object with information about a human, where
namecan be either specified explicitly or generated fromfirstNameandlastNameif not specified. - An object with parameters for drawing an ellipse, where
rydefaults torxif not explicitly set. - An object literal with date information, and a
readableproperty which formats the date, but can be overwritten with a custom human-readable format. - An object representing parts of a Github URL (e.g. username, repo, branch) with an
apiCallproperty which can be either customized or generated from the parts (this is actually the example which prompted this blog post)
Ok, so now that I convinced you about the utility of this pattern, how do we implement it in JS?
Our first attempt may look something like this:
let lea = {
name: "Lea Verou",
get id() {
return this.name.toLowerCase().replace(/\W+/g, "-");
}
}
Note: We are going to use object literals in this post for simplicity, but the same logic applies to variations using Object.create(), or a class Person of which lea is an instance.
Our first attempt doesn’t quite work as you might expect:
lea.id; // "lea-verou"
lea.id = "lv";
lea.id; // Still "lea-verou"!
Why does this happen? The reason is that the presence of the getter turns the property into an accessor, and thus, it cannot also hold data. If it doesn’t have a setter, then simply nothing happens when it is set.
However, we can have a setter that, when invoked, deletes the accessor and replaces it with a data property:
let lea = {
name: "Lea Verou",
get id() {
return this.name.toLowerCase().replace(/\W+/g, "-");
},
set id(v) {
delete this.id;
return this.id = v;
}
}
Abstracting the pattern into a helper
If we find ourselves needing this pattern in more than one places in our codebase, we could abstract it into a helper:
function writableGetter(o, property, getter, options = {}) {
Object.defineProperty(o, property, {
get: getter,
set (v) {
delete this[property];
return this[property] = v;
},
enumerable: true,
configurable: true,
...options
});
}
Note that we used Object.defineProperty() here instead of the succinct get/set syntax. Not only is the former more convenient for augmenting pre-existing objects, but also it allows us to customize enumerability, while the latter just defaults to enumerable: true.
We’d use the helper like this:
let lea = {name: "Lea Verou"};
writableGetter(lea, "id", function() {
return this.name.toLowerCase().replace(/\W+/g, "-");
}, {enumerable: false});
Overwriting the getter with a different getter
This works when we want to overwrite with a static value, but what if we want to overwrite with a different getter? For example, consider the date use case: what if we want to maintain a single source of truth for the date components and only overwrite the format, as a function, so that when the date components change, the formatted date updates accordingly?
If we are confident that setting the property to an actual function value wouldn’t make sense, we could handle that case specially, and create a new getter instead of a data property:
function writableGetter(o, property, getter, options = {}) {
return Object.defineProperty(o, property, {
get () {
return getter.call(this);
},
set (v) {
if (typeof v === "function") {
getter = v;
}
else {
delete this[property];
return this[property] = v;
}
},
enumerable: true,
configurable: true,
...options
});
}
Do note that if we set the property to a static value, and try to set it to a function after that, it will just be a data property that creates a function, since we’ve deleted the accessor that handled functions specially. If that is a significant concern, we can maintain the accessor and just update the getter:
function writableGetter(o, property, getter, options = {}) {
return Object.defineProperty(o, property, {
get () {
return getter.call(this);
},
set (v) {
if (typeof v === "function") {
getter = v;
}
else {
getter = () => v;
}
},
enumerable: true,
configurable: true,
...options
});
}
Improving the DX of our helper
While this was the most straightforward way to define a helper, it doesn’t feel very natural to use. Our object definition is now scattered in multiple places, and readability is poor. This is often the case when we start implementing before designing a UI. In this case, writing the helper is the implementation, and its calling code is effectively the UI.
It’s always a good practice to start designing functions by writing a call to that function, as if a tireless elf working for us had already written the implementation of our dreams.
So how would we prefer to write our object? I’d actually prefer to use the more readable get() syntax, and have everything in one place, then somehow convert that getter to a writable getter. Something like this:
let lea = {
name: "Lea Verou",
get id() {
return this.name.toLowerCase().replace(/\W+/g, "-");
}
}
makeGetterWritable(lea, "id", {enumerable: true});
Can we implement something like this? Of course. This is JS, we can do anything!
The main idea is that we read back the descriptor our get syntax created, fiddle with it, then stuff it back in as a new property:
function makeGetterWritable(o, property, options) {
let d = Object.getOwnPropertyDescriptor(o, property);
let getter = d.get;
d.get = function() {
return getter.call(this);
};
d.set = function(v) {
if (typeof v === "function") {
getter = v;
}
else {
delete this[property];
return this[property] = v;
}
};
// Apply any overrides, e.g. enumerable
Object.assign(d, options);
// Redefine the property with the new descriptor
Object.defineProperty(o, property, d)
}
Other mixed data-accessor properties
While JS is very firm in its distinction of accessor properties and data properties, the reality is that we often need to combine the two in different ways, and conceptually it’s more of a data-accessor spectrum than two distinct categories. Here are a few more examples where the boundary between data property and accessor property is somewhat …murky:
- “Live” data properties: properties which execute code to produce side effects when they are get or set, but still hold data like a regular data property. This can be faked by having a helper that creates a hidden data property. This idea is the core of
Bliss.live(). - Lazy evaluation: Properties which are evaluated when they are first read (via a getter), then replace themselves with a regular data property. If they are set before they are read, they function exactly like a writable getter. This idea is the core of
Bliss.lazy(). MDN mentions this pattern too.
Note: Please don’t actually implement id/slug generation with name.toLowerCase().replace(/\W+/g, "-"). That’s very simplistic, to keep examples short. It privileges English/ASCII over other languages and writing systems, and thus, should be avoided.