Skip to content

Conversation

@kddnewton
Copy link

for/in returns the index for arrays, so this just works. Passes all the tests.

Before:

        122 B: dlv.js.gz
         91 B: dlv.js.br
        121 B: dlv.es.js.gz
         97 B: dlv.es.js.br
        198 B: dlv.umd.js.gz
        160 B: dlv.umd.js.br

After:

        109 B: dlv.js.gz
         83 B: dlv.js.br
        110 B: dlv.es.js.gz
         83 B: dlv.es.js.br
        185 B: dlv.umd.js.gz
        151 B: dlv.umd.js.br

@RReverser
Copy link
Contributor

Really well done!

@lukeed
Copy link
Contributor

lukeed commented May 23, 2019

So fun to do this 😆I had the same thing inside clsx originally, but ultimately reversed it for proper Array handling. Doing so (re)gained at least 2x performance: lukeed/clsx@91f5e68

I'm definitely all for cheeky golfing, but I think should maybe do a before/after comparison of this change.

@jonasraoni
Copy link

From:
module.exports=function(t,i,n,o,r){for(o in i=i.split?i.split("."):i)t=t?t[i[o]]:r;return t===r?n:t};
To:
module.exports=function(t,i,n,o,r){for(o in i=i.sub?i.split('.'):i)t=t?t[i[o]]:r;return t===r?n:t};

I was going to shave a bit more using template literals split`.` , but I see it's not in ES5 :L

Whatever, I think there should be a break in the loop.

@kddnewton
Copy link
Author

The other solution I came up with was:

export default function dlv(obj, key, def, p, undef) {
	key = key.split ? key.split('.') : key;
	for (p = 0; obj && p < key.length; obj = obj[key[p++]]);
	return p < key.length || obj === undef ? def : obj;
}

which does bail out early for deeply nested objects. It depends on if you want the trimmest version possible or the most efficient. If you're going for efficiency then I can change over to this one. Stats for that:

        126 B: dlv.js.gz
         92 B: dlv.js.br
        126 B: dlv.es.js.gz
        100 B: dlv.es.js.br
        200 B: dlv.umd.js.gz
        177 B: dlv.umd.js.br

It's a difference of 17 bytes, so up to you.

@RReverser
Copy link
Contributor

RReverser commented May 23, 2019

Bailing out early is what dlv has been doing before my PR - #30 - but I changed it to reduce size and I still believe that early fallout is not common nor does it give any substantial win to justify a more complicated code.

@jonasraoni
Copy link

I agree! But this is an episode of "what has been seen cannot be unseen" :)
Whatever, micro improvements are normally pointless, but that's where the fun lives \o/

@RReverser
Copy link
Contributor

@jonasraoni FWIW this one

module.exports=function(t,i,n,o,r){for(o in i=i.sub?i.split('.'):i)t=t?t[i[o]]:r;return t===r?n:t};

was pretty cool, but results in an actually larger size after compression (as shown by npm run build) due to two different words.

@luanmuniz
Copy link

Just a note. forin loops are a lot less performative then normal for loops.

I don't think this should aim for fewer bytes in the module rather than performance.

IMHO Even if we double the byte size, if we increase the performance I think it's still valid.

@RReverser
Copy link
Contributor

I don't think this should aim for fewer bytes

That's precisely the goal of this helper library AFAIK. If someone cares about performance, they shouldn't use string-based dynamic paths in the first place, but when they do, microimprovements of loops are not going to change much.

@mikesherov
Copy link

If performance is not a goal, then array reduce gives a smaller implementation, as pointed out in a few existing PRs: #8

I got:

Build "dlv" to dist:
        119 B: dlv.js.gz
         83 B: dlv.js.br
        118 B: dlv.es.js.gz
         89 B: dlv.es.js.br
        190 B: dlv.umd.js.gz
        150 B: dlv.umd.js.br

with:

export default function dlv(obj, key, def, p, undef) {
	key = key.split ? key.split('.') : key;
	obj = key.reduce(function(obj, p) {
		return obj ? obj[p] : undef
	}, obj);
	return obj === undef ? def : obj;
}

@lukeed
Copy link
Contributor

lukeed commented May 23, 2019

Jason's libraries are typically a balance of code size and performance. That's why they're so great.

I don't want to speak for him, but losing 13 bytes for less than half the performance is generally not worth it.

Screen Shot 2019-05-23 at 11 43 57 AM

Source: https://esbench.com/bench/5ce6e64a4cd7e6009ef62526

@mikesherov
Copy link

Here's the reduce version added to that bench as "Test 3":
image
https://esbench.com/bench/5ce6e64a4cd7e6009ef62526

@mikesherov
Copy link

Seems like reduce gives the size savings while only being 6% slower than for-in

@mikesherov
Copy link

Sorry, actually smaller!!!

Build "dlv" to dist:
        117 B: dlv.js.gz
         82 B: dlv.js.br
        116 B: dlv.es.js.gz
         81 B: dlv.es.js.br
        188 B: dlv.umd.js.gz
        148 B: dlv.umd.js.br

for:

export default function dlv(obj, key, def, undef) {
	key = key.split ? key.split('.') : key;
	obj = key.reduce(function(obj, p) {
		return obj ? obj[p] : undef
	}, obj);
	return obj === undef ? def : obj;
}

@mikesherov
Copy link

I opened a PR for the reduce version: #36

@kddnewton kddnewton closed this Jul 25, 2019
@kddnewton kddnewton deleted the slim branch July 25, 2019 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants