Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs: remove maybeCallback function #7168

Closed

Conversation

thefourtheye
Copy link
Contributor

Checklist
  • tests and code linting passes
  • the commit message follows commit guidelines
Affected core subsystem(s)

fs

Description of change

The "fs" module has two functions called maybeCallback and
makeCallback, as of now.

The maybeCallback creates a default function to report errors, if the
parameter passed is not a function object. Basically, if the callback
is omitted in some cases, this function is used to create a default
callback function.

The makeCallback, OTOH, creates a default function only if the
parameter passed is undefined, and if it is not a function object it
will throw an Error.

This patch removes the maybeCallback function and makes the callback
function argument mandatory for all the async versions.


cc @nodejs/collaborators

@thefourtheye thefourtheye added fs Issues and PRs related to the fs subsystem / file system. semver-major PRs that contain breaking changes and should be released in the next major version. labels Jun 5, 2016
@thefourtheye
Copy link
Contributor Author

@benjamingr
Copy link
Member

benjamingr commented Jun 5, 2016

Generally I like this change but I'm not really sure it's worth it given the amount of breakage it might cause in the wild.

---I tried running a smoke test but the CI gets frozen "Loading" when I attempt it - but I definitely think it's worth running in this case---

Smoke test: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/294/

Code changes themselves LGTM.

@bnoordhuis
Copy link
Member

I think the potential for ecosystem fallout is a bit too high to justify.

Note that makeCallback() and maybeCallback() treat the callback argument differently. The former calls rethrow() when it strict-equals undefined, the latter does so for any falsy value.

You could change makeCallback() to behave like maybeCallback() but that might introduce issues of its own.

@trevnorris
Copy link
Contributor

If we're going to break stuff, I'd rather break it to throw immediately when no callback is passed. Instead of throwing sometime in the future when the stack has been lost.

@benjamingr
Copy link
Member

@thealphanerd I looked at the smoke test output - it's green but looks like there are errors in the console output - can you PTAL?

@reqshark
Copy link

reqshark commented Jun 6, 2016

some of our production code would break with this change...

get ready to cringe: that's because with a preflight stat verifying path or read/writability, it turns out fs read/writes done in the fire-and-forget fashion (never passing a callback) are not only fine but also reliable

@benjamingr
Copy link
Member

@reqshark wait, what??

@reqshark
Copy link

reqshark commented Jun 6, 2016

While not passing a callback might be equal to passing undefined, and most of the node API won't let me get away with this now, I liked when we had the option to ignore callbacks or their parameters.

Occasionally program errors should be ignored, and the ability to not have to write an error handler for an inconsequential routine will reduce lines of code... for example, writing a noop() might be overkill

The decision not to pass the callback should result in an immediate consequence, either throw immediately or its /dev/null. Passing a function, on the otherhand, indicates a clear statement about wanting to wait and handle that outcome.

@trevnorris
Copy link
Contributor

If we are going to make a semver-major change here can we please simply throw immediately? Throwing in the future is one of the dumbest designs in node today.

@@ -1 +1 @@
require('fs').readFile('/'); // throws EISDIR
require('fs').readFile('/', undefined); // throws EISDIR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it not throw with arguments.length being 1?

@jasnell
Copy link
Member

jasnell commented Jun 20, 2016

+1 to throwing immediately.

Thinking out loud: I do get the case where an explicit noop would be useful, however. I'm wondering if some form of sentinel value could be used to explicitly signal that the async method should simply not bother attempting to callback tho. A Symbol would work...

fs.writeFile('/tmp/foo', 'hello there', fs.NoCallback);

I dunno, just a thought.

@Fishrock123
Copy link
Contributor

@jasnell Seems like a better option for a userland module to do?

@thefourtheye
Copy link
Contributor Author

Okay, updated the PR to throw if the callback is not passed. PTAL.

@trevnorris
Copy link
Contributor

Sweet. The code change LGTM. Looks like we're missing test coverage checking if all the altered functions throw. Mind making sure there's a single check for each method to make sure it throws if no callback is passed?

@thefourtheye
Copy link
Contributor Author

@trevnorris I included a test now to check if the functions fail when callback is not passed.

@@ -221,19 +191,17 @@ fs.Stats.prototype.isSocket = function() {
});

fs.access = function(path, mode, callback) {
callback = makeCallback(arguments[arguments.length - 1]);
Copy link
Member

@jasnell jasnell Jun 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm... not thrilled about this approach. For instance, the following is technically not an incorrect way of calling the fs.access() function even if the extraneous arguments on the end aren't supported. This code, however, would fail:

fs.access('/some/path', () => {}, 'useless', 'arguments', 'here');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasnell Perhaps I can traverse the arguments backwards and see if there is atleast one function object passed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little verbose, but should be as simple as:

if (typeof mode === 'function') {
  callback = mode;
  mode = fs.F_OK;
}
if (typeof mode !== 'number' || Number.isNaN(mode)) {
  throw new TypeError('mode must be a number');
}
if (typeof callback !== 'function') {
  throw new TypeError('callback must be a function');
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are doing this, we should probably do the same for other methods as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay. I'd like that change, but let's keep that for another PR.

@trevnorris
Copy link
Contributor

I agree with @jasnell's opinion on grabbing the last argument. Other than that LGTM.

@trevnorris
Copy link
Contributor

Still LGTM. With the note above that changing how arguments are parsed should go into another PR.

The "fs" module has two functions called `maybeCallback` and
`makeCallback`, as of now.

The `maybeCallback` creates a default function to report errors, if the
parameter passed is not a function object. Basically, if the callback
is omitted in some cases, this function is used to create a default
callback function.

The `makeCallback`, OTOH, creates a default function only if the
parameter passed is `undefined`, and if it is not a function object it
will throw an `Error`.

This patch removes the `maybeCallback` function and makes the callback
function argument mandatory for all the async functions.
@thefourtheye
Copy link
Contributor Author

@thefourtheye
Copy link
Contributor Author

Landed in 9359de9.

@thefourtheye thefourtheye deleted the remove-maybeCallBack branch July 21, 2016 21:06
thefourtheye added a commit that referenced this pull request Jul 21, 2016
The "fs" module has two functions called `maybeCallback` and
`makeCallback`, as of now.

The `maybeCallback` creates a default function to report errors, if the
parameter passed is not a function object. Basically, if the callback
is omitted in some cases, this function is used to create a default
callback function.

The `makeCallback`, OTOH, creates a default function only if the
parameter passed is `undefined`, and if it is not a function object it
will throw an `Error`.

This patch removes the `maybeCallback` function and makes the callback
function argument mandatory for all the async functions.

PR-URL: #7168
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
@MylesBorins
Copy link
Contributor

oh hey all... looks like this broke npm set which in turn is breaking citgm on master

/cc @nodejs/npm

MylesBorins pushed a commit to MylesBorins/node that referenced this pull request Jul 22, 2016
This reverts commit 9359de9.

Original Commit Message:

    The "fs" module has two functions called `maybeCallback` and
    `makeCallback`, as of now.

    The `maybeCallback` creates a default function to report errors, if the
    parameter passed is not a function object. Basically, if the callback
    is omitted in some cases, this function is used to create a default
    callback function.

    The `makeCallback`, OTOH, creates a default function only if the
    parameter passed is `undefined`, and if it is not a function object it
    will throw an `Error`.

    This patch removes the `maybeCallback` function and makes the callback
    function argument mandatory for all the async functions.

    PR-URL: nodejs#7168
    Reviewed-By: Trevor Norris <trev.norris@gmail.com>
@gibfahn gibfahn mentioned this pull request Jul 25, 2016
4 tasks
@othiym23
Copy link
Contributor

oh hey all... looks like this broke npm set which in turn is breaking citgm on master

Indeed, see npm/npm#13457 for further breakage that this causes in npm. What's the status on this?

@jasnell
Copy link
Member

jasnell commented Jul 28, 2016

Status is that we will be reverting this specific change and taking a
slightly different approach. Long term, callbacks will be required. Near
term it's possible that we'll emit warnings.

On Wednesday, July 27, 2016, Forrest L Norvell notifications@github.com
wrote:

oh hey all... looks like this broke npm set which in turn is breaking
citgm on master

Indeed, see npm/npm#13457 npm/npm#13457 for
further breakage that this causes in npm. What's the status on this?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#7168 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAa2eVGeyvMobe1tOxQ_py_DFtGXWHB-ks5qZ-xwgaJpZM4IudvB
.

MylesBorins pushed a commit to MylesBorins/node that referenced this pull request Aug 4, 2016
This reverts commit 9359de9.

Original Commit Message:

    The "fs" module has two functions called `maybeCallback` and
    `makeCallback`, as of now.

    The `maybeCallback` creates a default function to report errors, if the
    parameter passed is not a function object. Basically, if the callback
    is omitted in some cases, this function is used to create a default
    callback function.

    The `makeCallback`, OTOH, creates a default function only if the
    parameter passed is `undefined`, and if it is not a function object it
    will throw an `Error`.

    This patch removes the `maybeCallback` function and makes the callback
    function argument mandatory for all the async functions.

    PR-URL: nodejs#7168
    Reviewed-By: Trevor Norris <trev.norris@gmail.com>
addaleax pushed a commit that referenced this pull request Aug 4, 2016
This reverts commit 9359de9.

Original Commit Message:

    The "fs" module has two functions called `maybeCallback` and
    `makeCallback`, as of now.

    The `maybeCallback` creates a default function to report errors, if the
    parameter passed is not a function object. Basically, if the callback
    is omitted in some cases, this function is used to create a default
    callback function.

    The `makeCallback`, OTOH, creates a default function only if the
    parameter passed is `undefined`, and if it is not a function object it
    will throw an `Error`.

    This patch removes the `maybeCallback` function and makes the callback
    function argument mandatory for all the async functions.

    PR-URL: #7168
    Reviewed-By: Trevor Norris <trev.norris@gmail.com>

PR-URL: #7846
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
@cjihrig cjihrig mentioned this pull request Aug 10, 2016
2 tasks
@gibfahn gibfahn mentioned this pull request Jun 15, 2017
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fs Issues and PRs related to the fs subsystem / file system. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants