Array.prototype.find - Proposal for (breaking) change of API
Then how could you find undefined
in an array? That's a real use case too.
In your A example, I'd represent that as:
var paths = files.map(file => path.resolve(base, file));
var found = paths.find(filePath => fs.existsSync(filePath));
… and then found
would be the resolved path you're looking for.
You need lazy sequences aka iterators. They give you the rather optimal:
let found = first(filter( map(files, _ => path.resolve(base, _)), fs.existsSync ));
Libs like lodash and lazy.js provide the bits you need, which are actually fairly trivial to build on top of nice new ES6 iterators if you want.
Alex
not sure if off topic but
- you need a with statement to use lodash like that
- ... the following ...
let found = first(filter(
map(files, _ => path.resolve(base, _)),
fs.existsSync
));
is a very wasteful pattern ... have you ever heard of some
?
let found;
some(files, _ => fs.existsSync(found = path.resolve(base, _)) || (found =
'') || false);
It could bring few alchemies in ;-)
Even more off-topic, I’m sure, but with rbuckton/queryjs (a query library over iterables) and ES6 you can do:
import { Query } from './query';
let files = ["main.md", "backup.md"];
let base = "/my/root";
let found = Query
.from(files)
.map(file => path.resolve(base, file))
.filter(file => fs.existsSync(file))
.first();
Ron
From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Andrea Giammarchi Sent: Tuesday, April 7, 2015 1:40 PM To: Alexander Jones Cc: Martin Heidegger; es-discuss at mozilla.org Subject: Re: Array.prototype.find - Proposal for (breaking) change of API
not sure if off topic but
- you need a with statement to use lodash like that
- ... the following ...
let found = first(filter(
map(files, _ => path.resolve(base, _)),
fs.existsSync
));
is a very wasteful pattern ... have you ever heard of some
?
let found;
some(files, _ => fs.existsSync(found = path.resolve(base, _)) || (found = '') || false);
It could bring few alchemies in ;-)
On Tue, Apr 7, 2015 at 9:14 PM, Alexander Jones <alex at weej.com<mailto:alex at weej.com>> wrote:
You need lazy sequences aka iterators. They give you the rather optimal:
let found = first(filter( map(files, _ => path.resolve(base, _)), fs.existsSync ));
Libs like lodash and lazy.js provide the bits you need, which are actually fairly trivial to build on top of nice new ES6 iterators if you want.
Alex
On Tuesday, April 7, 2015, Martin Heidegger <martin.heidegger at gmail.com<mailto:martin.heidegger at gmail.com>> wrote:
I am probably very late to the game but I just read about harmonies “Array.prototype.find” and found that it might be worth considering a change in way it works. Its not a drastic change but it would break the compatibility to the current setup. I understand that the chances for this going through will be slim but since I would like to give it a shot anyways:
Currently the API uses a callback function that has to return a boolean to identify the item that has been found. This is good because find & findIndex can use the same methods but it also has a drawback.
Problem: Say you have a list of items that need to be processed before you know if you “found” the item. Then you will need to process the last item again since there is no way to “keep” the result (A) of the find method or you preprocess all items using map (B) that will require to process all the items even if the first one already matches.
Example:
(BASE) var files = [“main.mdmain.md”, “backup.mdbackup.md”]
var base = “/my/root"
(A)
// Specifies path.resolve
on two places
var found = files.find(function (file) {
return fs.existsSync(path.resolve(base, file))
}))
if (found)
found = path.resolve(base, file)
(B)
// Runs path.resolve
for all items
var found = files.map(function (file) {
return path.resolve(base, file)
}).find(fs.existsSync)
Proposal (C): I think it might be interesting to have a change of the signature so that the return value is not true/false but the value that actually will be returned (not undefined):
(C) var found = files.find(function (file) { file = path.resolve(base, file) if(fs.existsSync(file)) return file });
This way the operations would be minimised, it is still few to write and it would make life a bit easier.
yours Martin Heidegger
It's not wasteful if, as I said, they are iterator-consuming functions. I'm not sure why you think mutating a closed-over variable is better or more efficient code. Email me off list and I'll explain, or just look up the Python 3 map and filter (or Python 2 itertools equivalents).
nope, I know it wasn't the bext example, but if you use Array methods as iterators examples I think I have a problem understanding what you are talking about.
What you rote, in a JS Array world, is wasteful, and bad/non-optimal usage of Array patterns we have/know already.
Maybe that's not the point you are trying to make, but surely mine, and when I read breaking change API and see non optimal patterns I believe the vision is not clear for everyone about where we are, and where we are moving.
Apologies if that's not the reply you were hoping for
actually never-mind, I got hooked by the "Libs like lodash and lazy.js
provide the bits you need" and thought you were using those functions as if
magically wrapped in a with
statement ... oh well, sorry for the noise:
keep "iterating"
I am probably very late to the game but I just read about harmonies “Array.prototype.find” and found that it might be worth considering a change in way it works. Its not a drastic change but it would break the compatibility to the current setup. I understand that the chances for this going through will be slim but since I would like to give it a shot anyways:
Currently the API uses a callback function that has to return a boolean to identify the item that has been found. This is good because find & findIndex can use the same methods but it also has a drawback.
Problem: Say you have a list of items that need to be processed before you know if you “found” the item. Then you will need to process the last item again since there is no way to “keep” the result (A) of the find method or you preprocess all items using map (B) that will require to process all the items even if the first one already matches.
Example:
(BASE) var files = [“main.md”, “backup.md”] var base = “/my/root"
(A) // Specifies
path.resolve
on two places var found = files.find(function (file) { return fs.existsSync(path.resolve(base, file)) })) if (found) found = path.resolve(base, file)(B) // Runs
path.resolve
for all items var found = files.map(function (file) { return path.resolve(base, file) }).find(fs.existsSync)Proposal (C): I think it might be interesting to have a change of the signature so that the return value is not true/false but the value that actually will be returned (not undefined):
(C) var found = files.find(function (file) { file = path.resolve(base, file) if(fs.existsSync(file)) return file });
This way the operations would be minimised, it is still few to write and it would make life a bit easier.
yours Martin Heidegger