Skip to content

Instantly share code, notes, and snippets.

@abetkin
Last active November 4, 2016 12:39
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 abetkin/0061c1e8ae7998c1b2194a737373388f to your computer and use it in GitHub Desktop.
Save abetkin/0061c1e8ae7998c1b2194a737373388f to your computer and use it in GitHub Desktop.

Hi everyone!

I am coming from Python background, and in Python we have context managers.

These are objects encapsulating the try-catch-finally block, and usually are used to cleanup resources, like closing the open file. In Python community, most developers consider context managers a very neat feature of the language and you really can find them often in the code.

So, my question is: why is this feature missing completely in the js world? I could not find a single library. I think I can imagine what it could look like:

import With from 'missing-context-managers'
import open from 'some-file-utils'

With(open(file_path), (file) => {
    // file is open now
    console.log(file.getContents())
})
// file is closed now

From what I understand, the respective aspects of the language (error handling) is pretty much the same in python and javascript. What is the difference? Why one community finds a feature useful and the other - completely not?

P. S. I am not really asking if you consider context managers useful, just what is the possible difference between js/nodejs and python in this aspect.

@callahad
Copy link

callahad commented Nov 3, 2016

I think much of this stems from just having resources that need to be cleaned up: open sockets, file descriptors, etc. Python solves this with context managers, C++ with destructors, Golang (kinda) with defer, Java (kinda) with finalizers, Rust with the Drop trait, and so on.

...but JavaScript in the browser never had those sorts of concerns. You'd never need worry about forgetting to close a file, because you couldn't open a file in the first place. You didn't need to worry about releasing mutexes or locks, because JavaScript was single-threaded. It's only with Node that we're starting to have some of those concerns, and I don't have any insight into Node's development. However, it does seem like proper support for something like a context manager would likely require support from the language, and Node doesn't fork JavaScript itself, so its hands are, in a sense, tied. :)

@abetkin
Copy link
Author

abetkin commented Nov 3, 2016

@callahad Thank you! Why do you think there is support from the language required?

@callahad
Copy link

callahad commented Nov 3, 2016

Because you have to be able to run some code when a block ends and there are no more references to its resources. That's really hard to do in an async/callback-heavy language like JavaScript. In your example above, the call to file.getContents() would probably return immediately, and schedule a callback for later, like Node's fs.readFile(). Which means you'd exit the With function and close the file handler before readFile() has a chance to run.

Alternatively, you could only use synchronous, blocking methods like fs.readFileSync(), but then all of your execution is paused while you wait on I/O: a total non-starter.

...You could probably hack something together generators (or maybe even with promises?), but those have only come to JavaScript recently.

@abetkin
Copy link
Author

abetkin commented Nov 3, 2016

@callahad I was talking about context managers for synchronous code like readFileSync, taking reading file contents just as an example.

@abetkin
Copy link
Author

abetkin commented Nov 3, 2016

@callahad Finally I have a hypothesis: that the missing library is just missing.

Probably, when facing with the need, say, to read a file (abstract example!) js developers write:

open(file_path, (file) => {
  // ...
})

merging With and open into the open function. I have actually very little experience in nodejs world, so I need proof :).
@sindresorhus @gaearon is this true ?

So, nothing, imho, really stops js community from writing some kind of contextlib with neat and powerfull stuff like
ExitStack.

@callahad About what you've written on the support in other languages: I don't think
destructors / finalizers can be directly compared to context managers:
the latter do error handling within a scope of a code-block or function,
and the former - just the resource cleanup (special case of error handling, you can't have different cleanup logic depending on which exception was raised), usually without any garantees in which scope or when it will be done.
But talking about scripting languages, Ruby has "code blocks" which are not less powerful than python context
managers.

@rfk
Copy link

rfk commented Nov 4, 2016

You might also find some inspiration from the resource-management APIs provided by bluebird:

http://bluebirdjs.com/docs/api/resource-management.html
http://bluebirdjs.com/docs/api/disposer.html

Although the documentation there is not terribly clear for newcomers, I think it's in the ballpark of what you're describing here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment