npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

immutagen

v1.0.9

Published

A library for emulating immutable generators in JavaScript

Downloads

1,418

Readme

immutagen Build Status

A JavaScript microlibrary for emulated immutable generators.

Installation

npm install --save immutagen

Usage

import immutagen from 'immutagen'

const gen = immutagen(function*() {
  yield 1
  yield 2
  return 3
})()                      // { value: 1, next: [function] }

gen.next()                // { value: 2, next: [function] }
gen.next()                // { value: 2, next: [function] }

gen.next().next()         // { value: 3, next: null }

immutagen takes a generator function and returns an immutable generator object. Instead of mutating itself upon each call to next(), it returns a new generation method next alongside the value it produces. When next is undefined, the generator is exhausted.

Motivation

Generators are a very cool feature of ES6+ which open up a lot of possibilities for metaprogramming. Unfortunately, as implemented they are less powerful than they could be. The problem is that the generator objects obtained by invoking a generator function are mutable. One repeatedly invokes a next() method on the same generator object, which moves it through its own private state machine, returning potentially different values each time:

function* genFun() {
  const x = yield 1
  return 2 + x
}
const gen = genFun()
gen.next()  // -> { value: 1, done: false }
gen.next(3) // -> { value: 5, done: true }

This means that whenever we call gen.next(...), the state that gen was in before the call is lost forever. For example once we make the gen.next(3) call above, we can no longer find out what would've happened if we had passed 6 instead of 3 to the generator in that particular state. One solution to this situation would be if we could clone generators in a particular state:

gen.next()          // -> { value: 1, done: false }
gen.clone().next(3) // -> { value: 5, done: true }
gen.clone().next(6) // -> { value: 8, done: true }

Unfortunately no such clone() method exists for generators, nor is it possible to implement one without employing essentially the same emulation technique as does this library to implement immutable generators.

Why does any of this matter? It may all seem academic, but suffice it to say that certain libraries we might like to build are impossible without immutable or cloneable generators. My own use case is the burrido library.

Emulated Immutability

Without the ability to defensively copy mutable generators, we can't implement true immutable generators. We can, however, emulate them, assuming a pure generator function. The strategy is to keep track of the history of values that have been fed into the generator at every yield expression so far, and then "replay" them from scratch whenever we want to recreate a generator in the same state.

It is however crucial that the generator function be pure; if it is impure in its input the generator's state could diverge upon replay, and if it is impure in its output, replaying will cause repetition of side-effects. Note also that there is inherent inefficiency in this technique, because every yield expression requires replaying the entire history up to that point. For this reason it's advisable to keep expensive computations to a minimum inside immutable generators, particularly as the number of yield expressions in the generator grows. Even if there isn't a lot of expensive computation, the runtime complexity will be quadratic in the number of yield expressions to be evaluated, so be careful.