yaymukund’s weblog ^_^

I decided to catalogue examples of engineers— primarily software developers— being asked to change a name to avoid being racist, sexist, transphobic, ableist, or otherwise bigoted. About half of these examples come from responses to my AskMetaFilter question.

Note: This list is not any sort of exhaustive or representative sample. I offer it as a starting point for anyone interested in reading more perspectives. If you find any links that should be added, please don't hesitate to send me an email.



There's a TON of 2020 Pull Requests about this, so I am going to pick some of them.

2020

In Jon Gjengset's Demystifying Unsafe Code talk at Rust NYC, he gives a very interesting example of unsafe code. Here's the link— please go and watch it— but I've transcribed it here along with my paraphrased explanation.

impl<T> Vec<T> {
  /// apply `f` to every element of `us`, and extend `self`
  /// with the result. for example:
  ///
  /// names.extend_map([user1, user2], |u| u.name())
  ///
  fn extend_map<U, F>(&mut self, us: &[U], mut f: F)
  where F: FnMut(&U) -> T {
    // reserve capacity in the Vec all at once, for perf (?)
    self.reserve(us.len());

    // set the length() manually.
    let cur_len = self.len();
    unsafe { self.set_len(cur_len + us.len()) };

    // insert the items by writing to the memory location
    let into = unsafe { self.as_mut_ptr().add(cur_len) };
    for u in us {
      unsafe { std::ptr::write(into, f(u)) }; into += 1;
    }
  }
}

If f panics, then Rust will unwind the stack and drop every item in Vec before dropping the Vec itself. However, since you've unsafely set its length with set_len(), it will try to call drop on array indices that you haven't written to yet! In other words, it will just call garbage memory. Apparently, this is why it can be challenging to write Vec::drain() implementations.

A Few Things Like These (Ippatiyum Cila Vicayankal)

Among birds, I like crows very much.
It's true; it is a thieving creature
tactfully snatching away the eats from the hands of children.
In deed, it is a foolish creature
visiting and perching on the compound wall of the house
and caws at the oddest hours.
Even then
isn't it my friend
who looks at me and calls out to me
in my village where I crawled as a baby and grew up
and also in this city planted from elsewhere?

— Cinnakkapali (Translated by Nirmal Selvamony)

There were three or four crows standing on a branch in the trees outside our balcony, so this poem feels very timely.

Source: Oikopoetrics and Tamil Poetry by Nirmal Selvanomy

Later, I Learned to Speak Without a Tongue

But first I wrote backwards.
First I learned to breathe without my throat.

Once, my teeth chattered alphabets and people sat in rows
to hear me speak.

Later I wrote on paper and the paper cut itself to emptiness.
Later I sat alone in the pew.

Once I chanted into the empty nests of finches.
Once a cathedral grew in the meadow,

crowns of flowers on the skulls of deer.
Before that I had children.

After that, everything I loved became a hole.
I lay down and shouted names into the dirt.

After that, eyes grew upon my heart and all those eyes
grew hearts and all those hearts eyes and hearts and eyes

were trapped inside me in the dark. Later the children will
come back and we'll swim moonlit in the river.

Later, an emptiness will swallow me and whole.
After that I will turn to grass.

— Lisa Allen Ortiz

I love this poem. The surreal imagery ("my teeth chattered alphabets", "skulls of deer") contrasts with her plain, almost boring, sentence structure (First this. Then that. Once this). She also speaks with absolute certainty, describing only what did or will happen. The resulting poem sounds like a recipe or a witness statement, but what is she recounting?

Sleeping Alone

Listening
to the neighbor's dog
bark
and bark.
He must
be very big,
his mouth as big
as my head,
his head
as big
as a Macy's Day float,
his corridor throat
commanding me
to hear:
I am one
dog
in the lonely bowl
of night
and there
is so
much
dark.

— Amy Miller, 2018

I want to hug a dog.

How to spy on your Rust code

In the following code, how can you test that Player is making the correct API calls?

struct Player<'a> {
  api: &'a Api,
}

impl<'a> Player<'a> {
  pub fn new(api: &'a Api) -> Player<'a> {
    Player { api }
  }

  pub fn play(&self, song: &str) {
    self.api.sing(song);
  }

  pub fn stop(&self) {
    self.api.shush();
  }
}

The answer? Make it generic!

struct Player<'a, T> {
  api: &'a T,
}

impl<'a, T> Player<'a, T>
where
  T: PlayerApi,
{
  pub fn new(api: &'a T) -> Player<'a, T> {
    Player { api }
  }

  // ...
}

trait PlayerApi {
  // Default trait implementation uses `Api`
  fn sing(&self, url: &str);
  fn shush(&self);
}

impl PlayerApi for Api {
  fn sing(&self, url: &str) {
    Api::sing(self, url)
  }

  fn shush(&self) {
    Api::shush(self)
  }
}

Then you can easily spy on it:

#[cfg(test)]
module Test {
  struct ApiSpy {
    pub invocations: Vec<String>,
    api: Api,
  }

  impl ApiSpy {
    pub fn new() -> ApiSpy {
      ApiSpy { api: Api::New() }
    }
  }

  impl PlayerApi for ApiSpy {
    fn sing(&self, url: &str) {
      self.invocations.push('play');
      self.api.sing(url)
    }
  }

  #[test]
  fn test_play() {
    let api = ApiMock::new();
    let player = Player::new(&api);
    player.play("my_url");
    assert_eq!(api.invocations[0], "play");
  }
}

That's it!

How can I assert that I passed the correct arguments?

You can store the arguments in the ApiSpy. For example, here's how I mocked the mpv api and used it in a test.

I don't want to define a trait for my API just for tests!

Defining a trait for your external APIs is good for reasons beyond testing. But if you still still don't want to make your API generic, then you could use conditional compilation instead..

What if I don't want to execute API code in tests?

If you want to mock instead of spy, you have a couple options:

Wireless printers on swaywm

Here's how you add a wireless printer to Sway. You'll need the following tools:

  1. CUPS, the "standards-based, open source printing system"
  2. Avahi for wireless support
  3. nss-mdns, so we can refer to the printer as <hostname>.local (e.g. myprinter.local)
# Install the packages
$ yay -S cups avahi nss-mdns

# Start the cups service
$ systemctl start org.cups.cupsd.service

# Ensure you can see the CUPS web interface at localhost:631

# Start the Avahi daemon
$ systemctl start avahi-daemon.service

Now, enable hostname resolution in Avahi by following the instructions on the Arch Wiki.

# Find the printer on the local network
$ sudo lpinfo —include-schemes dnssd -v

# You should see something like:
# network dnssd://Canon%20MG5700%20series._ipp._tcp.local/?uuid=<some uuid>

# Add the printer to CUPS
$ sudo lpadmin \
  -p short-name-eg-canon-md5750 \
  -D "Full Name (e.g. 'Canon MG5750 Laserjet')" \
  -L "Location (e.g. 'Living Room') (Optional)" \
  -v dnssd://Canon%20MG5700...

If you did everything right so far, you should be able to see the printer in the CUPS web interface (localhost:631). If you click on the printer's name, it should say "Idle, Accepting Jobs."

Now, you can try to print your document. You can track your print job from the CUPS web interface. If something goes wrong, you can see the error there.

Bonus! Add custom printer drivers

To access advanced features of your printer, you may need to install a custom driver. First, find the relevant drivers by searching the AUR for your printer model. For me, it was the cnijfilter2-mg7700 package.

Once you've done that, tell CUPS to assign the custom driver to the printer:

# Find the driver's ppd file
$ lpinfo -m
# It will be something like lsb/usr/canonmg5700.ppd

# And assign it in CUPS
$ sudo lpadmin -p canon-md5750 -m lsb/usr/canonmg5700.ppd

That's it!

Troubleshooting

My printer in CUPS is listed as disabled or not accepting new jobs

Make sure you run:

$ sudo cupsenable $short_name
$ sudo cupsaccept $short_name

You may be able to do this from the web interface, but I was getting permission denied errors.

My print job fails because it can't find ghostscript

You need to install ghostscript. In Arch, it's just yay -S ghostscript.

References

By translating these poems, we aim to memorialize Xu, share some of his excellent literary work, and spread awareness that the harsh conditions, struggles and aspirations of Chinese migrant workers (including but not limited to Foxconn) have not diminished since the more widely-publicized spate of 18 attempted Foxconn suicides in 2010, resulting in 14 deaths. Insiders report that thereafter, although the frequency of suicides decreased (mainly due to Foxconn's installation of nets making it more difficult for workers to jump from their dormitories, along with the development of workers' collective resistance), such suicides have continued to the present. Including Xu Lizhi, at least 8 cases have been reported in the media since 2010, but insiders say that many other cases go unreported. We hope that in the future, workers in Foxconn and elsewhere manage to find ways around such companies' military-style discipline and surveillance, come together, and forge collective paths out of this capitalist world of death, into a world worth living in. Don't give up!

Source: libcom.org/blog/xulizhi-foxconn-suicide-poetry

On My Deathbed

I want to take another look at the ocean, behold the vastness of tears from half a lifetime
I want to climb another mountain, try to call back the soul that I’ve lost
I want to touch the sky, feel that blueness so light
But I can’t do any of this, so I’m leaving this world
Everyone who’s heard of me
Shouldn’t be surprised at my leaving
Even less should you sigh or grieve
I was fine when I came, and fine when I left.

— Xu Lizhi, 30 September 2014

Looking to keep the [Soviet—Afghan] war fueled, Washington— where the prevailing ethos was to bleed the Russians until the last Afghan— financed textbooks for schoolchildren in refugee camps that were festooned with illustrations of Kalashnikovs, swords, and overturned tanks. One such edition declared: "Jihad is a kind of war that Muslims fight in the name of God to free Muslims... If infidels invade, jihad is the obligation of every Muslim." An American text designed to teach children the Farsi alphabet began

Aleph [is for] Allah; Allah is one

Bey [is for] Baba (father); Father goes to the mosque

Tey [is for] Tofang (rifle); Javed obtains rifles for the mujahedeen

Jeem [is for] Jihad; Jihad is an obligation. My mom went to the jihad.

No Good Men Among The Living (2014) by Anand Gopal

One result of all the outside attention was the 2004 constitution [of Afghanistan], drafted with heavy Western input and hailed as one of the world's most progressive. In addition to protecting basic civil liberties and minority rights, the document guaranteed women 25 percent of parliamentary seats (surpassing the proportion in the US Congress).

No Good Men Among The Living (2014) by Anand Gopal