Cargo Cult Code Generation
Javascript Errors in the Wild⌗
Recently, I came across this code in the popular Axios library:
function AxiosError(message, code, config, request, response) {
Error.call(this);
// some more code i've left out for brevity
}
What does Error.call(this)
do, you might ask? Nothing! I’ve tried it out in
Node versions back until 6, Spidermonkey and JavaScriptCore. None of them do anything to the this
object of the
Error
constructor. Moreover, the specification
says that you have to be able to call the Error
constructor without new
, so it makes sense to implement it
that way. Depending on how good you know Javascript Errors, you might assume that this call might:
- Turn
this
into aninstanceof Error
- It does not. - Turn
this
into a native error - It does not. - Add a
stack
property tothis
- It does not.
Error.call(this)
does absolutely nothing to this
. Zero, zilch, nada. The only thing it does is waste a lot of CPU time.
It creates a new Error
object and a new stack trace - a costly thing to do - and then lets the GC throw it away.
This is a a case of cargo cult programming:
Cargo cult programming is a style of computer programming characterized by the ritual inclusion of code or program structures that serve no real purpose.
I don’t want to hate on Axios through, a ton of popular libraries do this! I’ve grep
ed through my node_modules
folder and
found it in rxjs, jsonwebtoken, nock and js-yaml (which comes bundled with Node.js).
Sourcegraph finds more than 133K results in over 10k repos
for both Typescript and Javascript if you search for Error.call(this)
.1
Cargo Cult Copilot⌗
If Github Copilot is trained on this, will it generate code with Error.call(this)
in it? I’ve tried it by typing
function CachingError
and let it generate from there:
function CachingError(message) {
this.name = 'CachingError'
this.message = message
this.stack = (new Error()).stack
}
This can be done better, but no Error.call(this)
. On my second try I got the following result:
function CachingError() {
Error.apply(this, arguments);
}
There we are! Using .apply
instead of .call
and passing on the arguments
array would even be a good idea
if the Error
constructor would do something to it’s this
.
CargoGPT4⌗
What about ChatGPT? I’ve tried this prompt with GPT4:
CachingError
in Javascript using prototypal inheritance.Here’s an example of a CachingError subclass in JavaScript using prototypal inheritance:
// Define the CachingError constructor
function CachingError(message) {
// Call the Error constructor with the given message
Error.call(this, message);
// Set the error name to 'CachingError'
this.name = 'CachingError';
// Capture the current stack trace and store it in the error object
Error.captureStackTrace(this, CachingError);
}
// Set up the prototype chain between CachingError and Error
CachingError.prototype = Object.create(Error.prototype);
CachingError.prototype.constructor = CachingError;
// Example usage
try {
throw new CachingError('An error occurred while caching data');
} catch (error) {
console.error(error.name); // CachingError
console.error(error.message); // An error occurred while caching data
console.error(error.stack); // Stack trace
}
On the first try!
LoRas to the Rescue!⌗
The central problem with AI code generation is Sturgeon’s law:
Sturgeon’s law (or Sturgeon’s revelation) is an adage stating “ninety percent of everything is crap”.
90% of code is crap. That means instead of having gigantic models trained on everything that people can get their hands on, use smaller models and train with better code. In the Stable Diffusion community, people train textual inversions with 5 images and LoRas with ~20. There needs to be a “Javascript Error LoRa” in ChatGPT and Copilot that fixes this.
How to Do It Properly⌗
If you want to create a subclass of Error
use class
syntax:
class MyError extends Error {
constructor(){
super(...arguments);
this.name = "MyError";
}
}
This way, your error will be a native error, instanceof Error
and have a .name
property that differentiates it from other errors.
If you want to continue this deep dive, check out my post on how to detect if an object is an error, parts of which made it into the official Node.js documentation.
I’m sure there are a lot for false positives and false negatives (
Error.apply
…) in this search, but you get the idea. ↩︎