Skip to content

Instantly share code, notes, and snippets.

@mikermcneil
Last active December 20, 2017 03:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikermcneil/1efd95bdcedecbd064f9d0d0ba725b13 to your computer and use it in GitHub Desktop.
Save mikermcneil/1efd95bdcedecbd064f9d0d0ba725b13 to your computer and use it in GitHub Desktop.
Seems to me there are two varieties of procedural parameters out there: "leases" and "consequences".

2 kinds of procedural parameters

Seems to me there are two varieties of procedural parameters out there: "leases" and "consequences".

Examples

Procedures (generic)

doSomethingMysterious(()=>{
  // We don't know much, but we know this function is a procedure!
});
doSomethingMysterious(async ()=>{
  // Same here. Just because it's an async function is no guarantee it's a lease.
});

Leases

var result = await sails.helpers.flow.build(async()=>{
  // This function is a lease, because:
  // • the return value / error thrown matters
  // • implementorland waits for it to finish after cueing it internally
  return 3;
});
assert.equal(result, 3);
var result = await sails.helpers.flow.build(()=>{
  // Same here.
  return 3;
});
assert.equal(result, 3);
// (in ajax-form component)
handleParsingForm: function(formData){
  // Lease (because we care about the return value)
  return _.omit(formData, ['fullName', 'emailAddress']);
}
await sails.getDatastore().transaction(async (proceed)=>{
  // This function is a lease even though there's technically no return value.
  // The callback is serving the same purpose though.
  proceed();
});
machine({
  identity: 'foo',
  fn: async function(inputs, exits) {
    // Same deal with `exits` here.
    // (i.e. this function is a lease too)
    exits.success();
  }
})
await User.stream().eachRecord(async (record, proceed)=>{
  // Yet another lease.
  proceed();
});
async.eachSeries((next)=>{
  // Another, older school example of a lease.
  next();
}, (err)=>{
  // This "afterwards" callback is NOT a lease.
  // (It's a consequence.)
});
sails.router.bind('GET /foo', (req, res)=>{
  // This function is another kind of lease.
  // (Even though the TCP connetion eventually times out, the important thing is that implementorland
  // waits for something to happen-- in this case for a response method to be called.)
  res.send();
});
things.map((thing)=>{
  // This iteratee function is a lease.
  // (b/c the return value matters)
  return thing;
});

Consequences

io.socket.on('user', (msg)=>{
  // This is a consequence.
});
oldFashionedNodeStream.on('data', (chunk)=>{
  // This is a consequence.
});
User.find().exec((err)=>{
  // Another one!
  // All traditional Node callback functions are consequences.
});
setTimeout(
  // Same here.
  // The same goes for any "afterwards" procedure -- not just Node.js callbacks.
}, 500);
sails.load({
  log: {
    custom: {
      log: function(/*…*/){
        // This is a consequence.
        // (it'll be potentially invoked at some later time, and we don't know when)
        console.log.apply(console, arguments);
      }
    }
  }
});
things.forEach((thing)=>{
  // Remember above, how we showed that the iteratee passed into `.map()` is a lease?
  // Well, iteratees are not necessarily leases.  For example, this one is a consequence.
  // (because the return value doesn't matter and there's no way to communicate back with the iterating implementation--
  // i.e. you  can't break out of the loop or accumulate a result)  Technically a thrown exception breaks you out,
  // so it's possible, but only by coincidence.  If it takes a hack like that to make a procedure into a lease, that
  // doesn't make it a lease, does it?
});
// (in ajax-form component)
submittedForm: function(){
  // Notifier
},

Trickier gray areas

$('#some-button').click((e)=>{
  // Seems like a consequence, right?  Well, for some DOM events, it might be.
  // But technically, for most of them, it's really a lease:
  // There _are_ ways that its contents can affect the event system-- e.g. e.stopPropagation() and e.preventDefault().
  // In fact, depending on which DOM event and browser we're talking about, the return value could actually matter
  // (e.g. the form "submit" event in old releases of IE)
});
newStream.on('readable', ()=>{
  // This procedure is effectively a consequence.  Its return value doesn't matter,
  // and it is powered by a Node event emitter, which ignores exceptions (to the point of
  // potentially crashing the process in some cases!)
  //
  // But still, there is an argument to be made that it is technically a lease,
  // Why?  Because you can influence the implementation's behavior by calling other
  // methods on the stream instance.  Namely:
  newStream.read();
  //
  // Still, this is a gray area.  I'd still be tempted to call this a consequence since the
  // applicable means of communication is being accessed via closure.
});

Glossary

Noun Proposed definition
Subroutine A function (for our purposes)
Procedural parameter The aspect of an interface that expects a subroutine from userland, with the idea of invoking it (e.g. during: { example: '=>' })
Procedural variable The variable representing the subroutine received for a procedural parameter (e.g. inputs.during)
Procedure A (usually hand-rolled) function that is meant to be passed in for a procedural parameter, or perhaps that has already been passed in.
Lease parameter A procedural parameter that expects a lease (aka "tenure")
Lease ("tenure") A kind of procedure designed to be passed in for a lease parameter (might be run >=0 times)
Consequence parameter A procedural parameter that expects a consequence
Consequence A kind of procedure designed to be passed in for a consequence parameter (might be run >=0 times).
Verb Subject Proposed definition
to cue … ("trigger" …) implementorland instruction The act of invoking a procedure (might be a lease or consequence). (Note that this doesn't necessarily indicate whether to necessarily wait for it to complete, pay any attention to its return value, or if it throws an exception, whether or not to ignore that)
to attach … userland argin The act of passing in a procedure (might be a lease or consequence) to some other function, where the expectation is that the attached lease or consequence will be run >=0 times at some point(s) in the future
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment