New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should we rename nurseries? #504

Open
njsmith opened this Issue Apr 18, 2018 · 51 comments

Comments

Projects
None yet
@njsmith
Member

njsmith commented Apr 18, 2018

OK, let's do this.

Question: Should we rename "nurseries"? It's something that keeps coming up, and while it would be somewhat painful to change now, it'll be pretty much impossible within the next 6 months... so I guess now is the time to have a discussion, and if we decide not to change it then this can at least become the canonical issue that we link people to when they ask about it.

The most common version of this complaint is something like: "ugh, nursery is so cutesy. What about TaskGroup, or WaitGroup, or TaskScope, or something like that?" I don't find this version of the complaint compelling, so let me start by explaining why that is.

Names like TaskGroup, or TaskScope are excellent names for ordinary classes, the kinds of name we invent every day. For that kind of class, you want something that's descriptive, because you have a lot of them and people don't spend much time with any given one. And of course you want to follow the conventions, so the camelcase itself is informative: even if you aren't familiar with the particular class in question, you at least can tell at a glance that it is a class.

Nurseries, though, are a different kind of thing entirely. They're a new fundamental concept: you have to learn them up front, like you have to learn about for loops, and functions, and the difference between an object attribute and a local variable. Once you've used them for a few days, they recede into the background as part of your basic vocabulary. And they're just different from the concepts most people already know, so trying to give them a familiar descriptive name is actually misleading: you have to look them up and learn them. So, I want a name that feels like a primitive, like "for" or "function" or "variable" – something short and lowercase. And if anything, something that's a bit opaque and unfamiliar is probably better, because it signals "hey, new concept here". You can't have a lot of concepts like that, but nurseries are carrying an entire programming paradigm on their shoulders, so I think 1 new word is within our budget.

And regarding it being "cutesy": This doesn't really bother me, given that (1) this is a domain where "reaping orphan zombie children" is already considered totally ordinary technical language, and (2) after you use nurseries for a few minutes the name stops feeling cutesy, just like you stopped noticing that "trees" have nothing to do with botany, "functions" often don't function (little debugging joke there), "threads" have nothing to do with textiles, etc. So like... ok, it's a bit cutesy but whatever, people will get over it. And being cutesy actually has some upside: the whole joke about "a nursery is where child tasks live" probably does help it stick in people's minds. OTOH, I'm not like super attached to having a cutesy name either; I think it's mostly a neutral attribute.

So that's why I'm convinced that "nursery" is better than TaskGroup or similar.

But...... when talking to @graydon about this today, I did have some doubts about "nursery", for two reasons. The first is, he pointed out that "nursery" is also used as jargon for generational garbage collectors (to refer to the youngest generation, which often gets special handling). So a language implementer might ask "is this task in that nursery?", and "is this Task in the nursery?" and those are two completely unrelated questions. Fortunately it's mostly implementers who encounter the GC version of nursery, but still... this is a legitimate collision.

And the other is, I realized that the name is actually a bit less apropos since #375 landed and we tweaked the nursery semantics. Originally, I really wanted to emphasize the idea of "supervision", because we had the whole "parenting is a full time job" rule where the parent task had to park itself at the end of the nursery block or exceptions wouldn't propagate and stuff. Now the supervision part has dissolved into becoming an implicit part of the runtime, and doesn't really exist as a concept at all anymore – it's just, like, exceptions propagate themselves, what is there to talk about. The code inside the nursery block is just a slightly-special child. So that part of the metaphor has become a bit weird.

So here's another idea: maybe we could use a name that emphasizes that this is a place where your call stack splits/branches/words like that. Like, async with trio.open_split(), or open_branchpoint, or something like that? With the metaphor being that first you make a note "here's a point in my call stack where child tasks might split off", and then calling start_soon actually attaches a new branch there. I'm imagining like a hinge or a hook or something.

Anyway, that's just one idea – if y'all have other ideas I'd be interested to hear them, and ditto any thoughts on how the "nursery" name worked for you as either a newcomer to Trio or as you've become more experienced.

@pquentin

This comment has been minimized.

Member

pquentin commented Apr 18, 2018

The nursery name works fine for me. It's well explained in the tutorial, and I liked the cuteness! 😄

split and branchpoint work too, but how would you call the resulting object? I think nursery.start_soon(fn) works slightly better than split.start_soon(fn)? Or is it because I'm used to nurseries?

Anyway, I'm not personally opposed to a change, as it would be easy to adapt to a new name.

@jab

This comment has been minimized.

Contributor

jab commented Apr 18, 2018

What do you think of childminder?

To me it has a lot of the same helpful properties as nursery:

...but isn't (to my knowledge) overloaded with another programming meaning, and also directly refers to the existing-programming-concept "child" in the name, and so maybe avoids some of the cutesiness that some people have found distracting?

That said, I'd be fine with keeping nursery and fine with a change too. </$.02!>

@apexo

This comment has been minimized.

apexo commented Apr 18, 2018

While I kind of like nursery, just for the heck of it, here's my random proposal:

If parenting isn't a full-time job anymore … maybe it's actually fun? Like a party?

So let's trio.start_party() and invite tasks to party together w/ party.invite(task) ?

@jab

This comment has been minimized.

Contributor

jab commented Apr 18, 2018

Not sure about open_split. The word "split" is overloaded, and so doesn't necessarily invoke any obviously-intended associations immediately. Further overloading an overloaded term can add to cognitive load. It also doesn't signal "learn this important foreign concept!" to me as much.

The term "branchpoint" is better than "split" on both counts. But both "split" and "branchpoint" give up direct association with the concept of "children".

@Fuyukai

This comment has been minimized.

Contributor

Fuyukai commented Apr 18, 2018

I'm perfectly fine with the nursery name as is.

@smurfix

This comment has been minimized.

Contributor

smurfix commented Apr 18, 2018

@apexo You still can't leave the party. You (as the "host", i.e. the nursery's initial task) can just decide to do your own thing while the party is ongoing, just like every other party guest.

My preferred name, should we decide to switch the name, would be the rather boring "task manager", or taskmgr.

That being said, I'm also OK with keeping the name. "Branchpoint" … well, maybe. @jab it does for me.

@smurfix

This comment has been minimized.

Contributor

smurfix commented Apr 18, 2018

Personally: when I came across this nursery thing, I thought, OK, new name, new concept I actually need to think about instead of assuming that I already know what it's about. Which is exactly what we need to get across.

I didn't know about nurseries WRT garbage collection. However our nursery is very obviously not about GC, so I don't think that in practice there's much confusion. I'd be more wary about a name like branch since in if FOO then BAR else BAZ, BAR and BAZ are different branches of execution – a concept which (a) many people have already come across and (b) is in roughly the same realm, so more danger of confusion.

@touilleMan

This comment has been minimized.

Member

touilleMan commented Apr 18, 2018

I like nursery

And the other is, I realized that the name is actually a bit less apropos since #375 landed and we tweaked the nursery semantics.

I think the name is still valid even after #375.
Before this change we could see the main coroutine which open the nursery as the nurse which will take care of the child-coroutines.
After the change the main coroutine is just a lazy parent who drops it children-coroutines to the nursery and go have a beer do it own work.

@graydon

This comment has been minimized.

graydon commented Apr 18, 2018

Attempting to make a positive contribution (browsing thesaurus looking for new names is a favourite pass-time anyways) I might suggest:

  • supervision-related:

    • custodian
    • steward
    • caretaker
    • porter
    • attendant
    • concierge
  • childcare-related:

    • creche
    • cradle
  • tree/splitting-related:

    • outgrowth
    • bifurcation
    • partition
    • branch
    • sprout <-- personal fave
    • offshoot
    • bough
    • limb
  • organization-division related:

    • subsidiary
    • office
    • branch, also
    • division
    • department
    • chapter <-- has a nice "part of a story" secondary resonance
@njsmith

This comment has been minimized.

Member

njsmith commented Apr 21, 2018

My issue with options like sprout/bough/limb is that those sound like they refer to the children, while we need a name for the point where the children are attached.

@smurfix has a good point about "branch" already being overloaded, and as a control flow thing, so that's definitely confusing.

Of the nursery alternatives... maybe "splitpoint" is the best I can come up with so far? (As in, "this is a point where control can split".) It has some resonance with "checkpoint", which is our other bit of funny terminology. Something like:

async with trio.open_splitpoint() as splitpoint:
    splitpoint.start_soon(...)

I actually kind of like how this de-emphasizes the concept of "children", since trio doesn't really reify tasks/threads/whatever-you-wanna-call-them. There are no task ids or task objects or anything (unless you go digging into trio.hazmat). OTOH we still need to refer to the different concurrent functions in conversation -- I suppose we could call them "splits", like: "While the first split is doing name resolution, the other splits are waiting...". Maybe that's too weird?

("sproutpoint" is also an option, but that might be too silly even for me :-).)

I suppose there's also

async with trio.open_family() as family:
    family.start_soon(...)

but I feel like "family" is too commonly used as a kind of generic word for "category". "This family of concurrency frameworks uses families...", ick.

@dhirschfeld

This comment has been minimized.

dhirschfeld commented Apr 21, 2018

kindergarten

@dhirschfeld returns to lurking

@dhirschfeld

This comment has been minimized.

dhirschfeld commented Apr 21, 2018

Seriously though, I thought nurseries was a little cutsie at first, but it didn't really bother me [1]_.
Now, I actually think it's a very good name and better than any alternative I've seen / thought of.

.. [1]: Full Disclosure: I use a data processing library called "pandas" on a daily basis and that also doesn't bother me! 😜

@smurfix

This comment has been minimized.

Contributor

smurfix commented Apr 21, 2018

My problem with splitpoint or similar pointy names is that a point, conceptually, is just there. Like in geometry, it doesn't do anything.

My personal favorite still is a task manager. Maybe with trio.manage_subtasks() as mgr: await mgr.start(…).

@njsmith

This comment has been minimized.

Member

njsmith commented Apr 22, 2018

My problem with splitpoint or similar pointy names is that a point, conceptually, is just there. Like in geometry, it doesn't do anything.

That would be the point though :-). (No pun intended.) When you type open_splitpoint, you'd be marking a place in the call stack where you could potentially hang off other children/sprouts/whatever:

f1 -> f2 -> (splitpoint) -> f3

This doesn't actually do anything. Then later, when you call start_soon, that's when something actually happens:

f1 -> f2 -> (splitpoint) -> f3
                       |
                       +--> f4
@smurfix

This comment has been minimized.

Contributor

smurfix commented Apr 22, 2018

Well, in geometry you (mostly) don't just arbitrarily draw a point – the point exists as a consequence of something else (like two lines intersecting). Afterwards, other things exist as a consequence of the point being there (like a line being defined by two points). In both cases the "active" parts are the non-points.

shrug maybe I'm overthinking this … on reflection I'm like -0.1 on splitpoints-or-whatever, -1 on branchwhatever, and +0.1 on keeping nursery.

@sorcio

This comment has been minimized.

Contributor

sorcio commented Apr 24, 2018

To me, splits/branches/sprouts suggest the point where things go different ways but not so much that they eventually merge. When thinking in spacial terms they might be the same thing, especially if you're used to visualize tasks in a tree, but it doesn't translate well to the idea of concurrency (multiple things running at the same time over parallel lines).

Maybe, given our peculiar semantics, it makes more sense to call the nursery a merge/join/muster point and use splitting/branching/forking/sprouting to refer to what now is the nursery.start operation.

The idea of supervision is lost but, well, so it is in the paradigm of calling/returning functions (either sync or async) which in some ways is a close relative to this. Instead of waiting for one function call to return or raise, you're waiting for many concurrent ones. What's so special about that? 😉

@graydon

This comment has been minimized.

graydon commented Apr 24, 2018

splits/branches/sprouts suggest the point where things go different ways but not so much that they eventually merge. ... it doesn't translate well to the idea of concurrency (multiple things running at the same time over parallel lines).

This is why I highlighted above the term chapter as having both organizational-structure gloss and a part-of-a-sequential-book gloss: the more I think about this the more I think it might be a good (mixed) metaphor. In the org-chart-sense it's definitely part-of-a-hierarchy. But in the book sense it's a block-structuring element of a sequential story that introduces-and-concludes a bunch of specific scenes, and maybe lets a couple threads of the plot connect-up with those from earlier or later chapters.

It also includes (unlike all the options here -- including nursery!) the concept of conclusion, as you say. The term evokes both "beginning of chapter" and "end of chapter" -- things started and things wrapped-up -- in almost equal measure.

@theelous3

This comment has been minimized.

theelous3 commented Apr 25, 2018

I like my concurrency libraries like I like my concrete. Bland and functional. TaskManager

To use it in a sentence:

"The TaskManager manages its tasks."

Inessential weirdness and all that.

@jpfed

This comment has been minimized.

jpfed commented Apr 25, 2018

A common/boring name for a collection of jobs is a batch.

If you want a name that reflects some control-flow analogy...

Collections of threadlike things bound together at both ends are

  • bundles
  • fascicles (okay, that's weird, but maybe? They're hierarchical bundles of bundles of.., which is pretty cool)
  • sheaves (maybe confusing if someone knows the mathematical definition of sheaf, which I don't)

Places that things leave and then return to

  • nest (keep the cutesy!)
  • camp

Portmanteau silliness: daglet

@canadaduane

This comment has been minimized.

canadaduane commented Apr 26, 2018

chapter really works for me. It's short, concise, and builds on a well-known literary concept with an emphasis on beginning and ending, with stuff happening in between. It doesn't assume anything about the nature of the story--whether child labor or worker robots--and it makes sense to talk about passing a chapter around to functions, e.g. "Which chapter [of the overall book/app] am I in?".

@feluxe

This comment has been minimized.

feluxe commented Apr 26, 2018

This is fun! :)

Some more:

  • track
  • passage
  • stage
  • phase
  • portion
  • hive
@albertogomcas

This comment has been minimized.

Contributor

albertogomcas commented Apr 26, 2018

I have no issues with nursery, this is a python library and playfully named libraries are commonplace.

Anyway, nobody is shocked in this context about parents, children, (and infanticidal moves as killing children!), nursery is just a little blip that stops felling weird after you have seen it 12 times.

One analogy that has not been raised yet is the hub/spokes, but I am not fully convinced myself...

@oremanj

This comment has been minimized.

Contributor

oremanj commented Apr 26, 2018

I like the name "nursery". If we choose a new one, I'd hope that it share some of the properties of "nursery" that make me like it:

  • not in common usage elsewhere (as mentioned, maybe we can do even better than "nursery" in this regard, but I don't think the GC term overloading is a substantial issue)
  • short and easy to type (I think seven characters is substantially better even than the ten in "splitpoint")
  • doesn't invite ambiguous abbreviations (mgr could be a ThingManager for just about any value of Thing, and a large program might have a lot of those)
  • reads well in the trio pattern of open_thing() being a function that returns a context manager that scopes the lifetime of a new thing
  • not too cutesy (I think "party" might be going a bit too far in that direction)
  • suits the context in which it's used reasonably well - it doesn't have to be obvious without an explanation, but the explanation should make sense

I'm not sure it makes sense to switch for a name that's only infinitesimally better than "nursery", since there are switching costs. I don't feel like any of the names proposed so far are substantially better than "nursery", though I do like several of them.

Some random further thoughts:

  • "custodian" is in common usage in Scheme, I think, and refers to a sort of scope for all resources - when a custodian is shut down, all files created in its scope are closed, threads are killed, etc. IMO it's similar enough to the nursery idea to make the differences a potential point of confusion for Schemers.
  • The unit-of-an-organization meaning of "chapter" doesn't jump out at me nearly as much as the book-subdivision one does, so it feels like a mixed metaphor - the instinctive objection is "my program isn't made of chapters, that's for books! programs are made of (modules|packages|functions|...)". Nursery doesn't have this problem because nobody talks about dividing things into nurseries, in any domain.
  • I quite like "hive" and "nest", and they're very short and non-overloaded (as long as no one tries to write a trio library for controlling a certain trendy home thermostat...), but I think they score worse on "likely preexisting associations link to correct concepts" than nursery does.
@zmitchell

This comment has been minimized.

Member

zmitchell commented Apr 27, 2018

I don't really mind the nursery naming. If we do change it I wonder about a transportation analogy. Buses/trains/airlines tend to have hubs or central dispatches that buses/trains/planes leave from and eventually come back to. Something along those lines has the connotations of management, coordination, or authority.

@Mec-iS

This comment has been minimized.

Mec-iS commented Apr 28, 2018

Just an aesthetical subjective opinion from an amateur philologist, I would call them 'beacons' or 'cocoons' if you want to keep a biological-like sounding. If you want a more techie-industrial-crafting narration, maybe 'foundries' or 'workshops' it is more appropriate. A potentially helpful note, the whole library's concept and the arrows-like diagrams in your post made me think much about 3D-printing.

Thanks for your work.

@agadabanka

This comment has been minimized.

agadabanka commented Apr 29, 2018

The name nursery feels very dynamic and apt. It represents progress (growth) and chaos that is being constantly monitored on behalf of the parent process, which was responsible for the creation or the split. The metaphor is great - parent can just let the nursery manage the process while they take care of their work, with the how's of nursery being a black-box. Also, the name nursery stands out in the excellent blog post as something familiar w.r.t concurrency in everyday life, yet something I would want to read more about in the context of Trio. Irrespective of the simplifications in the implementations, the core idea behind a nursery resonates almost immediately for a first time reader and makes it approachable to take their first steps.

@linkmonitor

This comment has been minimized.

linkmonitor commented Apr 29, 2018

A coworker of mine suggested spool.

One could make the obvious connections with threads/threading and, if we stretch it, (sp)awn p(ool).

@maffoo

This comment has been minimized.

maffoo commented May 4, 2018

One problem with the name "nursery" is it only conveys that this is a place where new tasks can be spawned. But the really important thing about a trio nursery as I understand it, and in particular the thing that distinguishes it from other libraries' APIs for launching concurrent tasks, is that it also bounds the execution of all the tasks launched within it. That is, the nursery doesn't exit until all its child tasks have exited. The "nursery" metaphor doesn't convey this, in fact quite the opposite: most things born in nurseries grow up and leave the nursery to live their adult lives (especially if the nursery is working well and not prematurely killing it's charges :-) ).

I would favor a name that covey's this "boundedness", that no task started by this object will outlive that object. But I don't really have a good suggestion. I like variants of "scope", but @njsmith already rejected "TaskScope". I also like "lifetime", but that doesn't have the whimsy of the current name.

@maffoo

This comment has been minimized.

maffoo commented May 4, 2018

Here's a maybe off topic question though. Does there need to be a nursery object at all? Since the boundary provided by a nursery is the same as the async with statement (which is a lexical scope that doesn't need a name) couldn't trio just keep track of the current "nursery" (or whatever it's called internally) for the current task, and then let any async function start new tasks using global functions (e.g. trio.start and trio.start_soon)? It would seem to me the only change this would require compared to the current behavior is to have a top-level nursery created for the trio.run call itself, which would bound the execution of all tasks started within that top-level call. You would still be able to open new nurseries to create bounded groups of tasks within larger tasks, but you wouldn't need to name a local variable for the resulting object nor pass that variable to other functions, so the name would be much less important.

@oremanj

This comment has been minimized.

Contributor

oremanj commented May 5, 2018

@maffoo - giving the nursery object a name makes it possible to give another task the ability to start tasks in your scope, even though it is not in that scope, by passing the other task the nursery object. This provides additional flexibility in more intricate cases, which I wouldn't want to do away with. (It may even be required by trio's internals, I'm not sure.)

@maffoo

This comment has been minimized.

maffoo commented May 5, 2018

@oremanj, I could imagine this being useful in some cases, but if those are special "intricate" cases perhaps it would be useful to support the basic default case of not capturing the nursery in a local? (Although explicit is better than implicit and all that :-) .) Also, out of curiosity, could you point me to a place where this used?

@njsmith

This comment has been minimized.

Member

njsmith commented May 5, 2018

The more important reason for reifying the nursery is that we want to be able to see by looking at the source code all the functions that don't have access to it. Any function call that isn't passed a nursery can be assumed not to have access to any nurseries that outlive the call. If nurseries were implicitly attached to the current task then we'd lose this.

@maffoo

This comment has been minimized.

maffoo commented May 5, 2018

@njsmith and @oremanj, makes sense, thanks for the explanations. I still think a name that draws attention to the boundedness of subtasks would be nice, but as @njsmith says, the ability to spawn new work is a special capability in its own right, so a name with that emphasis is ok too.

@tgoodlet

This comment has been minimized.

Member

tgoodlet commented May 18, 2018

I had a couple pals point me to projects after sending @njsmith's recent nursery/goto blog post.
I figured I'd stick them here in case they spur further (naming) insight though these names are already mentioned in the initial description.

Personally I like nursery and I think it it communicates the idea of a task with a scope or lifetime.

Only serious names I can think of offhand are task_branch() or open_branch():

with trio.task_branch() as branch:
    branch.start_soon(coro, args)
@ksamuel

This comment has been minimized.

ksamuel commented May 30, 2018

I find the whole API to be very verbose:

with trio.open_nursery() as nursery:
     nursery.start_soon()

If you do a lot of async, you will type this very often. So we need to make it convenient. For this particular bit, it's ok to make it a shortcut, as if it's the main idiom, people will see it often and look it up anyway. It's not like it's going to be some obscure call you see once in a while.

So, just because nursery is long, I'm for changing it.

If you like the nursery analogy and the branching analogy, we can satisfy both using "nest", which is also short:

with trio.nest() as nest:
     nest.hatch(foo)
     nest.hatch(bar, 1)

But I wouldn't mind to do even shorter.

We could make it a verb, using __call__ to provide a shorhand:

with trio.runner() as run:
     run(foo)
     run(bar, 1)

Or give it a native look and feel with a dunder method:

with trio.scope() as tasks:
     tasks << foo
     tasks << bar, 1

It's shorter to type than start_soon(), and convey that something special happens.

I also like the name scope because it's neutral. We already have many different kind of scope, so you now you need to learn "scope of what ?" to understand it. But you already understand it place boundaries on something.

Also we could just focus on the causality, which is in the end the whole benefit of trio:

with trio.timeline() as line:
     line.run(foo)
     line.run(bar, 1)
with trio.begin() as scope:
     scope.run(foo)
     scope.run(bar, 1)

Also, this is a common task, so a shortcut to do "run this bunch of task by blocking" maybe in order.

await trio.collect(foo, bar) # like asyncio.gather, but with the nursery guaranty
@sametmax

This comment has been minimized.

sametmax commented Jun 1, 2018

Seems like scope and nest are winning right now. But since scope is already well understood as a generic way to define "binding something to a delimited region", if think using it would ease people into the concept.

After all, we have many scopes already (lexical scope, dynamic scope, angular scope...) so programmers know the general idea, but also that the specific application of it need to be looked up.

I find:

with trio.scope() as scp:
     scp.run(foo)
     scp.run(bar, 1)

Quite clear. And even as a one liner for the most common case:

await trio.scoped(foo, partial(bar, 1)) 

The kid in me also like the __lshift__ oriented api since it is a bit shorter to type and feels a bit native, like a go operator or something. But I understand that people may feel it's too much magic.

Because I gave try at a working POC of porting nurseries to asyncio (https://0bin.net/paste/V5KyhAg-2i5EOyoK#dzBvhdCVeFy8Q2xNcxXyqwtyQFgkxlKI3u5QG0buIcT), I discussed with Yuri yesterday since he is going to implement nurseries in uvloop, and eventually on asyncio. asyncio won't use that because capturing ensure_future() results would break a lot of things, but maybe something with a warning.

Anyway you can see in the test code at the bottom that "scope" reads pretty well and I find the intent well conveyed. The class could be called something like AsyncTaskScope, but aliased as trio.scope

My point is, we need to solve the naming before Yury get serious about it. He hasn't started yet, but he works fast. And once he codes it as "nursery" in uvloop, which is currently the only name he knows and uses for the concept, it will be set forever.

I really don't think sticking with a 7 letters word that we will need that often is a good thing, especially since the IT vocabulary doesn't lack expressiveness already.

@gareth-rees

This comment has been minimized.

gareth-rees commented Jun 7, 2018

I approve of renaming nurseries. When I first looked at Trio I had a little trouble understanding how nurseries worked, and I think that was mostly because of the name. The problem is not that the name is cute, it's that it doesn't have the right connotations. The name "nursery" suggests "a place where tasks/coroutines start out". Compare with memory management, we use the name "nursery" to mean "a region of memory containing recently created objects".

But Trio tasks don't just start inside nurseries, they spend their entire lifetime inside the nursery. And the most important feature of nurseries is how they handle the end of the lifetime of their tasks: in particular, control doesn't exit the nursery's with statement until all the tasks created in that nursery have finished (either by all of them exiting normally, or by one of them raising an exception and the nursery cancelling the others). It's this property that allows us to reason about code running in Trio, as described in Nathaniel's article "Notes on structured concurrency".

So whatever name is chosen, I think that it would be helpful to beginners if that name hinted at this lifetime (or synchronization/joining) property. Maybe the name lifetime would work.

The corresponding concept in normal (synchronous) structured programming is the "block" and this has a useful double meaning because a nursery's with statement blocks (waits) until all its tasks have finished before exiting. So maybe a name like lifetime block or parallel block or async block would have the right connotations. ("Async block" is a near-rhyme with "basic block", which also has good connotations since it's the unit of code which compilers use to reason about the properties of code.)

I don't like the name "scope" because I associate that with controlling the binding of names (for example in "lexical scope" and "dynamic scope") and it doesn't suggest anything about the lifetime of tasks to me.

@sametmax

This comment has been minimized.

sametmax commented Jun 7, 2018

I like "lifetime". It conveys the idea pretty well. But it's a bit too long to type for something you will constantly use. I wouldn't want the len() function to be called get_len().

On the other hand, "block" is a dangerous name because in the async world, we are very preoccupied about things blocking or not, and it has a mixed meaning.

We could keep the methode named scope(), but it would return an object of type LifetimeScope.

@gareth-rees

This comment has been minimized.

gareth-rees commented Jun 7, 2018

The name of the concept needn't be the same as the name of the function, just as the length of a list is not the same as the function len.

@madsmtm

This comment has been minimized.

madsmtm commented Jun 8, 2018

The name nursery stood out to me at first, and sparked my interest in this project. That's where the "cutesy" thing is actually important, it's important for first time users. nest or lifetime would work for me too, but scope is way too familiar, and doesn't really communicate that this is a new concept

@SergeBouchut

This comment has been minimized.

SergeBouchut commented Jun 9, 2018

I suggest warrant which is a noun and a verb at the same time. I think it may underlie control notion (but I am not a native Entlish speaker so I may be wrong about that).
Also it may be nice as a native primitive in the future.

warrant:
    do_something()
    do_otherthing()

Otherwise guard or park or farm for the same resasons.

farm:
    do_something()
    do_otherthing()

I understand and approve the reasons for nursery but it does not sound like a primitive name for me (contrary to if, for, while, etc.)

Edit: I also love block, stage, track previously mentionned.

Edit2: Final thought: track sounds like a really appropriate metaphor for concurrent tasks to run, starting almost all at the same time and waiting for all the runs to be finished, before ending. No as familiar as scope for instance, but less abstract than nursery and definitly shorter.

@drafter250

This comment has been minimized.

drafter250 commented Jun 19, 2018

I kind of like the word 'hive'. Every bee works for the good of the hive. And starts and ends it's life as part of the hive. Only with a new queen will some of the workers transfer to a new hive. And you could use 'hive.spawn ()'

@futal

This comment has been minimized.

futal commented Jul 9, 2018

Nurseries are groups of tasks that extend from the beginning of the first task and last until the last task finishes. The group of task can be cancelled if one task cannot complete. This is a common concept in scheduling construction projects. Depending of the software (Primavera, MS Project, DynaRoad, etc), scheduling method (CPM, PERT, LBMS) and detail level (project or project portfolio), it is called "summary task", "hammock activity", "subproject" or "project". On Gantt charts, it is usually represented above its subtasks as a thin line with wedges clearly marking its start and finish dates.

Sumtask may better describe that subtasks are executed concurrently. Project may better explain that it can be cancelled if one subtask fails.

In construction, summary activities are often used to gather cost information rather than for scheduling but the concept is the same. For example with MS Project, you can link summary activities (very powerful assuming that you don't link subtasks with a task in another scope).

@sametmax

This comment has been minimized.

sametmax commented Jul 10, 2018

Since then, I played with the concept a bit further and ended up applying it to asyncio more seriously.

I'm definitely biased to the name "Execution Scope" now. Indeed, the concept of a scope already has the notion of nesting and boundaries, while being well known in programming. Yet putting "execution" in front of it makes it clear that it's a specific kind of scope, and one that limits the execution of something.

This translates into quite an understandable API IMO. Example from the asyncio lib experiment:

import random
import asyncio
import ayo

async def zzz():
    time = random.randint(0, 15)
    await asyncio.sleep(time)
    print(f'Slept for {time} seconds')

async with ayo.scope(max_concurrency=10, timeout=12) as run:
    for _ in range(20):
        run.asap(zzz()) # schedule the coroutine for execution

Not only the implementation works, but it also runs as it reads, which is a great benefit for a new concept.

This allows to build even higher level tools on top of it:

async with ayo.scope() as run:
    run.all(zzz(), zzz(), zzz())
    run << zzz() # shorcut for run.asap(zzz())
    run.aside(callback, foo, bar=1)  # run.asap(asyncio.run_in_executor(None, callback, foo, bar=1))
    run.after(2, callback, foo, bar=1)
    run.at(dt.datetime(2018, 12, 1), callback, foo, bar=1)
    run.every(0.2, callback, foo, bar=1)

"Run that in this execution scope" feels like a clear way to express all those.

@gnzlbg

This comment has been minimized.

gnzlbg commented Aug 20, 2018

scoped threads from rust's crossbeam crate

In languages with RAII (like C++, Rust, D, etc.) the fundamental language feature that enables this is that of a "scope", which is often created with a pair of curly braces { ... }, and invokes the destructors of the objects in the scope in some specified order.

In C++, for example, the simplest way to use a nursery would be to just:

{  // create a new scope:
    auto t0 = std::thread(foo);
    auto t1 = std::thread(bar);
    // ...
}  // t0 and t1 must have finished (or have been handled somehow)

In crossbeam, nursery is actually just called Scope.

@belm0

This comment has been minimized.

Member

belm0 commented Aug 30, 2018

I came up with "task scope" independently from reading the opening post. I think it's close to ideal. ("Execution scope" is arguably more accurate, but also more letters.)

When you consider practical usage, it's a clear win over "nursery". In practice you'd like a short name for accessing the nursery, but n is not prudent. Proposed idiom for task scope using ts:

async with trio.open_task_scope() as ts:
    ts.run_soon(...)
@alexshpilkin

This comment has been minimized.

alexshpilkin commented Sep 24, 2018

Scopes (with whatever modifier—you appear to like long descriptive names much more than I do) should be fine, because what’s being enforced is pure (Algol) stack discipline with regard to spawning children. It’s not just like (dynamic) variable scopes, it’s exactly the same thing.

@rkedward

This comment has been minimized.

rkedward commented Nov 5, 2018

Perhaps "pod" as peas in a pod. Its short, is not commonly in use, and describes confinement.

@scottjmaddox

This comment has been minimized.

scottjmaddox commented Nov 6, 2018

I've been toying with the idea of writing a structured concurrency library for Rust. I haven't gotten far enough to see what is actually possible given the existing concurrency primitives, but I'm toying with naming the library everett, after Hugh Everett, the originator of the Everett interpretation, a.k.a. the Many-worlds interpretation, of quantum mechanics. Under this metaphor, the name breach seems like an appropriate alternative to nursery. A breach, as sometimes used in science-fiction, is a wormhole or branch point between two or more worlds. Along these metaphorical lines, it makes sense that a breach would be a branch point from which multiple concurrent threads of execution originate. Taking the metaphor further, instead of run_soon, the method that registers tasks for execution could be called entangle.

Example usage:

async with trio.open_breach() as breach:
    breach.entangle(...)
@theelous3

This comment has been minimized.

theelous3 commented Nov 6, 2018

If you have to add a section to the docs to explain your naming, your naming is not good. Keep it simple.

@scottjmaddox

This comment has been minimized.

scottjmaddox commented Nov 6, 2018

That's a fair argument against such a naming approach, but I think it needs to be balanced against the desire to implicitly communicate that these are new fundamental concepts that must be grokked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment