Stream: t-lang/wg-unsafe-code-guidelines

Topic: meeting 2018-09-13


avadacatavra (Sep 12 2018 at 01:44, on Zulip):

I'm getting together information for the meeting on Thursday. Post anything you think is relevant/progress/etc here (or PM me idc)

Nicole Mazzuca (Sep 12 2018 at 05:04, on Zulip):

It's at 8:15 PST, right?

avadacatavra (Sep 12 2018 at 14:05, on Zulip):

Yup--do you have/want a calendar invite?

Nicole Mazzuca (Sep 12 2018 at 14:06, on Zulip):

I have a calendar invite, but I forgot that I have no idea how to use google calendar :P

Nicole Mazzuca (Sep 12 2018 at 15:15, on Zulip):

:wave:

Nicole Mazzuca (Sep 12 2018 at 15:16, on Zulip):

where are we actually having this meeting?

Nicole Mazzuca (Sep 12 2018 at 15:17, on Zulip):

@avadacatavra

Nicole Mazzuca (Sep 12 2018 at 15:17, on Zulip):

https://github.com/rust-lang/rust/pull/53783

Nicole Mazzuca (Sep 12 2018 at 15:27, on Zulip):

I definitely misread as tuesday and woke up way too early lol. gj me

nikomatsakis (Sep 12 2018 at 16:33, on Zulip):

I'm getting together information for the meeting on Thursday. Post anything you think is relevant/progress/etc here (or PM me idc)

I've been meaning to go through the issues and try to do some summarizing, but I didn't have time

nikomatsakis (Sep 12 2018 at 16:34, on Zulip):

we've not done a great job of following through on that part of the plan @avadacatavra :P

nikomatsakis (Sep 12 2018 at 16:34, on Zulip):

but maybe that's a good work item over next couple of weeks, I think it's too much work for me to take on anyway

Nicole Mazzuca (Sep 12 2018 at 16:51, on Zulip):

Just... ignore me. My brain is terrible at time.

avadacatavra (Sep 12 2018 at 21:19, on Zulip):

@nikomatsakis i'm summarizing the best i can and i think that will probs be a topic of discussion (aka...sooo we have this stuff who wants to write it up)

avadacatavra (Sep 13 2018 at 15:14, on Zulip):

Hello! Thanks for joining us (both synchronously and asynchronously)--as a reminder, meetings are intended to gauge progress and figure out what to work on/how things are going, not Mariana trench deep discussions :)

Agenda:

Alan Jeffrey (Sep 13 2018 at 15:15, on Zulip):

Hi!

avadacatavra (Sep 13 2018 at 15:15, on Zulip):

Hi everyone! I've just posted the agenda (I'll try to post it earlier next time so you can look over it if desired). The first thing I'd like to talk about is what you think of the discussion format--is it working? Are we having productive discussions? Are there suggestions for improvement?

Alan Jeffrey (Sep 13 2018 at 15:17, on Zulip):

From a slightly semi-detached view, the discussions have been good, I'm not sure what the process is for turning them into artifacts is though.

avadacatavra (Sep 13 2018 at 15:19, on Zulip):

@Alan Jeffrey the "plan" (for some definition of the word) is to have writeups in an md book once we have a consensus/thorough discussion to be written up

avadacatavra (Sep 13 2018 at 15:19, on Zulip):

who does the work/how we track it is tbd afaik

avadacatavra (Sep 13 2018 at 15:19, on Zulip):

@nikomatsakis @RalfJ you around?

Nicole Mazzuca (Sep 13 2018 at 15:21, on Zulip):

I'm not sure what you mean by "we might have a consensus on unions, tuples, function pointers". I don't know what we have a consensus on?

nikomatsakis (Sep 13 2018 at 15:22, on Zulip):

I'm here, sorry :)

nikomatsakis (Sep 13 2018 at 15:22, on Zulip):

/me reads backscroll quickly

avadacatavra (Sep 13 2018 at 15:22, on Zulip):

@Nicole Mazzuca it seems like in https://github.com/rust-rfcs/unsafe-code-guidelines/issues/12, we can basically agree on "For the record, there's a compromise solution: special casing structs and tuples with homogeneous contents (and making them equivalent to arrays) without guaranteeing much about the layout of either tuples or structs that have heterogeneous contents."

Alan Jeffrey (Sep 13 2018 at 15:23, on Zulip):

@Nicole Mazzuca on the memory layout?

nikomatsakis (Sep 13 2018 at 15:23, on Zulip):

so, I agree with you agenda :) I think my take is similar to @Alan Jeffrey — the basic idea is working ok, but I think we need to get started on trying to produce concrete summaries

nikomatsakis (Sep 13 2018 at 15:23, on Zulip):

(in retrospect I think I would like to have designated people doing this earlier and more actively)

nikomatsakis (Sep 13 2018 at 15:24, on Zulip):

I think in some cases there is a bit of license permitted here too, and that's ok

nikomatsakis (Sep 13 2018 at 15:24, on Zulip):

e.g., for tuples...

Alan Jeffrey (Sep 13 2018 at 15:24, on Zulip):

@nikomatsakis would we have one PR per issue?

avadacatavra (Sep 13 2018 at 15:24, on Zulip):

@Nicole Mazzuca it seems like in https://github.com/rust-rfcs/unsafe-code-guidelines/issues/12, we can basically agree

which might not be the case, but seems like that's likely a good starting point there

Nicole Mazzuca (Sep 13 2018 at 15:25, on Zulip):

I'm going to need to read a bit. What about function pointers, tho?

nikomatsakis (Sep 13 2018 at 15:25, on Zulip):

er, @avadacatavra, I hadn't seen your edit but you said part of what I wanted to say :)

nikomatsakis (Sep 13 2018 at 15:25, on Zulip):

which is that if there is an idea that seems to have tentative consensus, I Think trying to write it up (with a caveat, perhaps) is a good way to make that consensus more precise

nikomatsakis (Sep 13 2018 at 15:25, on Zulip):

@nikomatsakis would we have one PR per issue?

a good question :) I think .. maybe yes?

avadacatavra (Sep 13 2018 at 15:26, on Zulip):

@nikomatsakis given a starting point, we can iterate with fork-pr-review on the md book

nikomatsakis (Sep 13 2018 at 15:26, on Zulip):

that was the goal of the issues was to try and break down into reasonable, bite-sized chunks

nikomatsakis (Sep 13 2018 at 15:26, on Zulip):

I think if one PR doesn't fit

nikomatsakis (Sep 13 2018 at 15:26, on Zulip):

then maybe we can need to split the issue further up

nikomatsakis (Sep 13 2018 at 15:26, on Zulip):

I guess I can imagine PRs that say "Closes #123"

nikomatsakis (Sep 13 2018 at 15:26, on Zulip):

(and a corresponding comment in the issue linking to the PR, to make it more visible)

nikomatsakis (Sep 13 2018 at 15:26, on Zulip):

as a way to kind of "call to question"

nikomatsakis (Sep 13 2018 at 15:27, on Zulip):

I personally would say:

Nicole Mazzuca (Sep 13 2018 at 15:27, on Zulip):

okay, what are the actual guarantees we're asking about?

nikomatsakis (Sep 13 2018 at 15:27, on Zulip):

if there are remaining things that need further discussion

nikomatsakis (Sep 13 2018 at 15:27, on Zulip):

we should (upon merging the PR), open new issues for those

nikomatsakis (Sep 13 2018 at 15:27, on Zulip):

okay, what are the actual guarantees we're asking about?

the current area of discussion is memory layout specifically, as well as things like ABI compatibility

avadacatavra (Sep 13 2018 at 15:28, on Zulip):

here were my thoughts on unions:
- Conclusion: we should “describe the controversy,” not make specific rules
- https://github.com/rust-rfcs/unsafe-code-guidelines/issues/13#issuecomment-420074167
- repr(C) unions guaranteed to be layout and ABI compatible with C unions
- default layout not fixed, revisit after validity invariants
- are there any use cases for layout optimizations with unions

nikomatsakis (Sep 13 2018 at 15:28, on Zulip):

we are explicitly not discussing the "invariants"

Nicole Mazzuca (Sep 13 2018 at 15:28, on Zulip):

okay, and the current consensus is no guarantees, beyond those already made?

Alan Jeffrey (Sep 13 2018 at 15:28, on Zulip):

@Nicole Mazzuca I think the consensus was that the memory layout for fn pointers is just the same as for non-null pointers. I could be wrong though.

Nicole Mazzuca (Sep 13 2018 at 15:28, on Zulip):

@Alan Jeffrey that's incorrect on some platforms tho

Nicole Mazzuca (Sep 13 2018 at 15:29, on Zulip):

(although it is common)

nikomatsakis (Sep 13 2018 at 15:29, on Zulip):

I think what I would like is to try and enumerate the platforms where it is/isn't true

avadacatavra (Sep 13 2018 at 15:29, on Zulip):

/me couldn't actually tell what the consensus was, but it seemed like people were mostly agreeing on function pointers

Nicole Mazzuca (Sep 13 2018 at 15:29, on Zulip):

It seems odd to define that in the "standard", when you could just have it as a common platform-specific thing

avadacatavra (Sep 13 2018 at 15:29, on Zulip):

@nikomatsakis i think that's the best way to approach it

avadacatavra (Sep 13 2018 at 15:29, on Zulip):

summarize the commonalities and point out the differences

nikomatsakis (Sep 13 2018 at 15:30, on Zulip):

I know this question comes up

Alan Jeffrey (Sep 13 2018 at 15:30, on Zulip):

@Nicole Mazzuca I think we might be getting into the weeds here, perhaps we should discuss this on the GH issue?

nikomatsakis (Sep 13 2018 at 15:30, on Zulip):

so I think it's important to offer people practical advice

nikomatsakis (Sep 13 2018 at 15:30, on Zulip):

but yes, this is precisely the sort of thing that a write-up can help make more clear I think :)

avadacatavra (Sep 13 2018 at 15:30, on Zulip):

maybe @Nicole Mazzuca would be interested in writing that up? ;)

nikomatsakis (Sep 13 2018 at 15:30, on Zulip):

I think for purposes of this meeting we probably ought to delegate out who will do writing

Nicole Mazzuca (Sep 13 2018 at 15:30, on Zulip):

sure, although it'll be a while :P

Nicole Mazzuca (Sep 13 2018 at 15:31, on Zulip):

(I have end of internship this week, into new York next week, into cppcon the following week)

nikomatsakis (Sep 13 2018 at 15:31, on Zulip):

This was the list that @avadacatavra made up:

but I think we probably can do a bit more -- at least starting points -- for other issues? I originally hoped that we could kind of produce an "in progress" summary to help focus the discussion. Does that maybe make sense?

avadacatavra (Sep 13 2018 at 15:31, on Zulip):

i'm happy to write some up, but i don't necessarily understand all the topics (which is sometimes helpful, but ends up with me pinging all of you a ton) -- i think it would be a good idea to have some tags for issues that are ready for writeup and ones that are assigned

nikomatsakis (Sep 13 2018 at 15:32, on Zulip):

I guess let's start with those 3

nikomatsakis (Sep 13 2018 at 15:32, on Zulip):

and worry about the rest later

nikomatsakis (Sep 13 2018 at 15:32, on Zulip):

yes, tags makes sense

avadacatavra (Sep 13 2018 at 15:32, on Zulip):

are there any others that we think might be ready for writeups?

nikomatsakis (Sep 13 2018 at 15:32, on Zulip):

we can probably try to issue a general call for help

Nicole Mazzuca (Sep 13 2018 at 15:32, on Zulip):

I can take function pointers if you're okay with waiting 2 1/2 weeks

nikomatsakis (Sep 13 2018 at 15:32, on Zulip):

I can take function pointers if you're okay with waiting 2 1/2 weeks

that is probably ok

avadacatavra (Sep 13 2018 at 15:32, on Zulip):

i was somewhat surprised to see that the integers/floating point thread had the most comments

nikomatsakis (Sep 13 2018 at 15:33, on Zulip):

heh

Alan Jeffrey (Sep 13 2018 at 15:33, on Zulip):

Not sure how we're getting consensus on tuples w/out consensus on structs.

nikomatsakis (Sep 13 2018 at 15:33, on Zulip):

I suspect "packed and align" is maybe ready?

nikomatsakis (Sep 13 2018 at 15:33, on Zulip):

well, I think tuples were sort of going to be defined somewhat in terms of structs

nikomatsakis (Sep 13 2018 at 15:33, on Zulip):

so it sort of sidesteps the problem :P

Alan Jeffrey (Sep 13 2018 at 15:33, on Zulip):

OK, we have consensus to punt :)

nikomatsakis (Sep 13 2018 at 15:33, on Zulip):

that said, how much controversy was there about structs? I guess some

nikomatsakis (Sep 13 2018 at 15:34, on Zulip):

I think it would be very helpful to have somebody look at structs and try to tease out what the core question is

nikomatsakis (Sep 13 2018 at 15:34, on Zulip):

if memory serves, Josh Tripplet had a kind of different perspective about layout (e.g., that it should be more defined)

avadacatavra (Sep 13 2018 at 15:34, on Zulip):

@nikomatsakis yep--are they here?

nikomatsakis (Sep 13 2018 at 15:35, on Zulip):

they're not on Zulip to my knowledge

nikomatsakis (Sep 13 2018 at 15:35, on Zulip):

but I think this wouldn't be the time/place to discuss the technical details anyway

avadacatavra (Sep 13 2018 at 15:35, on Zulip):

/me can ping on gh to see if they're interested in the writeup

nikomatsakis (Sep 13 2018 at 15:36, on Zulip):

so, I think I'd be game to try and write-up something on tuples + structs

nikomatsakis (Sep 13 2018 at 15:36, on Zulip):

I can touch base with Josh perhaps

nikomatsakis (Sep 13 2018 at 15:36, on Zulip):

they do seem tightly inter-related

nikomatsakis (Sep 13 2018 at 15:37, on Zulip):

in the case of structs, I think it wouldn't be a "final write-up", but more trying to tease out the pros/cons and try to organize the discussion

avadacatavra (Sep 13 2018 at 15:37, on Zulip):

Ok, so writeups wanted for:
-function pointers: @Nicole Mazzuca
- structs: @nikomatsakis
- tuples: @nikomatsakis
-enums
-unions
-packed/align
-integers/floating points
-references and pointers: @avadacatavra

avadacatavra (Sep 13 2018 at 15:38, on Zulip):

i guess unions and enums are also very related

nikomatsakis (Sep 13 2018 at 15:38, on Zulip):

well

nikomatsakis (Sep 13 2018 at 15:38, on Zulip):

maybe a bit less so?

Alan Jeffrey (Sep 13 2018 at 15:38, on Zulip):

Also, we should have a PR to update the TOC at https://github.com/rust-rfcs/unsafe-code-guidelines/blob/master/reference/src/SUMMARY.md

nikomatsakis (Sep 13 2018 at 15:39, on Zulip):

yes, true

nikomatsakis (Sep 13 2018 at 15:39, on Zulip):

I think union + enums, in practice, are quite different, unless we wind up adding some sort of mechanism that guarantees a union is initialized to some variant.

avadacatavra (Sep 13 2018 at 15:40, on Zulip):

are there any in the list that we think need more discussion on gh before a writeup attempt

nikomatsakis (Sep 13 2018 at 15:40, on Zulip):

which kind of gets into the "validity invariant" question

nikomatsakis (Sep 13 2018 at 15:40, on Zulip):

also, importantly, we don't currently do any layout optimizations there

nikomatsakis (Sep 13 2018 at 15:40, on Zulip):

whereas we do with enums

Alan Jeffrey (Sep 13 2018 at 15:40, on Zulip):

We'd need a skeleton "memory layout" chapter, which the other PRs would flesh out.

avadacatavra (Sep 13 2018 at 15:40, on Zulip):

@nikomatsakis then they are not related for our purposes today :p:

avadacatavra (Sep 13 2018 at 15:40, on Zulip):

/me sighs

nikomatsakis (Sep 13 2018 at 15:40, on Zulip):

there is some circularity around the validity invariant, but the idea was: we should start by documenting what we currently do, so that it can be an input into the invariant question (the invariant must justify at least what we do now)

nikomatsakis (Sep 13 2018 at 15:41, on Zulip):

so somebody should make a skeleton chapter of summary.md with appropriate subchapters, agreed

nikomatsakis (Sep 13 2018 at 15:41, on Zulip):

@Alan Jeffrey ? :)

nikomatsakis (Sep 13 2018 at 15:41, on Zulip):

(no good deed goes unpunished)

nikomatsakis (Sep 13 2018 at 15:41, on Zulip):

ideally quickly, and we can just merge it

Alan Jeffrey (Sep 13 2018 at 15:41, on Zulip):

@nikomatsakis by "what we do now" you mean (e.g.) optimizations?

Alan Jeffrey (Sep 13 2018 at 15:42, on Zulip):

I can do the skeleton.

nikomatsakis (Sep 13 2018 at 15:42, on Zulip):

yes, though also more generally. But for the purposes of the validity invariant optimizations are most imp't

nikomatsakis (Sep 13 2018 at 15:42, on Zulip):

@avadacatavra you keep editing comments when I don't expect it :) sorry, missed that you had expanded your writeup

Alan Jeffrey (Sep 13 2018 at 15:42, on Zulip):

What's our process for deciding when to merge a PR?

avadacatavra (Sep 13 2018 at 15:43, on Zulip):

@nikomatsakis sorrryyyyyyy my fingers aren't fast enough

nikomatsakis (Sep 13 2018 at 15:43, on Zulip):

not yet super formalized...I've been hoping we'll be able to achieve general consensus. If something is controversial, then we document the pro/con

Alan Jeffrey (Sep 13 2018 at 15:44, on Zulip):

@nikomatsakis general consensus is achieved on the PR discussion, or on the issue discussion?

nikomatsakis (Sep 13 2018 at 15:44, on Zulip):

both?

avadacatavra (Sep 13 2018 at 15:44, on Zulip):

Documenting pro/con/tradeoffs counts as consensus IMO. We don't need to agree on what the answer is, but we should agree on what the questions are

nikomatsakis (Sep 13 2018 at 15:44, on Zulip):

I mean the PR is sort of documenting the issue

nikomatsakis (Sep 13 2018 at 15:44, on Zulip):

I guess "the PR thread" then... it's hard to say what discussion on an issue means, since there is no specific text.

Alan Jeffrey (Sep 13 2018 at 15:45, on Zulip):

s/documenting/resolving/ ?

nikomatsakis (Sep 13 2018 at 15:45, on Zulip):

no

avadacatavra (Sep 13 2018 at 15:45, on Zulip):

@Alan Jeffrey i see it as using the consensus/discussion from the issue to create the writeup PR, then use the writeup for further refinement

nikomatsakis (Sep 13 2018 at 15:45, on Zulip):

right, I meant that the write-up should reflect what was said. It doesn't have to show the path that led there, but it tries to take general comments and make them more precise.

nikomatsakis (Sep 13 2018 at 15:46, on Zulip):

people can then read and say if it seems to reflect what they had in mind, or if they disagree (and why)

Alan Jeffrey (Sep 13 2018 at 15:46, on Zulip):

@nikomatsakis so the idea is that each issue might have multiple PRs?

nikomatsakis (Sep 13 2018 at 15:46, on Zulip):

I expected one PR

nikomatsakis (Sep 13 2018 at 15:46, on Zulip):

if nobody agrees on anything in it, we close it and try again

Alan Jeffrey (Sep 13 2018 at 15:47, on Zulip):

@nikomatsakis in which case why the "no" to "resolving"?

avadacatavra (Sep 13 2018 at 15:47, on Zulip):

@Alan Jeffrey @nikomatsakis i think that this process might need more discussion/documentation after we try it out

nikomatsakis (Sep 13 2018 at 15:47, on Zulip):

otherwise, it could be that we want to merge and open follow-up issues

nikomatsakis (Sep 13 2018 at 15:47, on Zulip):

I also agree :)

avadacatavra (Sep 13 2018 at 15:47, on Zulip):

because we're out of time and i'd like to bring up a few things quickly

nikomatsakis (Sep 13 2018 at 15:47, on Zulip):

go for it

nikomatsakis (Sep 13 2018 at 15:48, on Zulip):

(ps, I think that we should do the tags, like you said, and post a comment somewhere asking for follow-up)

nikomatsakis (Sep 13 2018 at 15:48, on Zulip):

if others want to take a stab

nikomatsakis (Sep 13 2018 at 15:48, on Zulip):

but maybe we wait until we've done it once or twice

Alan Jeffrey (Sep 13 2018 at 15:48, on Zulip):

OK, we'll see how the "add a memory layout chapter" PR goes, since that's probably quite uncontroversial.

nikomatsakis (Sep 13 2018 at 15:48, on Zulip):

so we have a model

avadacatavra (Sep 13 2018 at 15:48, on Zulip):

1. when we encounter a topic that is related to the active discussion but orthogonal, how should we record it for revisiting? (doesn't need to be answered right now, but i'd like to think about it)

avadacatavra (Sep 13 2018 at 15:49, on Zulip):

2. it looks like the plan is for some people to try writeups! tonight i'll do some organization on the repo when i summarize the meeting. i'm planning on creating tags and proposing a pr process (and next week trying it out with one of the topics).

nikomatsakis (Sep 13 2018 at 15:50, on Zulip):

1. when we encounter a topic that is related to the active discussion but orthogonal, how should we record it for revisiting? (doesn't need to be answered right now, but i'd like to think about it)

I've been opening issues tagged with "proposed discussion topic"

avadacatavra (Sep 13 2018 at 15:51, on Zulip):

overall, i think that the wg structure is working--needs to have some wrinkles ironed out, but the discussions look great and if we can be a bit more on top of writeups we'll be even better

nikomatsakis (Sep 13 2018 at 15:51, on Zulip):

2. it looks like the plan is for some people to try writeups! tonight i'll do some organization on the repo when i summarize the meeting. i'm planning on creating tags and proposing a pr process (and next week trying it out with one of the topics).

sounds good! I agree with you that we'll want to iterate. I don't think we've really tried to do something quite like this before...

Alan Jeffrey (Sep 13 2018 at 15:51, on Zulip):

Oh, and a late and annoying agenda item, licensing! https://github.com/rust-rfcs/unsafe-code-guidelines/issues/20

nikomatsakis (Sep 13 2018 at 15:51, on Zulip):

oh, yeah, annoying.

nikomatsakis (Sep 13 2018 at 15:51, on Zulip):

we should do whatever the Rust reference does I guess

nikomatsakis (Sep 13 2018 at 15:51, on Zulip):

https://github.com/rust-lang-nursery/reference

nikomatsakis (Sep 13 2018 at 15:52, on Zulip):

seems like LICENSE-MIT and LICENSE-APACHE.

Alan Jeffrey (Sep 13 2018 at 15:52, on Zulip):

Er, those are code licenses not doc licenses.

avadacatavra (Sep 13 2018 at 15:52, on Zulip):

1. when we encounter a topic that is related to the active discussion but orthogonal, how should we record it for revisiting? (doesn't need to be answered right now, but i'd like to think about it)

I've been opening issues tagged with "proposed discussion topic"

i'm thinking more things that aren't necessarily full discussion topics. particularly things in the layout discussions that we might also want to discuss with ffi stuff. although i suppose that could just take the form of a comment on an FFI proposed topic issue

nikomatsakis (Sep 13 2018 at 15:52, on Zulip):

/me shrugs

Alan Jeffrey (Sep 13 2018 at 15:52, on Zulip):

I was expecting a CC license.

avadacatavra (Sep 13 2018 at 15:52, on Zulip):

and @Alan Jeffrey volunteers to take care of licensing!

nikomatsakis (Sep 13 2018 at 15:52, on Zulip):

and/or whatever the rust book does

Nicole Mazzuca (Sep 13 2018 at 15:52, on Zulip):

We should definitely use something like CC-BY

Alan Jeffrey (Sep 13 2018 at 15:53, on Zulip):

I appear to be volunteering for things :/

Nicole Mazzuca (Sep 13 2018 at 15:53, on Zulip):

and also maybe figure out if we can fix the rust reference?

avadacatavra (Sep 13 2018 at 15:53, on Zulip):

I have to go--I'll send out a summary later today. Good work comrades.

Nicole Mazzuca (Sep 13 2018 at 15:53, on Zulip):

why did people use MIT/Apache for documentation -.-

Alan Jeffrey (Sep 13 2018 at 15:53, on Zulip):

Bye everyone!

nikomatsakis (Sep 13 2018 at 15:54, on Zulip):

I will check on licensing. I don't have a strong opinion (yet) =)

est31 (Sep 13 2018 at 16:07, on Zulip):

Thanks for taking care of the licensing!

alercah (Sep 13 2018 at 19:49, on Zulip):

As a practical matter, even if we could put all documentation under a more appropriate license, it'd cause no end of headache if we want to move docs between rustdoc and other documentation.

alercah (Sep 13 2018 at 19:49, on Zulip):

"You need to put attribution in the docs for this function because it came from the book."

Last update: Nov 19 2019 at 18:00UTC