Mr. Biancardi wrote about how the court had ruled against him. That drew attention from others who asked for articles about themselves to be taken down.
One of those demands was from Vittorio Pecoraro, now in his 80s, who was stabbed by his brother, Umberto, in the 2008 seaside restaurant brawl. The brothers were arrested after the fight. Assault-related charges against Vittorio Pecoraro were effectively dropped when the authorities did not pursue them.
Vittorio Pecoraro sued Mr. Biancardi, citing the right to be forgotten. Mr. Biancardi refused to remove the article. The story had been based on information from the police, he said. Nothing was factually wrong.
But Vittorio Pecoraro argued that his privacy had been violated. The article was easily available and searchable online, and he had not been convicted of a crime. Yet because of PrimaDaNoi, what he considered a humiliating family argument had become the first thing that many people knew about him and his pizza and seafood restaurant, he said.
“I have a reputation, I have been here for 50 years, I am known all over,” Mr. Pecoraro said in an interview at the restaurant, Positano, where the 2008 fight had occurred.
His lawyer, Paolo Sardini, said Google was not targeted because the article was Mr. Biancardi’s responsibility.
Umberto Pecoraro’s son, Vincenzo, said his father declined to comment.
In 2013, an Italian judge ruled in favor of Vittorio Pecoraro and ordered PrimaDaNoi to delete its stabbing story, saying the information in it was old and no longer in the public interest. (Mr. Pecoraro didn’t ask for another PrimaDaNoi article about the incident to be deleted because it didn’t rank high in Google’s search results for his restaurant.)
There are kids now who are old enough to go fight in wars that were justified back when they still had their umbilical cords attached. For them, the attacks are only history; that's all they ever were.
I can sort of understand it. I was born after Vietnam, after Watergate. But my whole childhood, these were the points of reference, the milestones used to justify choices or underpin arguments. They were totems, symbols, history. Only history, not something real.
And these days I spend a lot of time with people for whom 9/11 is only history. Someone who is as old today as I was that day would probably have been shielded from knowing too much at the time. They'd have been as young as my son is today, and I still shield him from the full weight of my memories of that day.
Frankly, that's hard for me to process. We still ground so much of our social and political rhetoric in that day, so it's easy for me to forget that for many (for most?), it's only a signifier, with none of the visceral evocations of memory. I remember how 9/11 smelled. I remember how my city smelled, for months. I can still look up at a clear blue sky with the slightest breeze in the air and imagine that morning, and remember when the wind shifted and the plume came over our neighborhood.
So, it's up to me to let it go. To let it become history. I don't mind that younger people don't have the same reverence for the moment. Maybe I'm kind of glad they don't. I can see now what I couldn't see then. Those of us who witnessed that day, even if only in a small way, will fade from the cultural conversation. When I was young, you would still hear people talk about D Day, or Pearl Harbor. Being young and insolent, I never had much patience for listening to the stories. Young people don't have reverence for these moments.
I guess we said we'd never forget. But the consensus around grief, around memorial, around observance — that fragile fiction faded by the time the smell dissipated. We didn't get around to deciding what it was, exactly, that we were Never Forgetting.
And so, we ended up with this legacy. There are ritualized remembrances, largely led by those who weren't there, those who mostly hate the values that New York City embodies. The sharpest memories are of the goals of those who masterminded the attacks. It's easy enough to remember what they wanted, since they accomplished all their objectives and we live in the world they sought to create. The empire has been permanently diminished. Never Forget.
But I still maintain a little bit of hope. Because just as a new generation doesn't revere the memories of those of us okd enough to bear witness, they are also not despairing over the failures of our follow-up. This is the world they've always lived in, the starting point they were always given. So there was never anything other than moving forward from that day.
In Past Years
Each year I write about the attacks on this anniversary, to reflect both on that day and where I'm at right now. I also deeply appreciate the conversation that ensues with those who check in with me every year.
I spent so many years thinking “I can’t go there” that it caught me completely off guard to realize that going there is now routine. Maybe the most charitable way to look at it is resiliency, or that I’m seeing things through the eyes of my child who’s never known any reality but the present one. I'd spent a lot of time wishing that we hadn't been so overwhelmed with response to that day, so much that I hadn''t considered what it would be like when the day passed for so many people with barely a notice at all.
So, like ten years ago, I’m letting go. Trying not to project my feelings onto this anniversary, just quietly remembering that morning and how it felt. My son asked me a couple of months ago, “I heard there was another World Trade Center before this one?” and I had to find a version of the story that I could share with him. In this telling, losing those towers was unimaginably sad and showed that there are incredibly hurtful people in the world, but there are still so many good people, and they can make wonderful things together.
I don’t dismiss or deny that so much has gone so wrong in the response and the reaction that our culture has had since the attacks, but I will not forget or diminish the pure openheartedness I witnessed that day. And I will not let the cynicism or paranoia of others draw me in to join them.
What I’ve realized, simply, is that 9/11 is in the past now.
For the first time, I clearly felt like I had put the attacks firmly in the past. They have loosened their grip on me. I don’t avoid going downtown, or take circuitous routes to avoid seeing where the towers once stood. I can even imagine deliberately visiting the area to see the new train station.
There’s no part of that day that one should ever have to explain to a child, but I realized for the first time this year that, when the time comes, I’ll be ready. Enough time has passed that I could recite the facts, without simply dissolving into a puddle of my own unresolved questions. I look back at past years, at my own observances of this anniversary, and see how I veered from crushingly sad to fiercely angry to tentatively optimistic, and in each of those moments I was living in one part of what I felt. Maybe I’m ready to see this thing in a bigger picture, or at least from a perspective outside of just myself.
I thought in 2001 that some beautiful things could come out of that worst of days, and sure enough, that optimism has often been rewarded. There are boundless examples of kindness and generosity in the worst of circumstances that justify the hope I had for people’s basic decency back then, even if initially my hope was based only on faith and not fact.
But there is also fatigue. The inevitable fading of outrage and emotional devastation into an overworked rhetorical reference point leaves me exhausted. The decay of a brief, profound moment of unity and reflection into a cheap device to be used to prop up arguments about the ordinary, the everyday and the mundane makes me weary. I’m tired from the effort to protect the fragile memory of something horrific and hopeful that taught me about people at their very best and at their very, very worst.
These are the gifts our children, or all children, give us every day in a million different ways. But they’re also the gifts we give ourselves when we make something meaningful and beautiful. The new World Trade Center buildings are beautiful, in a way that the old ones never were, and in a way that’ll make our fretting over their exorbitant cost seem short-sighted in the decades to come. More importantly, they exist. We made them, together. We raised them in the past eleven years just as surely as we’ve raised our children, with squabbles and mistakes and false starts and slow, inexorable progress toward something beautiful.
I don’t have any profound insights or political commentary to offer that others haven’t already articulated first and better. All that I have is my experience of knowing what it mean to be in New York City then. And from that experience, the biggest lesson I have taken is that I have the obligation to be a kinder man, a more thoughtful man, and someone who lives with as much passion and sincerity as possible. Those are the lessons that I’ll tell my son some day in the distant future, and they’re the ones I want to remember now.
[T]his is, in many ways, a golden era in the entire history of New York City. Over the four hundred years it’s taken for this city to evolve into its current form, there’s never been a better time to walk down the street. Crime is low, without us having sacrificed our personality or passion to get there. We’ve invested in making our sidewalks more walkable, our streets more accommodating of the bikes and buses and taxis that convey us around our town. There’s never been a more vibrant scene in the arts, music or fashion here. And in less than half a decade, the public park where I got married went from a place where I often felt uncomfortable at noontime to one that I wanted to bring together my closest friends and family on the best day of my life. We still struggle with radical inequality, but more people interact with people from broadly different social classes and cultures every day in New York than any other place in America, and possibly than in any other city in the world.
And all of this happened, by choice, in the years since the attacks.
[T]his year, I am much more at peace. It may be that, finally, we’ve been called on by our leadership to mark this day by being of service to our communities, our country, and our fellow humans. I’ve been trying of late to do exactly that. And I’ve had a bit of a realization about how my own life was changed by that day.
Speaking to my mother last week, I offhandedly mentioned how almost all of my friends and acquaintances, my entire career and my accomplishments, my ambitions and hopes have all been born since September 11, 2001. If you’ll pardon the geeky reference, it’s as if my life was rebooted that day and in the short period afterwards. While I have a handful of lifelong friends with whom I’ve stayed in touch, most of the people I’m closest to are those who were with me on the day of the attacks or shortly thereafter, and the goals I have for myself are those which I formed in the next days and weeks. i don’t think it’s coincidence that I was introduced to my wife while the wreckage at the site of the towers was still smoldering, or that I resolved to have my life’s work amount to something meaningful while my beloved city was still papered with signs mourning the missing.
Finally getting angry myself, I realize that nobody has more right to claim authority over the legacy of the attacks than the people of New York. And yet, I don’t see survivors of the attacks downtown claiming the exclusive right to represent the noble ambition of Never Forgetting. I’m not saying that people never mention the attacks here in New York, but there’s a genuine awareness that, if you use the attacks as justification for your position, the person you’re addressing may well have lost more than you that day. As I write this, I know that parked out front is the car of a woman who works in my neighborhood. Her car has a simple but striking memorial on it, listing her mother’s name, date of birth, and the date 9/11/2001.
On the afternoon of September 11th, 2001, and especially on September 12th, I wasn’t only sad. I was also hopeful. I wanted to believe that we wouldn’t just Never Forget that we would also Always Remember. People were already insisting that we’d put aside our differences and come together, and maybe the part that I’m most bittersweet and wistful about was that I really believed it. I’d turned 26 years old just a few days before the attacks, and I realize in retrospect that maybe that moment, as I eased from my mid-twenties to my late twenties, was the last time I’d be unabashedly optimistic about something, even amidst all the sorrow.
[O]ne of the strongest feelings I came away with on the day of the attacks was a feeling of some kind of hope. Being in New York that day really showed me the best that people can be. As much as it’s become cliché now, there’s simply no other way to describe a display that profound. It was truly a case of people showing their very best nature.
We seem to have let the hope of that day go, though.
I saw people who hated New York City, or at least didn’t care very much about it, trying to act as if they were extremely invested in recovering from the attacks, or opining about the causes or effects of the attacks. And to me, my memory of the attacks and, especially, the days afterward had nothing to do with the geopolitics of the situation. They were about a real human tragedy, and about the people who were there and affected, and about everything but placing blame and pointing fingers. It felt thoughtless for everyone to offer their response in a framework that didn’t honor the people who were actually going through the event.
I don’t know if it’s distance, or just the passing of time, but I notice how muted the sorrow is. There’s a passivity, a lack of passion to the observances. I knew it would come, in the same way that a friend told me quite presciently that day back in 2001 that “this is all going to be political debates someday” and, well, someday’s already here.
I spent a lot of time, too much time, resenting people who were visiting our city, and especially the site of the attacks, these past two years. I’ve been so protective, I didn’t want them to come and get their picture taken like it was Cinderella’s Castle or something. I’m trying really hard not to be so angry about that these days. I found that being angry kept me from doing the productive and important things that really mattered, and kept me from living a life that I know I’m lucky to have.
[I]n those first weeks, I thought a lot about what it is to be American. That a lot of people outside of New York City might not even recognize their own country if they came to visit. The America that was attacked a year ago was an America where people are as likely to have been born outside the borders of the U.S. as not. Where most of the residents speak another language in addition to English. Where the soundtrack is, yes, jazz and blues and rock and roll, but also hip hop and salsa and merengue. New York has always been where the first fine threads of new cultures work their way into the fabric of America, and the city the bore the brunt of those attacks last September reflected that ideal to its fullest.
I am physically fine, as are all my family members and immediate friends. I’ve been watching the footage all morning, I can’t believe I watched the World Trade Center collapse…
I’ve been sitting here this whole morning, choking back tears… this is just too much, too big. I can see the smoke and ash from the street here. I have friends of friends who work there, I was just there myself the day before yesterday. I can’t process this all. I don’t want to.
But once she got there, a very apologetic school staff informed her that he was not on its list and — making matters worse — the school system’s registration offices didn’t open until noon. After spending an hour at the school trying to sort through the mess, Wu left with her son — another victim of the chaotic Boston school registration system.
Get Metro Headlines in your inboxThe 10 top local news stories from metro Boston and around New England delivered daily.
Wu took to Twitter to vent her frustrations, writing “special guest with me at City Hall today due to BPS limbo.”
“The most frustrating part was that I was afraid this would happen & asked several times on the phone with @BostonSchools on Monday if I could get any confirmation that Blaise was all set — an email? A number? Anything?” she wrote as she was heading to her weekly City Council meeting. No, she said she was told, just show up.
Wu’s experience highlights the kinds of frustrations families endure as they attempt to navigate the city’s Byzantine student assignment system, which allows families to choose from a customized list of schools based on their home address but offers no guarantee they will receive any of their picks. The situation is even more precarious for families vying for prekindergarten, where hundreds of children are waitlisted every year with no clear indication they will ever be assigned.
Families have often complained that they receive conflicting information from school registration sites, and the process is cumbersome, requiring families to sign up in person and produce an array of documents, from proof of residency to child immunization records.
The school system defended its communication practices with families.
“Boston Public Schools always strives to communicate clearly, consistently, and accurately with families,” Dan O’Brien, a school spokesman, said in a statement. “In this isolated instance, there was a human error that led to a miscommunication. Our staff responded swiftly to bring an immediate resolution to this issue.”
Wu, in an interview, said she and her husband are lucky they can make their schedules work when a snafu like Wednesday morning’s arises, but she added, “Many other families can’t have last-minute instability and that you can’t rely on what you are told in an enrollment system — that is pretty archaic.”
Her City Hall office Wednesday afternoon looked almost like a makeshift daycare with brightlycolored Mega Legos scattered across the floor as Blaise built a tower with them and later pulled out a stack of children’s books from a shelf to read. Earlier, he endured a City Council meeting, where he sat with Councilor Kim Janey and drew pictures. He was still wearing his new long-sleeved white polo shirt with “Charles Sumner Elementary School” printed on the front.
One floor below, Wu’s youngest son, Cass, 2, was in the actual City Hall daycare.
The registration snafu was short-lived. Wu received an e-mail from the Sumner’s principal before the City Council meeting began, informing her that the registration was complete and that Blaise could return to school.
Wu said she appreciated the effort everyone made, from the school secretary to the principal, to resolve the issue. The Sumner was her top choice: She and her husband like the sense of community there, and it’s a short walk from their Roslindale home.
Beliza Veras-Moriarty, a Boston school parent who served recently on the superintendent search committee, said she was not surprised by Wu’s mishap. Six years ago, she missed a single phone call from the school system informing her a slot had become available for her son at Boston Arts Academy, but the family was on vacation at the time while she also was juggling a newborn.
“I called back and the seat was taken away,” she said. “My son was heartbroken.”
In the end, it worked out for her son, who wanted to be an artist and graduated from Fenway High School with a full scholarship to MassArt. But Veras-Moriarty said the school system could do a better job of communicating and working with families. “I feel like they beat you down so you don’t say anything,” she said.
This wasn’t the first time Wu has turned to social media to raise concerns about the assignment system. She voiced disappointment this spring when Blaise did not get assigned to any of the eight or nine schools they applied to, noting “a system that creates winners & losers out of our families is one that’s failing our city as a whole.” She echoed similar concerns a year earlier when she unsuccessfully tried getting Blaise into a preschool program for 3-year-olds.
Other city councilors have also voiced concerns about the student assignment system. Council President Andrea Campbell in releasing her education plan in June called on the school system to make the registration centers more welcoming and to simplify the school assignment process while also increasing access to quality schools to families of all backgrounds.
“The central office has to do a much better job in meeting the needs of families,” Campbell said. “Good communication is essential. Parents have a lot going on.”
Everyone knows that local newspapers are in trouble. That’s why Deb Fallows and I have been chronicling examples of smaller papers that have bucked the economic trend—in Mississippi, in coastal Maine, in rural communities across the country.
But what “everyone knows” about the main source of the problem may be wrong—or misleading enough to divert attention away from a possible solution.
The conventional view of the local-journalism crisis is that running a small-town newspaper just isn’t a viable business any more—now that the internet advertising has drained off revenue, and now that virtual communities and social media have displaced real-world connections and communities.
Those pressures are all too real. (Sobering details on the collapse of ad revenue are here.) But some of the remaining success stories in this troubled field suggest that the ownership structure of local news organizations may matter as much as internet-era advertising shifts, in determining which organizations survive and which perish.
In short: Increasing evidence suggests that the local newspaper business may still be viable, simply as a business. What it can no longer do is provide the super-profit levels that private equity groups expect from their holdings, and that they demand as a condition of letting the papers exist. Papers that are doomed under private-equity ownership might have a chance in some different economic structure.
This proposition—that newspaper ownership is as important as internet-era advertising trends, in deciding local journalism’s future—was examined at length in a 2017 article in The American Prospectby Robert Kuttner and Hildy Zenger (the latter a pen name). It has been a theme connecting our previous newspaper-survivor reports, from Maine to Mississippi. And it is the idea behind a new weekly print newspaper whose first edition came off the presses this month, in Provincetown, Massachusetts, at the tip of Cape Cod.
The long-established paper for “Outer Cape Cod,” the communities from Provincetown southward, was the Provincetown Banner, founded before the Civil War. In 2008, the Banner was sold to GateHouse Media Inc., a private-equity-run chain of mainly smaller papers across the country. Long-established newspaper chains like Gannett, Knight Ridder, and McClatchy have their problems and detractors. But their goal, as Kuttner and Zenger pointed out in their Prospect piece, was fundamentally to operate newspapers. Their operations paid at least lip-service to the idea that newspapers had a civic and community role, beyond their sheer economic existence.
The modern trend in small-paper ownership is their takeover by private-equity firms, of which Alden Global Capital, its subsidiary MediaNews Group (formerly known as Digital First Media), and GateHouse are the best-known examples. For these institutions, newspapers are a financial asset like any other—like a tract of commercial real estate, like a steel mill or a suburban mall. The profit-maximizing model they have applied to countless small papers has been: slashing costs, mainly by laying off reporters and editors, so as to boost short-term profit rates; continuing the cutbacks, so as to maintain profit margins, even as a thinner paper attracted fewer readers and ads; and when there was nothing left to cut, declaring bankruptcy or closing the paper, which had in strictly financial terms reached the end of its useful life.
The Banner, in its GateHouse years, has gone through a version of this cycle. (For the record: I have called and sent messages to relevant GateHouse officials, and will report back if I hear from them.) At the time of its sale, it had a staff of about 20. By early this year, the staff was down to four.
“When people think about corporate ownership of newspapers, they think the problem is that the company is telling you what to write—like Sinclair, with its broadcast stations,” Ed Miller, a long-time newspaper entrepreneur who worked as an editor at the Banner starting in 2015.
“The fact is, they couldn’t care less what you write,” he said. “Their only interest is how much profit you can squeeze out of the operation, so the way they actually undermine the reporting of news is simply by laying off staff. The cuts make the job so overwhelmingly difficult to do that there’s just no possibility that you will get into serious news coverage, or investigating the stories that need to be dug out.”
In July of this year, Miller resigned from the Banner. This month he and his wife, Teresa Parker, published the first print edition of a new, weekly, print newspaper, The Provincetown Independent, aimed at readers, advertisers, and citizens in the towns of outer Cape Cod. This month’s paper was a preview, and regular weekly print publication will begin in early October. In the meantime, new stories are being posted online.
The territory the Independent is covering is more diverse than the vacation-time imagery of Cape Cod might suggest. The communities in its market—Provincetown, Truro, Wellfleet, and Eastham—have median incomes at about the national-average level (or in the case of Provincetown, significantly below it). Some of the residents have vacation homes there; some are service-workers, small merchants and business people, or part of the working fisheries. Provincetown has long been an LGBT haven; the outer Cape has well-established arts, scientific, marine-science, and tourism-oriented institutions.
“This is an interesting community,” Miller told me. “There are lot of engaged people here, there is money here, this is a place that ought to be able to support a perfectly successful, profitable newspaper.” As they observed the shrinkage at the Banner, which recently laid off its last local reporter, Miller and his colleagues began thinking about a new venture they might launch.
The business plan is based on a four-year hoped-for course to profitability, at which point the paper would have total paid circulation of 6,000 per week, and 19 full-time staffers. So far Miller and Parker have raised a little more than half of the business capital they are looking for. The non-profit operation has raised three times as much as its original target. This money will be used for special projects—training young journalists, supporting investigative efforts, long-term projects on “themes that are important to the community, like how young families will manage to live here,” Miller told me.
For all the ceaseless technological and business change in the news business, Miller said, “The basics of the business are that people love local newspapers. If you can provide something they want, especially information they can’t get anyplace else, they will be loyal to you.”
The weekly publication schedule of the Independent, like the every-other-week schedule of The Quoddy Tides in Maine, helps the paper resist any temptation to cover breaking national or world news, for which readers have a million faster, better sources. Instead it can cover local developments—taxes, schools, zoning, real estate, religion, business ups and downs—that simply won’t be covered anywhere else.
“People are saying we need to come up with a new business model” for small newspapers, Miller told me. “Actually, the old business model for a local newspaper that really does its job, can actually work pretty well.” He said that he canvassed owners of similar-scale papers around the country, and found that a normal profit rate was about 8 percent of revenue. For a private-equity fund, that’s nothing. “But if you’re running a normal local business, 8 percent is pretty good.” Miller said that one local-paper owner told him, “If I’m making more than 8 percent, I know it’s time to reinvest in the business—hire more people, give them raises, upgrade our equipment.”
One of the Independent’s advisors and business backers is Louis Black, who in the 1980s in Austin co-founded and edited the successful and influential alt-weekly The Austin Chronicle and then was a co-founder of mega-successful SXSW. I spoke with him by phone today to ask why he’d become involved.
“When we started the Chronicle, we didn’t know what we were doing,” he said. “It took a decade to get up to speed. Eventually we realized a paper like that creates the community. It pulls it together, then sends it out.” Black said that despite the travails of print media, this was the role that he hoped papers like the Independent could fulfill.
“It’s not just about conveying information,” he said. “People have new ways to do that quickly. It’s about provide a cultural and intellectual center—and not only for like-minded people. It’s for people who want to engage in debate, and have principled debate. A strong local paper can do that. It’s not just about the words or information. It’s the spirit.”
Black met Ed Miller and Teresa Parker because Black had a neighboring house in Cape Cod. He learned that he and Miller were both from Teaneck, New Jersey, and both had spent their careers starting publications—Black’s with more financial success. Eventually Black decided to put time and money into the new Independent venture.
Did he think that it realistically had a chance? Black laughed, chuckled out some version of “Who knows?” and then said: “Because Cape Cod is what it is, and because Ed is who he is, I think they have a shot.”
Like Miller, and like me, Black is from the dreaded and aging Baby Boom generation. “We’re too old to do this,” Black told Miller, as they considered the years-long, dicey effort of starting a new publication. “But the young people don’t know how, and we have to show them. People need to see that it can be done.”
“I want to hang the sword up,” Black told me. “But we can’t. We’re living in a world where if we believe, we have to engage. And it matters.”
And one of those adults, KPCC listener Victoria Simon, had a question about how to approach the topic with children in a way that includes empathy and compassion, but also keeps safety in mind.
"I am the parent of a six-year-old and a three-year-old and we live in Santa Monica where we come face to face with homelessness every day," she said. "So, how do I thread that needle in terms of educating them and also keeping them safe?"
EMPATHY IS KEY
One of the most important things to keep in mind when talking to children about homelessness is coming from a place of empathy.
"When you tell a child that anyone can be homeless you then can also open up a discussion about the many circumstances that go into homelessness," said author and homeless advocate Angela Sanchez.
She wrote and illustrated the children's book Scruffy and the Egg, which was inspired by stories Sanchez and her father used to tell each other in her teen years when they were experiencing homelessness. Simon and Sanchez met up in studio for KPCC's Take Two — to have a candid conversation about how to explain homelessness to children. Here's a rundown of some of Sanchez's advice based on her own experience with being homeless.
ANYONE CAN BE HOMELESS
"We see homelessness and poverty as tied to ideas of merit and so when you tell a child that anyone can be homeless, you also open up the discussion about the many circumstances that go into homelessness," said Sanchez.
Though the most visible type of person experiencing homelessness are the individuals we see out in the streets, Sanchez went on to explain families comprise 40 percent of the total homeless population. And about 25 percent of all people experiencing homelessness are under the age of 18.
"The average age is eight years old," Sanchez said. "When I talk to kids about that, I usually say that means a third grader is the most likely type of child you will see who is homeless."
Sanchez has found that when she speaks to kids about homelessness and reveals that the most common age is close to or exactly their own, something clicks. It makes an otherwise abstract concept far more tangible, understandable and relatable. The reaction is one full of empathy.
"Usually the response that I've gotten is 'Oh, how do I help?' or 'I've never seen another homeless kid' or 'How do I know when someone is homeless.'" Sanchez said.
It's at this point in the conversation, she suggests, you list out different ways they, as children, can make an impact.
SHOW THEM THEY CAN DO SOMETHING ABOUT IT
There are a lot of ways people can our city's homeless population. But children often see the world differently and have an endless supply of compassion.
Simon brought up how her six-year-old son suggested housing a homeless person in their home as a way of helping out. She found herself at a loss of how to respond. Sanchez proposed focusing on impact.
"You can always turn around and say: Think about all the help that you need in one day and I live with you. And so being able to list those things and say, this is someone else who will also need that kind of stuff too." When you can break down the basic building blocks of a situation that makes it more consumable. Here are some more concrete ways you can suggest to help:
Volunteer at a family soup kitchen - For young kids, it's best to have them interacting with families and other children they could possibly relate to.
Lend an ear - Volunteer once a month to sit and speak with someone and give them your full attention.
School On Wheels, Inc. - They work with K-12 kids who are experiencing homelessness and their whole focus is to provide volunteer tutors.
KEEPING SAFETY IN MIND
One of the main concerns that kept popping up during Simon and Sanchez's conversation was that of safety.
"Sometimes when you're with your kids, you don't know whether it's appropriate to step in," Simon said. "You don't know how that person's day is going or whether it's an appropriate thing to do."
To that point, Sanchez brought up the vulnerability of the homeless population.
"By and large, it's quite the opposite," she said. "People who are homeless are generally the most vulnerable to assault. Sexual, physical or otherwise."
However, when it comes to individual safety being a concern, especially when it comes to checking for lucidity, Sanchez said "you can always say, 'it's okay to ask people how they're doing today.'"
And when kids get a little older, she advises "helping them decide when they would like to intervene and what kind of judgment they should be using."
Hey, thanks. You read the entire story. And we love you for that. Here at LAist, our goal is to cover the stories that matter to you, not advertisers. We don't have paywalls, but we do have payments (aka bills). So if you love independent, local journalism, join us. Let's make the world a better place, together. Donate now.
Every concurrency API needs a way to run code concurrently. Here's
some examples of what that looks like using different APIs:
go myfunc(); // Golang
pthread_create(&thread_id, NULL, &myfunc); /* C with POSIX threads */
spawn(modulename, myfuncname, ) % Erlang
threading.Thread(target=myfunc).start() # Python with threads
asyncio.create_task(myfunc()) # Python with asyncio
There are lots of variations in the notation and terminology, but the
semantics are the same: these all arrange for myfunc to start
running concurrently to the rest of the program, and then return
immediately so that the parent can do other things.
Another option is to use callbacks:
QObject::connect(&emitter, SIGNAL(event()), // C++ with Qt
g_signal_connect(emitter, "event", myfunc, NULL) /* C with GObject */
deferred.addCallback(myfunc) # Python with Twisted
future.add_done_callback(myfunc) # Python with asyncio
Again, the notation varies, but these all accomplish the same thing:
they arrange that from now on, if and when a certain event occurs,
then myfunc will run. Then once they've set that up, they
immediately return so the caller can do other things. (Sometimes
callbacks get dressed up with fancy helpers like promisecombinators,
or Twisted-style protocols/transports,
but the core idea is the same.)
And... that's it. Take any real-world, general-purpose concurrency
API, and you'll probably find that it falls into one or the other of
those buckets (or sometimes both, like asyncio).
But my new library Trio is weird. It
doesn't use either approach. Instead, if we want to run myfunc and
anotherfunc concurrently, we write something like:
When people first encounter this "nursery" construct, they tend to
find it confusing. Why is there an indented block? What's this
nursery object, and why do I need one before I can spawn a task?
Then they realize that it prevents them from using patterns they've
gotten used to in other frameworks, and they get really annoyed. It
feels quirky and idiosyncratic and too high-level to be a basic
primitive. These are understandable reactions! But bear with me.
In this post, I want to convince you that nurseries aren't quirky or
idiosyncratic at all, but rather a new control flow primitive that's
just as fundamental as for loops or function calls. And furthermore,
the other approaches we saw above – thread spawning and callback
registration – should be removed entirely and replaced with
Sound unlikely? Something similar has actually happened before: the
goto statement was once the king of control flow. Now it's a
punchline. A few languages still have
something they call goto, but it's different and far weaker than
the original goto. And most languages don't even have that. What
happened? This was so long ago that most people aren't familiar with
the story anymore, but it turns out to be surprisingly relevant. So
we'll start by reminding ourselves what a goto was, exactly, and
then see what it can teach us about concurrency APIs.
Let's review some history: Early computers were programmed using
assembly language, or other even
more primitive mechanisms. This kinda sucked. So in the 1950s, people
like John Backus at
IBM and Grace Hopper
at Remington Rand started to develop languages like FORTRAN and FLOW-MATIC (better known for its
direct successor COBOL).
FLOW-MATIC was very ambitious for its time. You can think of it as
Python's great-great-great-...-grandparent: the first language that
was designed for humans first, and computers second. Here's some
FLOW-MATIC code to give you a taste of what it looked like:
You'll notice that unlike modern languages, there's no if blocks,
loop blocks, or function calls here – in fact there's no block
delimiters or indentation at all. It's just a flat list of statements.
That's not because this program happens to be too short to use fancier
control syntax – it's because block syntax wasn't invented yet!
Instead, FLOW-MATIC had two options for flow control. Normally, it was
sequential, just like you'd expect: start at the top and move
downwards, one statement at a time. But if you execute a special
statement like JUMP TO, then it could directly transfer control
somewhere else. For example, statement (13) jumps back to statement
Just like for our concurrency primitives at the beginning, there was
some disagreement about what to call this "do a one-way jump"
operation. Here it's JUMP TO, but the name that stuck was goto
(like "go to", get it?), so that's what I'll use here.
Here's the complete set of goto jumps in this little program:
If you think this looks confusing, you're not alone! This style of
jump-based programming is something that FLOW-MATIC inherited pretty
much directly from assembly language. It's powerful, and a good fit to
how computer hardware actually works, but it's super confusing to work
with directly. That tangle of arrows is why the term "spaghetti code"
was invented. Clearly, we needed something better.
But... what is it about goto that causes all these problems? Why
are some control structures OK, and some not? How do we pick the good
ones? At the time, this was really unclear, and it's hard to fix a
problem if you don't understand it.
But let's hit pause on the history for a moment – everyone knows
goto was bad. What does this have to do with concurrency? Well,
consider Golang's famous go statement, used to spawn a new
"goroutine" (lightweight thread):
Can we draw a diagram of its control flow? Well, it's a little
different from either of the ones we saw above, because control
actually splits. We might draw it like:
Here the colors are intended to indicate that both paths are taken.
From the perspective of the parent goroutine (green line), control
flows sequentially: it comes in the top, and then immediately comes
out the bottom. Meanwhile, from the perspective of the child (lavender
line), control comes in the top, and then jumps over to the body of
myfunc. Unlike a regular function call, this jump is one-way: when
running myfunc we switch to a whole new stack, and the runtime
immediately forgets where we came from.
But this doesn't just apply to Golang. This is the flow control
diagram for all of the primitives we listed at the beginning of this
Threading libraries usually provide some sort of handle object that
lets you join the thread later – but this is an independent
operation that the language doesn't know anything about. The actual
thread spawning primitive has the control flow shown above.
Registering a callback is semantically equivalent to starting a
background thread that (a) blocks until some event occurs, and
then (b) runs the callback. (Though obviously the implementation is
different.) So in terms of high-level control flow, registering a
callback is essentially a go statement.
Futures and promises are the same too: when you call a function and
it returns a promise, that means it's scheduled the work to happen
in the background, and then given you a handle object to join the
work later (if you want). In terms of control flow semantics, this
is just like spawning a thread. Then you register callbacks on the
promise, so see the previous bullet point.
This same exact pattern shows up in many, many forms: the key
similarity is that in all these cases, control flow splits, with one
side doing a one-way jump and the other side returning to the caller.
Once you know what to look for, you'll start seeing it all over the
place – it's a fun game!
Annoyingly, though, there is no standard name for this category of
control flow constructs. So just like "goto statement" became the
umbrella term for all the different goto-like constructs, I'm
going to use "go statement" as a umbrella term for these. Why
go? One reason is that Golang gives us a particularly pure example
of the form. And the other is... well, you've probably guessed where
I'm going with all this. Look at these two diagrams. Notice any
That's right: go statements are a form of goto statement.
Concurrent programs are notoriously difficult to write and reason
about. So are goto-based programs. Is it possible that this might
be for some of the same reasons? In modern languages, the problems
caused by goto are largely solved. If we study how they fixed
goto, will it teach us how to make more usable concurrency APIs?
Let's find out.
In these papers, Dijkstra was worried about the problem of how you
write non-trivial software and get it correct. I can't give them due
justice here; there's all kinds of fascinating insights. For example,
you may have heard this quote:
Yep, that's from Notes on structured programming. But his major
concern was abstraction. He wanted to write programs that are too
big to hold in your head all at once. To do this, you need to treat
parts of the program like a black box – like when you see a Python
then you don't need to know all the details of how print is
implemented (string formatting, buffering, cross-platform differences,
...). You just need to know that it will somehow print the text you
give it, and then you can spend your energy thinking about whether
that's what you want to have happen at this point in your code.
Dijkstra wanted languages to support this kind of abstraction.
By this point, block syntax had been invented, and languages like
ALGOL had accumulated ~5 distinct types of control structure: they
still had sequential flow and goto:
And had also acquired variants on if/else, loops, and function calls:
You can implement these higher-level constructs using goto, and
early on, that's how people thought of them: as a convenient
shorthand. But what Dijkstra pointed out is that if you look at these
diagrams, there's a big difference between goto and the rest. For
everything except goto, flow control comes in the top → [stuff
happens] → flow control comes out the bottom. We might call this the
"black box rule": if a control structure has this shape, then in
contexts where you don't care about the details of what happens
internally, you can ignore the [stuff happens] part, and treat the
whole thing as regular sequential flow. And even better, this is also
true of any code that's composed out of those pieces. When I look at
I don't have to go read the definition of print and all its
transitive dependencies just to figure out how the control flow works.
Maybe inside print there's a loop, and inside the loop there's an
if/else, and inside the if/else there's another function call... or
maybe it's something else. It doesn't really matter: I know control
will flow into print, the function will do its thing, and then
eventually control will come back to the code I'm reading.
It may seem like this is obvious, but if you have a language with
goto – a language where functions and everything else are built on
top of goto, and goto can jump anywhere, at any time – then
these control structures aren't black boxes at all! If you have a
function, and inside the function there's a loop, and inside the loop
there's an if/else, and inside the if/else there's a goto... then
that goto could send the control anywhere it wants. Maybe control
will suddenly return from another function entirely, one you haven't
even called yet. You don't know!
And this breaks abstraction: it means that every function call is
potentially agotostatement in disguise, and the only way to
know is to keep the entire source code of your system in your head at
once. As soon as goto is in your language, you stop being able do
local reasoning about flow control. That's whygoto leads to
And now that Dijkstra understood the problem, he was able to solve it.
Here's his revolutionary proposal: we should stop thinking of
if/loops/function calls as shorthands for goto, but rather as
fundamental primitives in their own rights – and we should remove
goto entirely from our languages.
From here in 2018, this seems obvious enough. But have you seen how
programmers react when you try to take away their toys because they're
not smart enough to use them safely? Yeah, some things never change.
In 1969, this proposal was incredibly controversial. Donald Knuthdefendedgoto. People who had become experts on writing code with goto
quite reasonably resented having to basically learn how to program
again in order to express their ideas using the newer, more
constraining constructs. And of course it required building a whole
new set of languages.
Left: A traditional goto. Right: A domesticated goto, as
seen in C, C#, Golang, etc. The inability to cross function
boundaries means it can still pee on your shoes, but it probably
won't rip your face off.
In the end, modern languages are a bit less strict about this than
Dijkstra's original formulation. They'll let you break out of multiple
nested structures at once using constructs like break,
continue, or return. But fundamentally, they're all designed
around Dijkstra's idea; even these constructs that push the boundaries
do so only in strictly limited ways. In particular, functions – which
are the fundamental tool for wrapping up control flow inside a black
box – are considered inviolate. You can't break out of one
function and into another, and a return can take you out of the
current function, but no further. Whatever control flow shenanigans a
function gets up to internally, other functions don't have to care.
This even extends to goto itself. You'll find a few languages that
still have something they call goto, like C, C#, Golang, ... but
they've added heavy restrictions. At the very least, they won't let
you jump out of one function body and into another. Unless you're
working in assembly , the classic, unrestricted goto is gone.
And once goto disappeared, something interesting happened:
language designers were able to start adding features that depend on
control flow being structured.
For example, Python has some nice syntax for resource cleanup: the
with statement. You can write things like:
and it guarantees that the file will be open during the ... code,
but then closed immediately afterward. Most modern languages have some
equivalent (RAII, using, try-with-resource, defer, ...). And
they all assume that control flows in an orderly, structured way. If
we used goto to jump into the middle of our with block... what
would that even do? Is the file open or not? What if we jumped out
again, instead of exiting normally? Would the file get closed? This
feature just doesn't work in any coherent way if your language has
goto in it.
Error handling has a similar problem: when something goes wrong, what
should your code do? Often the answer is to pass the buck up the stack
to your code's caller, let them figure out how to deal with it. Modern
languages have constructs specifically to make this easier, like
exceptions, or other forms of automatic error propagation.
But your language can only provide this help if it has a stack, and
a reliable concept of "caller". Look again at the control-flow
spaghetti in our FLOW-MATIC program and imagine that in the middle of
that it tried to raise an exception. Where would it even go?
So goto – the traditional kind that ignores function boundaries –
isn't just the regular kind of bad feature, the kind that's hard to
use correctly. If it were, it might have survived – lots of bad
features have. But it's much worse.
Even if you don't use goto yourself, merely having it as an option
in your language makes everything harder to use. Whenever you start
using a third-party library, you can't treat it as a black box – you
have to go read through it all to find out which functions are regular
functions, and which ones are idiosyncratic flow control constructs in
disguise. This is a serious obstacle to local reasoning. And you lose
powerful language features like reliable resource cleanup and
automatic error propagation. Better to remove goto entirely, in
favor of control flow constructs that follow the "black box" rule.
So that's the history of goto. Now, how much of this applies to
go statements? Well... basically, all of it! The analogy turns out
to be shockingly exact.
Go statements break abstraction. Remember how we said that if our
language allows goto, then any function might be a goto in
disguise? In most concurrency frameworks, go statements cause the
exact same problem: whenever you call a function, it might or might
not spawn some background task. The function seemed to return, but is
it still running in the background? There's no way to know without
reading all its source code, transitively. When will it finish? Hard
to say. If you have go statements, then functions are no longer
black boxes with respect to control flow. In my first post on
I called this "violating causality", and found that it was the root
cause of many common, real-world issues in programs using asyncio and
Twisted, like problems with backpressure, problems with shutting down
properly, and so forth.
Go statements break automatic resource cleanup. Let's look again
at that with statement example:
Before, we said that we were "guaranteed" that the file will be open
while the ... code is running, and then closed afterwards. But
what if the ... code spawns a background task? Then our guarantee
is lost: the operations that look like they're inside the with
block might actually keep running after the with block ends, and
then crash because the file gets closed while they're still using it.
And again, you can't tell from local inspection; to know if this is
happening you have to go read the source code to all the functions
called inside the ... code.
If we want this code to work properly, we need to somehow keep track
of any background tasks, and manually arrange for the file to be
closed only when they're finished. It's doable – unless we're using
some library that doesn't provide any way to get notified when the
task is finished, which is distressingly common (e.g. because it
doesn't expose any task handle that you can join on). But even in the
best case, the unstructured control flow means the language can't help
us. We're back to implementing resource cleanup by hand, like in the
bad old days.
Go statements break error handling. Like we discussed above,
modern languages provide powerful tools like exceptions to help us
make sure that errors are detected and propagated to the right place.
But these tools depend on having a reliable concept of "the current
code's caller". As soon as you spawn a task or register a callback,
that concept is broken. As a result, every mainstream concurrency
framework I know of simply gives up. If an error occurs in a
background task, and you don't handle it manually, then the runtime
just... drops it on the floor and crosses its fingers that it wasn't
too important. If you're lucky it might print something on the
console. (The only other software I've used that thinks "print
something and keep going" is a good error handling strategy is grotty
old Fortran libraries, but here we are.) Even Rust – the language
voted Most Obsessed With Threading Correctness by its high school
class – is guilty of this. If a background thread panics, Rust
discards the error and hopes for the best.
Of course you can handle errors properly in these systems, by
carefully making sure to join every thread, or by building your own
error propagation mechanism like errbacks in Twisted
But now you're writing an ad-hoc, fragile reimplementation of the
features your language already has. You've lost useful stuff like
"tracebacks" and "debuggers". All it takes is forgetting to call
Promise.catch once and suddenly you're dropping serious errors on
the floor without even realizing. And even if you do somehow solve all
these problems, you'll still end up with two redundant systems for
doing the same thing.
Just like goto was the obvious primitive for the first practical
high-level languages, go was the obvious primitive for the first
practical concurrency frameworks: it matches how the underlying
schedulers actually work, and it's powerful enough to implement any
other concurrent flow pattern. But again like goto, it breaks
control flow abstractions, so that merely having it as an option in
your language makes everything harder to use.
The good news, though, is that these problems can all be solved:
Dijkstra showed us how! We need to:
Find a replacement for go statements that has similar power, but
follows the "black box rule",
Build that new construct into our concurrency framework as a
primitive, and don't include any form of go statement.
And that's what Trio did.
Here's the core idea: every time our control splits into multiple
concurrent paths, we want to make sure that they join up again. So for
example, if we want to do three things at the same time, our control
flow should look something like this:
Notice that this has just one arrow going in the top and one coming
out the bottom, so it follows Dijkstra's black box rule. Now, how can
we turn this sketch into a concrete language construct? There are some
existing constructs that meet this constraint, but (a) my proposal is
slightly different than all the ones I'm aware of and has advantages
over them (especially in the context of wanting to make this a
standalone primitive), and (b) the concurrency literature is vast and
complicated, and trying to pick apart all the history and tradeoffs
would totally derail the argument, so I'm going to defer that to a
separate post. Here, I'll just focus on explaining my solution. But
please be aware that I'm not claiming to have like, invented the idea
of concurrency or something, this draws inspiration from many sources,
I'm standing on the shoulders of giants, etc.
Anyway, here's how we're going to do it: first, we declare that a
parent task cannot start any child tasks unless it first creates a
place for the children to live: a nursery. It does this by opening a
nursery block; in Trio, we do this using Python's async with
Opening a nursery block automatically creates an object representing
this nursery, and the as nursery syntax assigns this object to the
variable named nursery. Then we can use the nursery object's
start_soon method to start concurrent tasks: in this case, one
task calling the function myfunc, and another calling the function
anotherfunc. Conceptually, these tasks execute inside the
nursery block. In fact, it's often convenient to think of the code
written inside the nursery block as being an initial task that's
automatically started when the block is created.
Crucially, the nursery block doesn't exit until all the tasks inside
it have exited – if the parent task reaches the end of the block
before all the children are finished, then it pauses there and waits
for them. The nursery automatically expands to hold the children.
Here's the control flow: you can see how it matches the basic pattern
we showed at the beginning of this section:
This design has a number of consequences, not all of which are
obvious. Let's think through some of them.
The fundamental problem with go statements is that when you call a
function, you don't know whether it's going to spawn some background
task that keeps running after it's finished. With nurseries, you don't
have to worry about this: any function can open a nursery and run
multiple concurrent tasks, but the function can't return until they've
all finished. So when a function does return, you know it's really
Here's a simpler primitive that would also satisfy our flow control
diagram above. It takes a list of thunks, and runs them all
But the problem with this is that you have to know up front the
complete list of tasks you're going to run, which isn't always true.
For example, server programs generally have accept loops, that
take incoming connections and start a new task to handle each of them.
Here's a minimal accept loop in Trio:
With nurseries, this is trivial, but implementing it using
run_concurrently would be much more awkward. And if you wanted
to, it would be easy to implement run_concurrently on top of
nurseries – but it's not really necessary, since in the simple cases
run_concurrently can handle, the nursery notation is just as
The nursery object also gives us an escape hatch. What if you really
do need to write a function that spawns a background task, where the
background task outlives the function itself? Easy: pass the function
a nursery object. There's no rule that only the code directly inside
the async with open_nursery() block can call
nursery.start_soon – so long as the nursery block remains open
, then anyone who acquires a reference to the nursery object gets
the capability of spawning tasks into that nursery. You can pass it in
as a function argument, send it through a queue, whatever.
In practice, this means that you can write functions that "break the
rules", but within limits:
Since nursery objects have to be passed around explicitly, you can
immediately identify which functions violate normal flow control by
looking at their call sites, so local reasoning is still possible.
Any tasks the function spawns are still bound by the lifetime of the
nursery that was passed in.
And the calling code can only pass in nursery objects that it itself
has access to.
So this is still very different from the traditional model where any
code can at any moment spawn a background task with unbounded
One place this is useful is in the proof that nurseries have
equivalent expressive power to go statements, but this post is
already long enough so I'll leave that for another day.
The standard nursery semantics provide a solid foundation, but
sometimes you want something different. Perhaps you're envious of
Erlang and its supervisors, and want to define a nursery-like class
that handles exceptions by restarting the child task. That's totally
possible, and to your users, it'll look just like a regular nursery:
If you have a function that takes a nursery as an argument, then you
can pass it one of these instead to control the error-handling policy
for the tasks it spawns. Pretty nifty. But there is one subtlety here
that pushes Trio towards different conventions than asyncio or some
other libraries: it means that start_soon has to take a function,
not a coroutine object or a Future. (You can call a function
multiple times, but there's no way to restart a coroutine object or a
Future.) I think this is the better convention anyway for a number
of reasons (especially since Trio doesn't even have Futures!),
but still, worth mentioning.
It's also worth talking about how task cancellation and task joining
interact, since there are some subtleties here that could – if handled
incorrectly – break the nursery invariants.
In Trio, it's possible for code to receive a cancellation request at
any time. After a cancellation is requested, then the next time the
code executes a "checkpoint" operation (details),
a Cancelled exception is raised. This means that there's a gap
between when a cancellation is requested and when it actually
happens – it might be a while before the task executes a checkpoint,
and then after that the exception has to unwind the stack, run cleanup
handlers, etc. When this happens, the nursery always waits for the
full cleanup to happen. We never terminate a task without giving it
a chance to run cleanup handlers, and we never leave a task to run
unsupervised outside of the nursery, even if it's in the process of
Because nurseries follow the black box rule, they make with blocks
work again. There's no chance that, say, closing a file at the end of
a with block will accidentally break a background task that's
still using that file.
As noted above, in most concurrency systems, unhandled errors in
background tasks are simply discarded. There's literally nothing else
to do with them.
In Trio, since every task lives inside a nursery, and every nursery is
part of a parent task, and parent tasks are required to wait for the
tasks inside the nursery... we do have something we can do with
unhandled errors. If a background task terminates with an exception,
we can rethrow it in the parent task. The intuition here is that a
nursery is something like a "concurrent call" primitive: we can think
of our example above as calling myfunc and anotherfunc at the
same time, so our call stack has become a tree. And exceptions
propagate up this call tree towards the root, just like they propagate
up a regular call stack.
There is one subtlety here though: when we re-raise an exception in
the parent task, it will start propagating in the parent task.
Generally, that means that the parent task will exit the nursery
block. But we've already said that the parent task cannot leave the
nursery block while there are still child tasks running. So what do we
The answer is that when an unhandled exception occurs in a child, Trio
immediately cancels all the other tasks in the same nursery, and then
waits for them to finish before re-raising the exception. The
intuition here is that exceptions cause the stack to unwind, and if we
want to unwind past a branch point in our stack tree, we need to
unwind the other branches, by cancelling them.
This does mean though that if you want to implement nurseries in your
language, you may need some kind of integration between the nursery
code and your cancellation system. This might be tricky if you're
using a language like C# or Golang where cancellation is usually
managed through manual object passing and convention, or (even worse)
one that doesn't have a generic cancellation mechanism.
Eliminating goto allowed previous language designers to make
stronger assumptions about the structure of programs, which enabled
new features like with blocks and exceptions; eliminating go
statements has a similar effect. For example:
Trio's cancellation system is easier to use and more reliable than
competitors, because it can assume that tasks are nested in a
regular tree structure; see Timeouts and cancellation for humans
for a full discussion.
Trio is the only Python concurrency library where control-C works
the way Python developers expect (details).
This would be impossible without nurseries providing a reliable
mechanism for propagating exceptions.
So that's the theory. How's it work in practice?
Well... that's an empirical question: you should try it and find out!
But seriously, we just won't know for sure until lots of people have
pounded on it. At this point I'm pretty confident that the foundation
is sound, but maybe we'll realize we need to make some tweaks, like
how the early structured programming advocates eventually backed off
from eliminating break and continue.
And if you're an experienced concurrent programmer who's just learning
Trio, then you should expect to find it a bit rocky at times. You'll
have to learn new ways to do things
– just like programmers in the 1970s found it challenging to learn how
to write code without goto.
But of course, that's the point. As Knuth wrote (Knuth,
Probably the worst mistake any one can make with respect to the
subject of go to statements is to assume that "structured
programming" is achieved by writing programs as we always have and
then eliminating the go to's. Most go to's shouldn't be
there in the first place! What we really want is to conceive of our
program in such a way that we rarely even think about go to
statements, because the real need for them hardly ever arises. The
language in which we express our ideas has a strong influence on
our thought processes. Therefore, Dijkstra asks for more new
language features – structures which encourage clear thinking – in
order to avoid the go to's temptations towards complications.
And so far, that's been my experience with using nurseries: they
encourage clear thinking. They lead to designs that are more robust,
easier to use, and just better all around. And the limitations
actually make it easier to solve problems, because you spend less time
being tempted towards unnecessary complications. Using Trio has, in a
very real sense, taught me to be a better programmer.
For example, consider the Happy Eyeballs algorithm (RFC 8305), which is a simple
concurrent algorithm for speeding up the establishment of TCP
connections. Conceptually, the algorithm isn't complicated – you race
several connection attempts against each other, with a staggered start
to avoid overloading the network. But if you look at Twisted's best
it's almost 600 lines of Python, and still has at least one logic
bug. The equivalent in
Trio is more than 15x shorter. More importantly, using Trio I was
able to write it in minutes instead of months, and I got the logic
correct on my first try. I never could have done this in any other
framework, even ones where I have much more experience. For more
details, you can watch my talk at Pyninsula last month. Is this typical?
Time will tell. But it's certainly promising.
The popular concurrency primitives – go statements, thread
spawning functions, callbacks, futures, promises, ... they're all
variants on goto, in theory and in practice. And not even the
modern domesticated goto, but the old-testament fire-and-brimstone
goto, that could leap across function boundaries. These primitives
are dangerous even if we don't use them directly, because they
undermine our ability to reason about control flow and compose complex
systems out of abstract modular parts, and they interfere with useful
language features like automatic resource cleanup and error
propagation. Therefore, like goto, they have no place in a modern
Nurseries provide a safe and convenient alternative that preserves the
full power of your language, enables powerful new features (as
demonstrated by Trio's cancellation scopes and control-C handling),
and can produce dramatic improvements in readability, productivity,
Unfortunately, to fully capture these benefits, we do need to remove
the old primitives entirely, and this probably requires building new
concurrency frameworks from scratch – just like eliminating goto
required designing new languages. But as impressive as FLOW-MATIC was
for its time, most of us are glad that we've upgraded to something
better. I don't think we'll regret switching to nurseries either, and
Trio demonstrates that this is a viable design for practical,
general-purpose concurrency frameworks.