Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Core API #4

Closed
bnjmnt4n opened this issue Jun 5, 2015 · 42 comments
Closed

Core API #4

bnjmnt4n opened this issue Jun 5, 2015 · 42 comments
Labels

Comments

@bnjmnt4n
Copy link

bnjmnt4n commented Jun 5, 2015

Just briefly glancing through the “Core” and “More” functions, I think difference and intersection should be in the core, as they are used very commonly.

@chicoxyzzy
Copy link

totally agree

@jashkenas
Copy link
Contributor

Are they really? Enlighten us. Got some examples of places you use difference and intersection in real-world code?

@jdalton
Copy link
Contributor

jdalton commented Jun 5, 2015

Yep, I those set methods are pretty common (I use them in my own code regularly).

@megawac
Copy link
Contributor

megawac commented Jun 5, 2015

My thoughts on the current state

Strongly in favour of

+indexOf
+lastIndexOf
+now
+omit
+max
+min
+drop
+take
+first
+last
+restParam
+negate

If we're sharing core features and keeping both project identities for now (#6)

-chain
-iteratee

Borderline. I'm not sure if these belong

+union
+intersection
+difference
-memoize
-compose

@akre54
Copy link

akre54 commented Jun 5, 2015

first and last really? I think I've only used them while chaining. I almost always just do arr[0] or arr[arr.length - 1]. Not pretty, but idiomatic (and makes me wistful for other rubyisms).

Memoize is much better handled in idiomatic JS (the Underscore API isn't great for it). compose is cool, but also not super useful as an API.

@megawac
Copy link
Contributor

megawac commented Jun 5, 2015

They're convenient for cases where arr can be null

@akre54
Copy link

akre54 commented Jun 5, 2015

How often do you use them outside of chaining though? I'd wager you almost always want to do arr && arr[0] instead. Utility functions are great, using the language is better.

@jridgewell
Copy link
Contributor

I actually use first and last frequently (just for 1 element, not the n form).

Agree with removing memoize and compose, and everything in your "strong support" except negate.

@jdalton
Copy link
Contributor

jdalton commented Jun 5, 2015

I actually use first and last frequently (just for 1 element, not the n form).

Lodash split first, last into take, drop, takeWhile, takeRightWhile, dropWhile, dropRightWhile. So the first, last, initial, rest are the most basic forms.

Since the goal is a small core we should err on the side of less, it can always expand later (if needed).

Yep, I those set methods are pretty common (I use them in my own code regularly).

To my earlier comment while difference, intersection, & uniq are handy. Lodash & Underscore differ on implementations so may be easier to punt them as non-core for now.

@jdalton
Copy link
Contributor

jdalton commented Jun 8, 2015

Update:
I'm kicking around a combo of methods roughly (give or take a few) like those from Underscore 1.3.3 and Lodash 0.1.0 which comes in at a low 4kb or 5kb.

Update:
Experimenting with a core that can pass the Backbone unit tests.

Updates (July 15):
The following is a list of work items I've done in prepping for lodash v4 (due at the end of July) which proofs out several Underdash ideas.

  • Removed the following aliases:
    all, any, backflow, collect, compose, contains, detect, eq, foldl, foldr, head, include, inject, methods, object, select, tail, unique
  • Removed _.findWhere, _.pluck, & _.where in favor of _.find, _.map, & _.filter
  • Absorbed _.sortByAll into _.sortBy
  • Made _.assign, _.extend, _.defaults, & _.merge coerce values to objects so
    _.extend(null,{a:1},{b:2}) will return {a:1,b:2}
  • Made "Collection" methods treat functions as objects
  • Made _.eq its own method to perform a SameValueZero comparison between two values
  • Made _.extend and _.defaults align with Underscore's behavior
  • Made _.sortByOrder accept "asc" and "desc" (in v3.10.0)
  • Removed IE 6/7 testing
  • Removed legacy support for boolean values for options object params in methods like _.debounce
  • Removed pre-es5 environment support as those wanting older enviros can simply load es5-shim first
  • Removed isDeep params from _.clone and _.flatten in favour of _.cloneDeep and _.flattenDeep
  • Removed thisArg, aka context, params methods in favor of folks using _.bind
  • Renamed _.callback to _.iteratee to align with Underscore
  • Split out _.max, _.min, _.sum, _.sortedIndex, _.sortedLastIndex, _.uniq
    to separate their iteratee functionality with _.maxBy, _.minBy, etc. and limited the iteratee to receive only the value param
  • Split out _.assign, _.clone, _.extend, _.isEqual, _.merge, _.omit, & _.pick
    to separate their customizer functionality into _.assignWith, _.cloneWith, etc.
  • Removed most of the createXYZ methods for improved readability

Next up I'm creating the smaller core. As for the smaller core I'm currently keeping things as-is for the npm package. This means kitchen sink and modules as usual for node folks. The smaller core build will come in to play for the bower/component packages and site downloads.

@SimenB
Copy link

SimenB commented Jul 10, 2015

Removed isDeep params from _.clone and _.flatten

Will those still be available in some form? The reason I went from underscore to lodash in the first place was deep clone. 😆 Maybe not the main reason I migrated (jQuery.extend can be made deep), but it was the reason I looked into migrating at all.
(It showed up when I googled why _.clone didn't work like I wanted it to)

Either way, I'm really excited about where you're taking this, keep up the awesome work!

@megawac
Copy link
Contributor

megawac commented Jul 10, 2015

Will those still be available in some form?

_.cloneDeep & _.flattenDeep

@SimenB
Copy link

SimenB commented Jul 10, 2015

Ah, nice! Never was a fan of boolean params anyway. Perfect solution. Thanks for the swift response! No idea how I didn't notice it before...

@riyadhalnur
Copy link

i noticed _.assign doesn't do child object assignments very well. it ends up overwriting the parent object's keys.

@jdalton
Copy link
Contributor

jdalton commented Jul 19, 2015

i noticed _.assign doesn't do child object assignments very well. it ends up overwriting the parent object's keys.

Correct, recursive assignment is what _.merge is for.

@riyadhalnur
Copy link

@jdalton ah, thanks for clearing it up

@jdalton
Copy link
Contributor

jdalton commented Jul 21, 2015

Ok so here's the 58 methods I've gotten to include in the 4kb build which should still support Backbone:

["before", "bind", "chain", "clone", "compact", "defaults", "defer", "delay", "escape",
 "every", "extend", "filter", "find", "first", "flatten", "flattenDeep", "forEach",
 "functions", "has", "identity", "indexOf", "invoke", "isArguments", "isArray", "isDate",
 "isEmpty", "isEqual", "isFinite", "isFunction", "isObject", "isRegExp", "isString",
 "iteratee", "keys", "keysIn", "last", "map", "max", "min", "mixin", "negate",
 "noConflict", "noop", "now", "once", "pick", "reduce", "result", "size", "slice",
 "some", "sortBy", "tap", "thru", "toArray", "uniqueId", "value", "values"]

@adelgado
Copy link

Removed the following aliases:
all, any, backflow, collect, compose, contains, detect, eq, foldl, foldr, head, include, inject, methods, object, select, tail, unique

@jdalton Out of curiosity: what's the rationale for this?

@jdalton
Copy link
Contributor

jdalton commented Jul 27, 2015

@adelgado

Out of curiosity: what's the rationale for this?

To keep the API clean and focused.

@akre54
Copy link

akre54 commented Jul 27, 2015

"Penny wise and dollar foolish", as my dad would say...

@jdalton
Copy link
Contributor

jdalton commented Jul 27, 2015

@akre54

"Penny wise and dollar foolish", as my dad would say...

Sometimes aliases are great but having close to 20 of them is a bit much. Reducing the aliases also helps devs grok the API so they don't have to map for example that contains is the same include is the same as includes.

@akre54
Copy link

akre54 commented Jul 27, 2015

But some of those aliases read better in real code than their canonical names (some vs any is a big one). Ruby seems to be doing just fine with its aliases in the language.

There's real fat trimming to be done in Lo-Dash and Underscore. Killing 20 aliases isn't really the problem.

@jdalton
Copy link
Contributor

jdalton commented Jul 27, 2015

But some of those aliases read better in real code than their canonical names (some vs any is a big one)

I dig favoring those with JS lang precedents over Ruby since this is a JS lib and devs are more likely to be familiar with the JS names.

There's real fat trimming to be done in Lo-Dash and Underscore. Killing 20 aliases isn't really the problem.

Fat trimming is a different issue which is tackled by other line items. Reducing aliases is more about ensuring a more focused, uniform, & grokkable API.

In addition, a subtle issue I've seen with aliases is that devs reach for them not knowing which is the primary/preferred API and end up with dependencies which just point to others adding extraneous scaffolding for browserfiy/webpack bundles.

@michaelficarra
Copy link

I'm for getting rid of aliases. Each function should have a single canonical name. If you want to use an alias, use underscore like this:

import _, {some, some as any} from "underscore";

@akre54
Copy link

akre54 commented Jul 28, 2015

That's not the point at all. But fine. Killing aliases is the definition of bikeshedding. Don't we have some actual culling to do?

@jdalton
Copy link
Contributor

jdalton commented Jul 28, 2015

Don't we have some actual culling to do?

On my end I've created a 4kb lodash core build.

@jdalton
Copy link
Contributor

jdalton commented Jul 30, 2015

The WIP core build is up.

The core build is composed of methods required by Backbone and others I could fit into 4kb gzipped.
I made sure to include reduce since it's the swiss army knife of methods and helpers like noConflict.

I got the file size down by removing deep path look ups, removing placeholder support, removing array and method composition optimizations, and removing features from clone and sortBy to be on par with Underscore.

@CrossEye
Copy link

💯

Very nice!

@ghost
Copy link

ghost commented Aug 11, 2015

I think some of those 'aliases' were well established long before Lodash (e.g. head, tail, etc.), no? It would be a shame for someone coming from FP land would have to learn new terms here?

@jdalton
Copy link
Contributor

jdalton commented Aug 11, 2015

They are rooted in other langs and I'm OK with dropping them. This is JS (this is Spartaaaa) I'm fine with folks learning alternative APIs.

@bjmiller
Copy link

Two thoughts.

  1. I like the "We're all adults here" approach. It can be made real with a sort of companion to _.mixin.
_.alias({reduce: 'foldl', some: 'any'});

(This itself can be written as a mixin, if need be.)

  1. Is it realistic to provide a "lodash-migrate" library similar to jquery-migrate, for people who want to move to v4/underdash without having to break their code right away? Having helpful console warnings like "_.any has been removed in favor of _.some" sure is easier than having things just fail with "_.any is not a function".

@jdalton
Copy link
Contributor

jdalton commented Aug 11, 2015

  1. Is it realistic to provide a "lodash-migrate"

You mean this... :)

@bjmiller
Copy link

Exactly!

Any comments on whether an alias method is appropriate?

@jdalton
Copy link
Contributor

jdalton commented Aug 11, 2015

Any comments on whether an alias method is appropriate?

I think use of _.mixin is simple enough:

_.mixin({foldl: _.reduce, any: _.some});

@michaelficarra
Copy link

_.mixin({ alias: _.mixin });

😅

@cryo-warden
Copy link

The suggested API for alias is a little different from mixin, but I think mixin is better. The number of characters typed is the same, but with mixin, you directly reference functions on _, which is convenient for static analysis.

_.alias({reduce: 'foldl', some: 'any'});

_.mixin({reduce: _.foldl, some: _.any});

@jdalton
Copy link
Contributor

jdalton commented Aug 27, 2015

Continuing to reduce overloaded methods I've split out
_.sortedUniq, _.sortedUniqBy, _.sortedIndexOf, and _.sortedLastIndexOf.

@jdalton
Copy link
Contributor

jdalton commented Nov 20, 2015

I've gotten the 4kb core build tested via our CI now. Since June there's been ~700 commits which is pretty active development. It's like squeezing ~3yrs of Underscore development into ~6 months.

@alundiak
Copy link

alundiak commented Dec 1, 2015

@jdalton I realize it's not yet officially published/released, right? But would it be ok, if I would have latest code in file, and I would try to replace underdash in Backbone app to replace underscore, and another project to replace lodash, so that to test if my app work :) Kinda code testing for free :)

@bnjmnt4n
Copy link
Author

bnjmnt4n commented Dec 1, 2015

@alundiak Currently we're only in discussion phase, so there's no code that you can replace Underscore/lodash with as of right now. What @jdalton has been referring to is lodash 4.0, due out in January, which will have a core build based on ideas in current discussions.

@jdalton
Copy link
Contributor

jdalton commented Feb 6, 2016

Lodash v4 release notes!

@jdalton
Copy link
Contributor

jdalton commented Feb 13, 2016

Closed by #14.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

No branches or pull requests