Journalist/developer. Interactive editor @frontlinepbs. Builder of @HomicideWatch. Sinophile for fun. Past: @WBUR, @NPR, @NewsHour.
1608 stories

One Brother Stabbed the Other. The Journalist Who Wrote About It Paid a Price.

1 Share

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.)

Read the whole story
22 days ago
Boston, MA
Share this story

Eighteen is History

1 Share
Eighteen is History

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.

Last year, Seventeen is (Almost) Just Another Day

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.

Two years ago, Sixteen is Letting Go Again

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.

Three years ago, Fifteen is the Past:

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.

In 2015, Fourteen is Remembering:

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.

In 2014, Thirteen is Understanding:

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.

From 2013, Twelve is Trying:

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.

In 2012, Eleven is What We Make:

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.

In 2011 for the 10th anniversary, Ten is Love and Everything After:

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.

In 2010, Nine is New New York:

[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.

In 2009, Eight Is Starting Over:

[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.

In 2008, Seven Is Angry:

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.

In 2007, Six Is Letting Go:

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.

In 2006, After Five Years, Failure:

[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.

In 2005, Four Years:

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.

In 2004, Thinking Of You:

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.

In 2003, Two Years:

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.

In 2002, I wrote On Being An American:

[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.

In 2001, Thank You:

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.

Read the whole story
23 days ago
Boston, MA
Share this story

At Boston Public Schools, even the city’s most politically connected can get the runaround

1 Comment

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.”

James Vaznis can be reached at Follow him on Twitter @globevaznis.

Read the whole story
27 days ago
News from the neighborhood.
Boston, MA
Share this story

There’s Hope for Local Journalism

1 Share

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 Prospect by 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.

Hang gliders over the Cape Cod National Seashore (Courtesy of Edward Miller).

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 approach they decided on—which you can read about on the Independent’s own site, or by Allison Hagan in The Boston Globe and  Sarah Mizes-Tan for the local public radio station WCAI—was a mix of normal for-profit business structure, and non-profit adjunct.

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.

August Carnival parade in Provincetown (Courtesy of Marcia Geier)

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.”

Cape Cod in the summertime (Courtesy of Elspeth Hay)

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.

Louis Black speaks during the 36th Annual Austin Music Awards (Gary Miller / Getty)

“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.”

More from this series

Read the whole story
27 days ago
Boston, MA
Share this story

How Do I Talk To Kids About Homelessness?: LAist

1 Comment


Take a look at our homepage any day, and you're likely to come across a story about homelessness — from efforts to house people, to health standards for homeless shelters to the rise of children who are homeless.

But those stories are written for adults.

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?"

Here's how.


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.


"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."

LA Explained: Homelessness


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.


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.


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.

Read the whole story
29 days ago
This was LAist/KPCC's 500th story from their Hearken collaboration.
Boston, MA
Share this story

Go statement considered harmful — njs blog

1 Share

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
                 &receiver, SLOT(myfunc()))

g_signal_connect(emitter, "event", myfunc, NULL)   /* C with GObject */

document.getElementById("myid").onclick = myfunc;  // Javascript

promise.then(myfunc, errorhandler)                 // Javascript with Promises

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 promise combinators, 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:

async with trio.open_nursery() as nursery:

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 nurseries.

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 (2):

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 post:

  • 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 similarities?

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.

So what is it about goto that makes it cause so many problems? In the late 1960s, Edsger W. Dijkstra wrote a pair of now-famous papers that helped make this much clearer: Go to statement considered harmful, and Notes on structured programming (PDF).

goto: the destroyer of abstraction

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:

Testing can be used to show the presence of bugs, but never to show their absence!

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 program do:

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 this code:

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 a goto statement 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 why goto leads to spaghetti code.

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 Knuth defended goto. 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.

On the left, a photo of a snarling wolf. On the right, a photo of a grumpy bulldog.

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. Dijkstra won.

A surprise benefit: removing goto statements enables new features

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:

# Python
with open("my-file") as file_handle:

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?

goto statements: not even once

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 concurrency APIs, 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:

# Python
with open("my-file") as file_handle:

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 or Promise.catch in Javascript. 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.

go statements: not even once

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 syntax:

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.

Nurseries preserve the function abstraction.

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 done.

Nurseries support dynamic task spawning.

Here's a simpler primitive that would also satisfy our flow control diagram above. It takes a list of thunks, and runs them all concurrently:

run_concurrently([myfunc, anotherfunc])

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:

async with trio.open_nursery() as nursery:
    while True:
        incoming_connection = await server_socket.accept()
        nursery.start_soon(connection_handler, incoming_connection)

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 readable.

There is an escape.

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 lifetime.

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.

You can define new types that quack like a nursery.

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:

async with my_supervisor_library.open_supervisor() as nursery_alike:

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.

No, really, nurseries always wait for the tasks inside to exit.

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 being cancelled.

Automatic resource cleanup works.

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.

Automated error propagation works.

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 do?

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.

A surprise benefit: removing go statements enables new features

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, 1974, p. 275):

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 implementation, 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 high-level language.

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, and correctness.

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.

Read the whole story
29 days ago
Boston, MA
Share this story
Next Page of Stories