, 15 tweets, 2 min read Read on Twitter
Have you ever really looked at some of the library code we use every day (or used to)?

Let's look at underscore's "sample" method, which produces some amazing surprises if you poke at it a little.
The docs say: _.sample(list, [n])

Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned.

Easy enough?
First up: What is the time complexity of this operation?

I can't fit the answer in a tweet because there are too many cases.

e.g., _.sample(a, 1) is slower than _.sample(a)

The function is never time-efficient (a 1,000-element array is entirely shuffled to pluck two values).
Next: Allocations?

Again, depends on how it's called. For n != undefined, the array is always copied in its entirety (!!!) even if only sampling a small # of elements (isn't this the intended use case?)
What are the error conditions?

_.sample({ height: "10", width: "10", length: "10" }) is "10"
_.sample({ height: 10, width: 10, length: 10 }) is undefined
_.sample({ height: 10, width: 10, length: 10 }, 1) throws "sample.slice is not a function"
More edge cases?

_.sample(2, [3, 4]) returns [], but _.sample(2) returns undefined

[1, 2, 3].map(_.sample.bind(_, [3, 4, 5]) returns something like [[5], 3, 4] - have fun explaining that one
I bet this works with strings, right? Strings are list-ish?

_.sample("abcdef") returns a random character, as expected
_.sample("abcdef", 3) is *always* "abc"
_.sample("abc", "abc") is ""
So this function doesn't even always return an array, even for 'n' > 1

Underscore was built for size, not speed/predictability, but it's still *incredibly* hard just to describe the behavior of this function. I only tweet about TypeScript, though, so what's the connection?
DefinitelyTyped's job is, in part, to:
1) Figure out all the rules the docs don't explain
2) Get people to agree on which of those behaviors constitute "errors"
3) Explain that behavior to a computer using a general-purpose DSL
So sometimes I hear "Type definitions are too complex" and really my response is that it isn't the definitions that are too complex, it's the library behavior. The *true* documentation for "sample" alone would span several written pages.
If you come across some code that is heavily indirected and just says _.sample(obj, arg) you can literally say nothing about the return value without knowing a *lot* about both arguments. Isn't that... bad? Principle of Least Astonishment?
Complexity, huge amounts of it, is routinely hidden behind badly-documented library-specific coercion algorithms for the sake of presenting what appears to be a "smaller" API surface area.
In a reasonable world, 'sample' throws on non-array inputs, does the right thing on strings instead of nonsense, and you call sampleKeys or sampleValues to sample from objects.
This isn't me dynamic-shaming you, it's that a function should do one predictable job, not guesstimate your intent. You can write dynamic code without having five layers of "Does X if Y is Z, otherwise does Q to M when A is present"
My hope is that long-term, people write functions whose behavior is *easy* to describe, both to a human and to a machine.
Missing some Tweet in this thread?
You can try to force a refresh.

Like this thread? Get email updates or save it to PDF!

Subscribe to Ryan Cavanaugh
Profile picture

Get real-time email alerts when new unrolls (>4 tweets) are available from this author!

This content may be removed anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!