&https://dpb.bitbucket.io/2017-08-14T12:53:00-04:00John Holt's Instead of Education (1976)2017-08-14T12:53:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2017-08-14:john-holt-instead-of-education-1976.html<p>A couple of months ago I read John Holt's <em>Instead of Education: Ways to help people do things better</em> (1976; Boulder: Sentient Publications, LLC, 2004). My reactions:</p>
<p><strong>Interesting ideas</strong></p>
<p><strong>Escape</strong>. I like the last line of the book: "Let all those escape [compulsory schooling] who can, any way they can" (p. 222). That has worked for me, and I'm in favor of it for others. Holt also proposes "a new Underground Railroad, to help children escape from S-chools" (p. 218). At the same time, I'm not sure I believe my own meandering development up to this point can or should be replicated closely.</p>
<p><strong>Coercion</strong>. some sections of Chapter 3 ("Nothing to Do with Gerbils", "Nothing to Do with Rules", pp. 20-22) show a subtle point that had not been evident to me from presentations I had read of his thought. He is opposed to coercion in the matter of whether or not you go to school, but not necessarily within a school once you go. It's an interesting distinction. </p>
<p>Holt praises as "s-chool" (the good kind of school) certain kinds of institutions that he says are "very tightly and rigidly structured," imposing "the most intense and inflexible discipline," and "demanding, intensive, formal, and tightly organized." At such places, including martial arts schools and dance schools, "the discipline is exact and intense." Perhaps amazingly, "as long as [students] stay in the class, they have no choices at all." Again, these are among the kind of school he approves of.</p>
<p>Holt's key objection to "S-chools" (the bad kind of school) is not that instruction is inflexible and denies students choice; he is concerned with "the degree to which the students are <em>free to choose</em> to spend their time with [the teacher] or not, do what he is doing, use his help, listen to and accept or reject his ideas." Holt wants students to be able to choose to, or not to, go to a school — how the school or the teacher chooses to run the curriculum seems to be the school or the teacher's business, and if you don't like it, you should be free to leave.</p>
<p>He writes: "The difference between s-chools and S-chools has nothing whatever to do with pedagogy, with philosophies of education, ways of teaching, curricula, materials, and so forth. … The only choice society offer[s students is], go to this school or some other school. Any school which is part of such a system of coercion is a S-chool."</p>
<p><strong>Guidance</strong>. In Chapter 7, he describes "the true t-eacher, the master": As he sharpens the student's movements, he sharpens the criteria by which the student will later judge and correct his own movements. The true master does not want to make the student into a slave or puppet, but into a new master. He is not a behavior modifier. He does not move the student by imperceptible steps toward an end which only he, the master, can see. He seeks instead to give the student greater control of his own behavior, so that he may move himself toward his own ends..." (p. 58).</p>
<p>I like that "master" recalls the master-apprentice relationship, although elsewhere Holt says that some excellent teachers are not themselves masters of what they teach.</p>
<p><strong>Teacherless textbooks</strong>. He has some thoughts about an idea that has motivated me for a long time: how do I enable independent learners to get training in subjects in which I have proficiency but that I may never have a chance to teach them in person? </p>
<p>In Chapter 7, Section "Feedback without a Teacher," Holt asserts "it must always be the first and central task of any teacher to help the student become independent of him, to learn to be his own teacher. The true teacher must always be trying to work himself out of a job." (p. 66)</p>
<p>Chapter 8: "I was once very interested in the idea of teacherless textbooks, particularly in Math. Math teachers seemed so unable to answer most students' questions that I thought, why can't we have a textbook that will answer them?" (p. 87). He concludes that "[we would] have to explain the explanations, and then explain them, and so on. The reason why the human t-eacher is at best so infinitely quicker and more flexible than a book or machine, is that with a t-eacher (but not a T-eacher) the student can begin with what he knows and what he wants to find out. He can ask the question <em>he</em> wants, and if the answer is not clear, do whatever he needs to do to make it clear" (p. 87).</p>
<p>I like that he considered the idea, but his argument against it seems to me both weak and dogmatic. There is such a thing as doing a good job that is nonetheless not perfect, but it is still a good job. </p>
<p><strong>Mutual feedback</strong>. "People very often work more effectively in a group. Not all people, not always, and not for all kinds of work. Some people are loners and some work, like writing, is usually best done alone. But much of the time people can do far more working with others than they could all by themselves. They give each other a sort of collective feedback. These children knew or sensed that it was highly probably that any of their answers was right if they all agreed on it. Not that they were democrats, believing that the voice of the people is the voice of God; like all young children, they were aristocrats and anarchists. But they had all learned from experience that it was very unlikely, if a mistake had been made, that they would all make and agree on the same mistake." (p. 103).</p>
<p><strong>The school [Ny Lilleskole] tries not to decide things on the basis of close votes; people look instead for solutions with which everyone or nearly everyone can agree.</strong> (p. 126)</p>
<p><strong>Ivan Illich</strong>. The one book of Illich's that I've read is full of polemic and misinformation, and my opinion of him has been bad because of it. But Holt has an account of one pedagogical idea of Illich's that seems clear-headed to me.</p>
<p>Holt begins by describing an idea he considers mistaken: "The teacher has infinite obligations to the student and the students in return no obligations at all. … The teacher is expected to be infinitely available, and to respond with utmost sympathy and understanding to all the needs of the students. But he cannot make any demands on them. Their needs count, his don't. The students need not come to class, but should they feel like coming the teacher must be there. The students need not read a book, but should they feel like discussing one the teacher should have read it, and if not should immediately read it. The students have a right to withdraw from or reject any discussion that does not interest them. The teacher has no such right.</p>
<p>"When I first went to [Centro Intercultural de Documentación (CIDOC), Illich's 'de-Yankeefication' school in Mexico] and met Illich, some such ideas were in my mind. In our earliest talks I was surprised at how strongly he resisted the idea of what was then called informal teaching, and defended instead the old-fashioned schoolmaster. Later I was surprised again by the passion with which he argued against free schools. Most puzzling of all was his fear that what people were beginning to call the deschooling of society might simply produce a society that was itself a universal or perpetual school, or his remark that a global schoolhouse would be like a global madhouse or a global prison.</p>
<p>"On my second or third visit to CIDOC, he told me a perplexing story. He said that after one of his talks in the U.S. someone in the audience began to criticize him sharply for not having made clear something he had been trying to say. After a while Illich interrupted him, and said with great force, 'Please sit down! I am <em>not</em> your teacher!' He told me this as if it were important that I understand it, and as if understanding it would make clear what in a larger sense he was saying about education and teaching. But it was still some time before I began to see what he meant.</p>
<p>"Only as I began to make in my own mind the distinction between doing and education, or between S-chools and s-chools, and T-eachers and teachers, did I begin to understand the passion with which Illich told the questioner that he was not his teacher. He was saying, in effect, 'I have not <em>agreed</em> to be your teacher, and there for am not responsible for your understanding or failing to understand anything I may say. If you want me to be your teacher, to accept a responsibility for making you learn or understand something, you must ask me. Even then I will only agree if I feel fairly certain that I <em>can</em> in fact teach you or help you understand. If I think I can, I will set forth the conditions, the mutual responsibilities and obligations under which I will agree to teach you. If you wish to accept them, you may. Otherwise, I accept no responsibility for making you understand, or blame if you do not. We are not talking here as teacher and pupil, <em>but as equals</em>, and not understanding each other is one of the risks of all such conversations.'</p>
<p>"It is important to understand here that Illich is saying, first of all, that the proper relationship of teacher to student is not one of equals. The student, while he is in that relationship, is in some ways (but not all) an inferior; he acknowledges and accepts that. Beyond that, Illich is saying most emphatically that not all things can be taught. … One of Illich's deepest criticisms of S-chools and S-chool people is that they do not even know or admit the distinction between what can be taught and what can not, what is not learned <em>by</em> being 'taught.'" (pp. 107-9)</p>
<p>How much of this is Holt and how much Illich I won't guess.</p>
<hr />
<p><strong>Irritations</strong></p>
<p>Much of the book has to do with things Holt doesn't like about society, especially but not only in relation to education. Almost all of that is polemical, familiar, and uninspiring. He goes long on truisms and anecdote, and it's dull. I no longer have the patience to read theories on how to solve the problems of society. Instead, I'm interested in effective strategies by which people can obtain proficiency in various skills. </p>
<p>There are some interesting ideas in the book, but I am put off when I find Holt returning over and over to dogmatic statements about the kinds of schools and teachers he disapproves of. He has a "tone issue" that makes my irritation fuller: he distinguishes between "s-chool" (his word for the sort of educational organization he approves of) and "S-chool" (the sort he does not). There is a similar distinction between "t-eacher" (approved of) and "T-eacher" (not). He also writes "do-er" and "do-ing", I suppose in hope of making me see these words with fresh eyes. But after seeing for the tenth time, I am revulsed and feel the author is talking down to me.</p>
<hr />
<p><strong>Miscellaneous inanities</strong></p>
<p>In Chapter 5, he suggests that in small towns without good libraries, people "are forced into the passive amusement of watching TV. There is very little else for them to do" (p. 40). By that reasoning, people in big cities today should spend relatively little of their time on social media. But I'll bet the numbers are about the same for big cities and small towns.</p>
<p>P. 59: "Reading, unlike dancing, is not a muscular act." I do not agree with that. Maybe it is an easier process to master by oneself, but "automaticity" is the key — reading is not about decipherment but about training one's mind to perform the act accurately and without the need for conscious control. Holt seems to have an opinion I don't understand about the intrinsic difference between different subjects, in terms of their learnability. It comes up also in the last paragraph I quoted about Illich.</p>
<p>P. 205: "A teacher who does not use fear and does not need to use it, who makes his students less afraid, <em>and so make them harder for others to make afraid</em>, threatens every other teacher in the S-chool." I've seen teachers who use fear and teachers who do not use fear coexist peacefully and respect each other. I think this is a case (one of many) where Holt is in a rage and says things that are not sound.</p>
<p>P. 165: "Modern work is moronic, not by accident, but by design." Well, U.S. society is soon going to have to find something to do with tens of millions of people who are only good for doing moronic work and have been superannuated by technology. That's by design? It's going to be a political nightmare.</p>
<p>P. 78: "In S-chool talk, 'guidance' means being told what to do. When someone asks, 'Don't children need guidance?' he is not asking if children need advice — which in fact they do need and seek out. He is saying that children need, everywhere, always to be told what to do. The 'guide' is the person who tells them. So the word 'guide' loses its proper meanings, and we lose our sense of the ways in which one person really can guide, and so help, another." I've been to S-chools my whole l-ife. There was plenty of true guidance everywhere. Even rigid teachers who relied on fear were able to give genuine guidance to all sorts of students, one on one or in small groups. I think this is more petulant generalization on Holt's part. Really, this writer needs a strong editor.</p>
<p>In a lot of the book (as above) I hear him as primarily angry. What he writes in that state is not enlightening for me to read.</p>
<p>[end]</p>John Holt on learning in mid-life and the role of the teacher (1978)2017-06-25T20:35:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2017-06-25:john-holt-on-learning-in-mid-life-1978.html<p><em>Never Too Late</em> (Reading, Massachusetts: Addison-Wesley, 1978; <a href="https://archive.org/stream/NeverTooLate-JohnHolt/nevertoolate_djvu.txt">full text found on-line</a>, 20170625) is a memoir by John Holt (1923–85) of his experiences learning in mid-life to perform music, without much background. Holt’s best-known books are from the mid-sixties and deal with teaching small children. This book, on the other hand, is squarely about the adult learner.</p>
<p>A lot of the text rather rambles, but below I provide extracts of what seem to me the finest parts.</p>
<p>This book narrates Holt’s various encounters with music, from childhood onward, with some philosophizing on independent learning. The two most important tales feature the flute and the cello. Holt took up the flute in his mid-thirties and then set it down again a couple of years later. At forty — the same time he wrote his first book — he took up the cello and by the time of this book he had been at it for thirteen years.</p>
<p>Chapter 10 and the Epilogue (only) are good enough that I sense they could stand alone.</p>
<p>Chapter 10 (pp. 187-217) deals at discursive length with mental habits of self-reproach (“crippling and self-destructive thoughts”, p. 194) by learners. The Epilogue, “Clearing a Space” (pp. 234-42), deals most directly with the difficulties a learner in mid-life and later has in mastering a new skill. Much of the matter from Chapters 2 to 9 meanders among unfocused recollections about music in his life (“I never heard any of [my father’s brothers or sisters] sing, hum, or whistle, any part of a song or tune”, p. 20), although there are gems here and there.</p>
<p>There is a nod or two to Holt’s best-known advocacy, educational reform:</p>
<blockquote>
<p>For many years, with many others, I tried to make schools more kindly, interesting, competent, and serious. It now seems clear that in the near future this will not happen, mostly because there are so few people, in or out of schools, who want it to happen. To those few people who can’t stand what schools are doing to their children, I now urge that they look for ways to take their children out altogether and have them learn at home. (p. 240-41)</p>
<p>This work of deinstitutionalizing people and society now seems to me perhaps the most fundamental and important political task of our times. (p. 183)</p>
</blockquote>
<p>But the value of the book is in Holt’s reflections on his own difficulties in learning, outside of an institution — self-directedly, as an adult. </p>
<hr />
<p><strong>Difficulties in learning</strong> </p>
<p>Midway through the book Holt offers an autopsy of his failure to progress with the flute (“Not Ready Yet”, pp. 133-35). He lists six issues that were mostly resolved by the time he turned to the cello (below I name them in my own words). Three of them are relatively simple:</p>
<ul>
<li>
<p><strong>Physical exertion.</strong> Playing the flute “gave me no way to discharge in physical energy the tensions I felt in trying to play it” (p. 134) — it did not release as much tension as he needed it to. He says elsewhere that “music is athletics, a sport more difficult and fascinating than any I have ever played” (p. 237).</p>
</li>
<li>
<p><strong>Poor “mental model”</strong> of what flute music should sound like. Holt fixed this by listening thoughtfully to a lot of music.</p>
</li>
<li>
<p><strong>Collaboration.</strong> “I did not play enough with other people.” But Chapters 1 and 11 contain chatty, readable descriptions of musicians’ interactions, and it seems that by the time he came to the cello, Holt had learned to appreciate what he calls “the Fellowship of Music” (p. 180).</p>
</li>
</ul>
<p>The other three issues are major ones and I deal with them below in depth:</p>
<ul>
<li>
<p><strong>“Clearing a space” for learning</strong></p>
</li>
<li>
<p><strong>Fear and shame</strong></p>
</li>
<li>
<p><strong>Independence and resourcefulness, and the role of the teacher</strong></p>
</li>
</ul>
<hr />
<p><strong>“Clearing a space” for learning</strong> </p>
<p>When he was learning the flute, music was</p>
<blockquote>
<p>still only a hobby, not at the center but at the edge of my life, not connected with any of my concerns about politics or the world or human life. (p. 134)</p>
</blockquote>
<p>I have the sense that Holt was aware of this issue’s importance long before he resolved it. In 1969 or ’70, as a result of new thinking about education while working with Ivan Illich, “the gap I had felt between my work and my hobby had disappeared” (p. 186). And yet, based on the first stories (“The Beginner over His Head”, pp. 187-94) in the following chapter, it sounds as though his level four years after that was still terribly low.</p>
<p>The issue of clearing space for learning also arises elsewhere in the book and I think the best résumé of Holt’s thinking about it is: “Time is my problem, not ignorance about what to play” (p. 211). The problem is not only time but single-mindedness.</p>
<p>Holt takes the phrase “clearing a space” from (he suspects) Matthew Arnold (1822–88), who learned to play the piano after uncluttering enough spiritual <em>Lebensraum</em> to do so. The main points he makes under the heading “clearing a space” are:</p>
<ul>
<li>
<blockquote>
<p>To make more time for music, I have had to give up many pleasures I have enjoyed for years. ... I don’t go any more to the ballet, which I have always loved, or to the theatre or movies, which I liked to go to once in a while. ... Outside of the Boston Symphony, which is too beautiful to give up, I go to few concerts. There are many other recreations that have given me great pleasure in the past, that I may rarely or never do again — sailing, canoeing, swimming, skiing, squash, tennis, soccer, skating, fishing, wilderness camping, mountain backpacking. I realize this without the slightest regret. (p. 237)</p>
</blockquote>
</li>
<li>
<blockquote>
<p>Friendship ... also has to give way. (p. 238)</p>
</blockquote>
</li>
<li>
<blockquote>
<p>More and more I am going to have to choose between playing and listening. ... To produce more music, I am going to have to consume less. (p. 238)</p>
</blockquote>
</li>
</ul>
<p>Holt also feels a conflict between the desires to write and to work on music:</p>
<blockquote>
<p>I am like the rope in a tug of war, the writer pulling one way, the musician the other. ... When the writer is in command, working on a book or an article for my newsletter, words are in my mind all the time, music making seems remote and trivial. When the musician is in command, I think music all the time. ... Words seem a distraction. (p. 238-39)</p>
</blockquote>
<p>And there is something of a change from the voice in <em>Instead of Education</em> (1976; Boulder: Sentient Publications, LLC, 2004; published the same year as this book), which fulminates against social injustice. Here, although he grants that many social problems and issues still “seize his mind” and he “can’t <em>stop</em> thinking about them” (p. 240), Holt says:</p>
<blockquote>
<p>One of the things I have had to learn to do, not just to make time for music, but to keep some sanity, is to give up the idea that I have to know and do something about everything, or everything bad, that is happening here and in the world. ... I already have all the bad news I can stand. (p. 239-40)</p>
</blockquote>
<hr />
<p>Mental “space” and single-mindedness are a problem only because time is a problem:</p>
<blockquote>
<p>Even if I can keep a space clear for music, time may also tell me something else — that the experts were right. Perhaps people in their fifties, like me, really do have something missing in their nervous and muscular systems that makes it impossible for them to become skilled musicians. ... Perhaps I will hit a speed barrier, a point beyond which I just can’t make my brain, eyes, arms, hands, and fingers work any faster. Perhaps I will find that even though I learn and improve, I do it so slowly that to play as well as I would like to would take me eighteen hours a day for fifty years — hours and years that I don’t have. ... By the time I can no longer dodge such a truth, I will have had many glimpses of it. Maybe I will be ready for it. ... Meanwhile, none of this has happened. If Nature has waiting for me up the road some kind of impassable barrier, she has so far given me no clear signs if it. (p. 241-43)</p>
</blockquote>
<p>There is one more aspect to consider in the question why time and space should be at issue. Earlier in the book Holt relates cellist János Starker’s (1924–2013) advice (p. 179):</p>
<blockquote>
<p>It’s extremely difficult for someone of our age to learn to play this instrument well, because we have to develop a whole new set of muscles, and a whole new set of coordinations. On the other hand, we have an advantage. … We can think of problems, and find solutions.”</p>
</blockquote>
<p>“Problems”, indeed, are part of the process of learning. Mental “space” is needed to work on them: </p>
<blockquote>
<p>There seem to be so many more kinds of problems in music, and so many more ways to work on them. It is a limitless field for thought, invention, experiment. (p. 238)</p>
</blockquote>
<hr />
<p><strong>Fear and shame</strong></p>
<p>This has been a trademark part of Holt’s arguments for educational reform. Here he says, of his flute studies:</p>
<blockquote>
<p>I was too frightened and ashamed of my mistakes, and the possibility of making mistakes, to be able to give myself wholly to the music (p. 134).</p>
</blockquote>
<p>He coins the name “Szigeti syndrome” (pp. 90-93) for the feeling of sympathetic embarrassment he experiences while attending a performance by violinist Joseph Szigeti (1892–1973); Szigeti’s arthritis led to many technical mistakes, which mortified Holt. </p>
<blockquote>
<p>What I finally came to understand is that I was not thinking about him, not feeling for him at all, but imagining <em>myself</em> up there, making those mistakes, and imagining all those three thousand people sneering and laughing <em>at me</em>. (p. 92)</p>
</blockquote>
<p>And yet</p>
<blockquote>
<p>Szigeti played on, in what was probably a very tough, thoughtful, and beautiful performance. But I could barely get past the wrong notes to hear the music. (p. 92)</p>
</blockquote>
<p>It’s illuminating that Holt thinks this 1952 performance “must have been one of his last public appearances”, although in fact Szigeti did not stop performing until 1960.</p>
<p>Holt says that helping children to be free of the fear of making mistakes, over several years between his encounters with flute and with cello, unburdened him of much of his own earlier worry about the same thing (p. 143). He considers fear and shame to have been his biggest obstacle as a learner.</p>
<blockquote>
<p>I have to keep in mind the distant goal, without worrying about how far away it is or reproaching myself for not being already there. This is very hard for most adults. It is the main reason why we old dogs so often do find it so hard to learn new tricks, whether sports or languages or crafts or music. But if as we work on our skills we work on this weakness in ourselves, we can slowly get better at both. (pp. 196-97)</p>
</blockquote>
<p>And he has thought a great deal about fear and shame in learning, and ways of escaping them. <em>A propos</em> of causes of shame, he mentions a student who went from an insightful but inexperienced teacher to an experienced but uninsightful one. He says the student could have returned to the less experienced teacher but</p>
<blockquote>
<p>he would have seen it, quite rightly, as a going <em>back</em>, a kind of retreat. Sooner or later, he must have thought, if he was going to be a good player, he was going to have to take lessons from a real teacher and if these lessons were going to be a misery, what was the use of going on? So he quit. (p. 155)</p>
</blockquote>
<p>One way to escape feelings of fear and shame in learning is to avoid eliciting words of consolation by making excuses for one’s poor performance — he calls this “no alibis in advance, no appeals for sympathy” (pp. 169-70). </p>
<hr />
<p><strong>Independence and resourcefulness, and the role of the teacher</strong></p>
<p>Holt is sometimes portrayed as minimizing the role of the teacher in education, but that seems to me to misconstrue him. Wary, yes, he is. In this book he says:</p>
<blockquote>
<p>Teaching is a very strong medicine, which like all strong medicines can quickly and easily turn into a poison. (p. 209)</p>
</blockquote>
<p>But he says very clearly that another way of minimizing fear and shame in the learning process is to have benefit of a teacher’s critical and expert guidance:</p>
<blockquote>
<p>I need ideas — beyond those I have already — about ways to work on a number of specific weaknesses: … . I need more critical feedback, more criteria for judging my own playing, more things to pay attention to in practice. … I practice very attentively right now, but there still might be something important that I am overlooking. Most of all, I need the experience of playing for a critical listener, to get over any stage fright I might feel about that, and to learn to play my best under pressure — just as in sports. (p. 216)</p>
</blockquote>
<p>Holt then adds his trademark caveat — a teacher’s guidance must not be all-dominating:</p>
<blockquote>
<p>Even while giving me this help, the teacher I need must accept that he or she is my partner and helper and not my boss, that in this journey of musical exploration and adventure, I am the captain. Expert guides and pilots I can use, no doubt about it. But it is my expedition; I gain the most if it succeeds and lose the most if it fails, and I must remain in charge. (p. 217)</p>
</blockquote>
<p>The same ideas come up in the “conditions” Holt set when, early in his own cello studies, he was asked to teach the instrument to a young person who had trouble sitting still:</p>
<blockquote>
<p>In agreeing, I made a few conditions. I insisted that playing the cello, and studying with me, be the boy’s idea, not his mother’s. He had to be free, and <em>to know that he was free</em>, to stop studying with me or stop playing altogether any time he felt like it, without having to feel ashamed or guilty. He had to be free to cancel a lesson if he wanted to. And I insisted that the whole matter of practice be left entirely up to him. Practice done in the spirit of why-do-I-have-to-do-this is worse than none at all. The only good practice is that done with zest and enthusiasm. I wanted this boy to play the cello for his own delight, to find out for himself that practice brought improvement, and to decide for himself how much improvement he was willing to pay for with work. (p. 150-51)</p>
</blockquote>
<p>He remarks that for parents to be involved in even such minor things as helping to tune a child’s instrument may be read as “a kind of subtle hint that he ought to practice” (p. 152), and that undermines self-direction.</p>
<p>As for Holt’s own flute studies,</p>
<blockquote>
<p>I was not independent or resourceful enough in my practice. I tried to do whatever my teacher told me, but I rarely thought of different ways to work on the problems he pointed out to me. … I did not understand enough about what happens in our minds, nervous systems, and muscles when we learn music, to take an intelligent, critical, and imaginative part, the <em>leading</em> part, in that process. I was not yet ready to be at the center of my own learning (p. 135).</p>
</blockquote>
<p>Holt describes what he calls the “mental-muscular model” (p. 197) of musicianship. He names eight things that have to be learned in mutual coordination and then makes two important points about the process of learning them. First, the process of mastering the mutual coordination of these things is not a linear process:</p>
<blockquote>
<p>Structures of knowledge … are much greater than the sum of their parts. (p. 202)</p>
</blockquote>
<p>Second, this learning is “not verbal” but carried out by the body (p. 199). Holt believes that the learner’s self-observation is vital to progress.</p>
<p>He illustrates this point on analogy with how we know how to change pitch when we are whistling or pressing strings against fingerboards — we understand through perception of ourselves: “trial and error; feedback; satisfaction, <em>pleasure</em> when it came out right” (pp. 114-16). Another example is his story of teaching a supposedly tone-deaf person to sing by harnessing the learner’s self-perception (pp. 99-104).</p>
<p>Holt’s fullest development of this theme now follows:</p>
<blockquote>
<p>There are no rules for getting a good sound from a stringed instrument. There is nothing that we can <em>tell</em> a novice that will enable him, then and there, to make a nice sound. ... The thing to do is to bow [DPB: rhymes with “go”], and as you bow, to listen. When you hear a note that is nicer than most of your notes, think “Aha!” — and keep bowing. You may not know what your muscles did that was different, but whatever it was, they will tend to do more of it.</p>
<p>What all this boils down to is a kind of law of learning that I have finally come to understand and accept:</p>
<p>WHEN YOU’RE WORKING, YOU’RE LEARNING.</p>
<p>... If we are fully involved in our music making, interested in it, excited by it, then we are learning. We may not and probably cannot know all of what we are learning. We are almost certainly learning much more than we think. By our work and our attention we are helping to grow the musical structures I spoke of earlier. If we are patient, we will find, as I am constantly surprised to find, that we <em>know</em> more than we consciously <em>learned</em>, even things that we never set out to learn. </p>
<p>... There is nothing mysterious or magical about this. The point about structures of knowledge is that they are much greater than the sum of their parts. ... As we build into our minds, nerves, and muscles these musical maps I have spoken of, we are using a finite amount of information, of <em>conscious</em> learning and practicing, to build structures that will generate an almost infinite amount of information, and what is more important, do it almost without conscious thought.</p>
<p>... This can create a paradox, a tension. At times we must think very hard with our conscious, planning, questioning, critical mind. At other times we must tell that part of our mind to shut up. (pp. 200-2)</p>
</blockquote>
<p>It seems that at the time he wrote this book, Holt was still really struggling to master technical proficiency — he says, for instance:</p>
<blockquote>
<p>What I need most, right now, is not someone to help me with interpretive problems. ... What I need is good advice about how to learn to play faster and read better. ... I need help with hard problems of fingering and bowing in the music I am playing with others. (pp. 213-16)</p>
</blockquote>
<p>In the Epilogue Holt describes his most current state, and all the things he describes are cases of growing into facility at playing. He says his left hand is getting more flexible. He is pleased to find he can now see more notes at once than before. “I knew all along that I <em>should</em> see more notes, <em>should</em> look ahead, but I couldn’t do it. Now, even when I am not trying to make it happen, it is beginning to happen. It is as if my eyes themselves have changed.” The biggest improvement is the changes he feels in his bow arm (p. 235). </p>
<p>Holt thinks the “method”, meaning a book of graded exercises, is a helpful tool for the beginner, but he is also grateful that his teacher, Hal Sproul, encouraged him to encounter technical challenges directly in major works that by any standard were too hard for him (pp. 143-45). He is fascinated by little tricks and rules of thumb to improve proficiency. Some of those used by his flute teacher Bill Grass (1926–2005) appear on p. 123. Holt also describes his own “inventions” — for tuning and for remembering specific intervals as an aid to sight-reading (p. 162-68). The Appendix lists his mnemonics for quickly remembering 19 pitch-intervals (pp. 243-44). In my experience, both as a learner and as a teacher, it’s helpful to devise one’s own mnemonics rather than using other people’s.</p>
<p>Mated with the non-verbal process of learning is Holt’s praise of Izler Solomon (1910–1987), as a conductor who talked very little and did not even interrupt the orchestra’s playing very often to make corrections. Solomon let players go as far as they could on their own. In general, says Holt, a teacher should not aim for more improvement in a day than is feasible for people (pp. 174-77).</p>
<hr />
<p><strong>Reflections</strong></p>
<p>Apart from Holt’s clear statements about the teacher’s role, the thing I expect to stay with me most vividly after reading this book is my own reflection on the place of non-verbal learning in self-directed study. In <em>Instead of Education</em> Holt says:</p>
<blockquote>
<p>Reading, unlike dancing, is not a muscular act (2004[1976]: 59)</p>
</blockquote>
<p>and this is related to firm ideas he has about what is and is not learnable. Curiously, in the present book Holt says it is not our business to decide what people are capable of learning:</p>
<blockquote>
<p>It is not our proper business as teachers, certainly not music teachers, to make decisions and judgments about what people are or are not “capable” of doing. It <em>is</em> our proper business, above all in music, to try to find ways to help people do what they want to do. ... Keep looking, keep asking, keep working on the problem yourself. If you want to make music, don’t let anybody tell you, and don’t tell yourself, that it is totally impossible for you to do it. (pp. 103-4)</p>
</blockquote>
<p>Speaking for myself, I am not persuaded that learning to read is a “verbal” and “non-muscular” process. I think the mind is a virtual muscle — “virtual” in the sense of “effective” or “simulated”, meaning that we interact with it usefully by modeling it as though it were a muscle. That is why learning by gestalt can be so effective at times.</p>
<p>Holt’s emphasis on direct perception of oneself in the process of learning leads me to reflect that “self-study” can mean both study by oneself and the study of oneself.</p>
<p>I think that what Holt is describing in his wrestling with musical performance applies to almost anything one tries to learn in adulthood. </p>
<p>[end]</p>What goes in a README?2016-12-01T15:45:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2016-12-01:what-goes-in-a-readme.html<p>In my job I spend a lot of time reading other people’s GitHub accounts — poking through their code and sometimes installing it to try out. Many README files are too sparse to be useful to me in that. As a result I have to spend time on my own, figuring out what’s going on in the code, or else abandon the effort. If I abandon the effort, I then have to fight the temptation to assume the programmer is lazy or the code isn’t finished. That outcome is not ideal if my reason for reading the code was to evaluate the programmer’s skill and attention to detail.</p>
<p>A README isn’t just designed for other users encountering your code for the first time; it will also be useful to you after you’ve been away from the project for a while — if you’re like most people, you’ll have forgotten a lot about it by then.</p>
<p>Below are the things I look for in a repository README file.</p>
<hr />
<ol>
<li>
<p><strong>What the project does</strong>.</p>
<p>Even if there isn’t anything else in the README itself, a link to any separate documentation site can go here, as can a statement of any software license covering the code.</p>
</li>
<li>
<p><strong>How to install it, including dependencies</strong>. </p>
<p>Be aware that you may be relying on dependencies that were put in place long ago, and that you’ve forgotten about. The user needs to know about them, though. One way you can make sure you have all dependencies accounted for is to write a script to populate a container for tools such as Vagrant or Docker. You should also mention what operating systems the project has been tested on, because that is a kind of dependency, too.</p>
</li>
<li>
<p><strong>How to run the code</strong>.</p>
<p>You should illustrate, even if it is obvious to you. If there are separate compilation or linking steps, show them; if your code is meant to be run in a REPL or browser console, say so here.</p>
<p>This is also the place to name the main sorts of functionality provided by the project, and to illustrate them. Remember, after time passes, you may have trouble remembering what you’ve actually built here.</p>
</li>
<li>
<p><strong>Discussion and references</strong>.</p>
<p>If the project is meant to display your skills, in the manner of a portfolio, it would be nice to hear about design decisions, surprises you encountered, and anything of interest you learned while doing the project. If there are external sources that were useful to you, cite them here. If there are people to thank, you might do that here, too.</p>
</li>
<li>
<p><strong>Work still to be done, known bugs, future plans</strong>.</p>
</li>
</ol>
<hr />
<p>Not all of this has to go into one huge README file. You can put separate sections into separate files — if there are two or more of them, you may like to place them in a directory called <code>doc</code> or something similarly suggestive. Nor does a README have to be exhaustive — but it should address the several headings I’ve listed above.</p>
<p>[end]</p>Self-segregation2016-11-16T21:55:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2016-11-16:self-segregation.html<p>The shocking thing about the election has been the severe emotions experienced by Clinton supporters. I, too, voted for Clinton — I made up my mind less than two weeks before the election to vote for the experienced political racketeer rather than the politically inexperienced bully. But now, facing the bully and his gangsters as they prepare to loot the economy and stack the courts, I find myself quite calm, whereas a crowd of people who voted as I did seem to have descended into depression and denial. Many say they feel blindsided. I am distressed at this reaction.</p>
<p>I blame it on poor sampling of the news by readers, something on their own responsibility. People seem to be self-segregating. More and more, they get their news via social media, meaning their friends, and from aggregators and algorithms that give them more of whatever they have indicated they like. It may be best to ignore most of the news altogether. But if you’re not doing that, then I think it’s better to read two or more physical newspapers or organized news sites, and do some with comparative thoroughness. A lot of what you take in will piss you off or bore you, but at least you can gauge the spread of reports on the same topic and pass fair judgment about the neutrality of the different sources, unlike someone who only sees sifted articles. This way of getting news varies your news-diet. Most of the electorate seems news-malnourished to me, eating plenty but lacking a balanced diet.</p>
<p>On self-segregation, here is an <a href="http://www.wsj.com/articles/fake-content-puts-pressure-on-facebook-google-1479257191">item</a> from this morning:</p>
<blockquote>
<p>Twitter on Tuesday said it would let users block notifications of tweets that include specific words, among other moves, to combat harassment on the short-messaging service.</p>
</blockquote>
<p>Many people now want to be able to silence mechanically anyone they don’t want to hear from. Technology makes it easy. I think naming harassment as the motive disguises what is actually happening.</p>
<p>What is the consequence of people segregating themselves into two large groups, defined by ideology? Unlike most of the people I am among in my second career, I have actually lived for extended periods in societies where political ideology destroyed people’s lives and careers, where martial law in name or spirit was in place, and speech was officially regulated to promote “harmony”. One of my friends in Taiwan spent most of the 1970s in a harsh political prison for being a Marxist. Most of the people I worked with in my Chinese fieldwork were rural intellectuals — schoolteachers, in the main. All had been on the outs politically for decades. There was also one sometime-journalist who in youth had been trained as a mason and gravedigger, and went back to gravedigging and masonry after politics shut down his newspaper — that is, when he was not being flung into pigpens and manure pits by his neighbors. </p>
<hr />
<p>Friends have, variously, been reading Eric Hoffer’s <em>True Believer</em> (1951), Ted Kaczynski’s <em>Unabomber Manifesto</em> (1995), and Philip Slater’s <em>Pursuit of Loneliness</em> (1970; 1990 revision), and I’ve taken up reading them, too. Only Slater’s is new to me, and I find it rambles and its prose reads stiffly. All three texts emerged from the pens of feral intellectuals. All three authors seem angry about trends in society and are indulge in immoderate assertion. Hoffer worked as a longshoreman and spent his off-time in libraries. Kaczynski is a U. Mich. math PhD who abandoned society and eventually began sending home-made bombs to engineers and airline executives; today he lives in a “supermax” prison in Colorado. Slater was a sociology professor who abruptly resigned from academia a year after publishing the book I’ve been reading, and after much swirling about eventually wound up at the Institute for Integral Studies. There’s a revealing late-life conversation with him <a href="http://harvardmagazine.com/2013/03/the-sage-of-tree-frog-lane">here</a>. </p>
<p>The most irritating and stimulating idea in this reading is the attacks on technology. Kaczynski and Slater both say technology is the tool of a system pressuring people to conform to rapid social change. Hoffer, writing in 1951, doesn’t mention technology at all, but he is worried about how a mass movement “subordinates creative work to the advancement of the movement” (#117). Kaczynski was much influenced by Hoffer and his innovation is to identify the evolution of technology as a kind of mass movement (#91), which seems to me an original thought. His solution is eliminating “industrial-technological society” so as to allow people more autonomy and freedom, something he considers necessary to human dignity. Slater’s idea of dignity is <em>less</em> autonomy — he wants better communication through smaller, closer communities, cooperative and where everyone has a place.</p>
<p>I think events of the past election year show that most of Slater’s predictions are now undermined. The divide between “individual strivers” and “cooperators” persists, although we’re now 45 years on since his book. The divide hasn’t been overcome and, despite his forecasts, our species persists, too. In the mean time, technology has given us social media and data mining, which together create “communities” possessing the power to make their boundaries impermeable to unwelcome ideas, as Twitter has just illustrated. I’m not sure if these distinct social organisms, which already behave like hostile states, observe the striver-cooperator cleavage Slater describes. But the separateness of the communities is scary — and one of its effects is the reaction of Clinton supporters over the past week.</p>
<hr />
<p>A pertinent point about technology-media as a source of community was made, in embryo, already in a 1978 review of Slater by Albert Bergesen:</p>
<blockquote>
<p>The key problem seems to be that the substance of this new community is composed symbolically, through the mass media. I suppose this is what McLuhan knew. As he said, people don’t read the morning newspaper, they slip into it like a warm bath. That’s a feeling of community! … If your primordial link is with the media, and thereby the collectivity as a whole (and increasingly the world as a whole), then movement from Maine to California, while a geographical shift, is not sociological travel, for you have never left your “local” community. If by local we mean people you are familiar with, see daily, and trust, wouldn’t Walter Cronkite and Johnny Carson count as much as your more immediate neighbors? (“Whence Community,” [<em>Contemporary Sociology</em>, 7/1: 18-22], p. 21; <a href="http://www.jstor.org/stable/pdf/2065892.pdf">http://www.jstor.org/stable/pdf/2065892.pdf</a>)</p>
</blockquote>
<p>In 2016 I think you and I know far better what is implied by technology-mediated “community”.</p>
<p>[end]</p>Python decorators for object-oriented method behaviors2016-11-15T15:21:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2016-11-15:python-decorators-for-object-oriented-method-behaviors.html<p>Python supplies special decorators for a number of tools common in object-oriented programming. Their functionality is implemented as ordinary built-in functions, but they are made available as decorators for easier application.</p>
<p>Below I first list them and then discuss them one by one under numbered headings.</p>
<p><strong>Functionality for restricting access to a property (attribute) of a class</strong>:</p>
<ul>
<li>as function: <code>property(fget=None, fset=None, fdel=None, doc=None)</code></li>
<li>as decorators: <code>@property</code>, <code>@x.getter</code>, <code>@x.setter</code>, <code>@x.deleter</code> for some attribute <code>__x</code>.</li>
</ul>
<p><strong>Functionality for methods of a class</strong>:</p>
<ol>
<li>
<p>Making a method “static” — available whether its class has been instantiated or not:</p>
<ul>
<li>as function: <code>staticmethod(function)</code></li>
<li>as decorator: <code>@staticmethod</code></li>
</ul>
</li>
<li>
<p>Making a method “abstract” — available only for subclassing.</p>
<ul>
<li>as function: <code>abc.abstractmethod(funcobj)</code></li>
<li>as decorator: <code>@abc.abstractmethod</code></li>
</ul>
</li>
</ol>
<p><strong>Functionality to modify attributes of a class, to take effect in all future instantiations</strong>:</p>
<ul>
<li>as function: <code>classmethod(function)</code></li>
<li>as decorators: <code>@classmethod</code></li>
</ul>
<p>(A decorator appears on the line before before a function definition, as seen in the examples below. It seems at first to modify that function. In reality, the decorator incorporates the function into some other piece of code, built-in or otherwise, behind the scenes.)</p>
<h2>1. Python public and private methods</h2>
<p>The “dunder” (double underscore, <code>__</code>) prefix prevents access to attributes, except through the accessors <code>@property</code>, <code>@attr.setter</code>, and <code>@attr.deleter</code>.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">C</span><span class="p">():</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__attr</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@property</span> <span class="c"># This is a "getter", though not so named explicitly.</span>
<span class="k">def</span> <span class="nf">attr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""The doc-string for the whole property goes here."""</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__attr</span>
<span class="nd">@attr.setter</span>
<span class="k">def</span> <span class="nf">attr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__attr</span> <span class="o">=</span> <span class="n">value</span>
<span class="nd">@attr.deleter</span>
<span class="k">def</span> <span class="nf">attr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">__attr</span>
</pre></div>
<p>The <code>@property</code> decorator is always required here, even if some of the others are omitted. It allows a docstring to be associated with the whole property <code>attr</code>. Technically, <code>@property</code> subsumes the function of <code>@attr.getter</code>, although the two can be used separately:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">C</span><span class="p">():</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">__attr</span> <span class="o">=</span> <span class="mi">0</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">attr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Supply getter functionally for property "attr"."""</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="nd">@attr.getter</span>
<span class="k">def</span> <span class="nf">attr</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__attr</span>
</pre></div>
<p>Some examples:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">f</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span> <span class="c"># Instantiate the object, to begin.</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">__attr</span> <span class="c"># Not directly accessible.</span>
<span class="o">...</span>
<span class="ne">AttributeError</span><span class="p">:</span> <span class="s">'C'</span> <span class="nb">object</span> <span class="n">has</span> <span class="n">no</span> <span class="n">attribute</span> <span class="s">'__attr'</span>
<span class="o">>>></span> <span class="s">'__attr'</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">__dir__</span><span class="p">()</span> <span class="c"># Not listed by __dir__()</span>
<span class="bp">False</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">__getattribute__</span><span class="p">(</span><span class="s">'__attr'</span><span class="p">)</span> <span class="c"># Not listed by __getattribute__()</span>
<span class="o">...</span>
<span class="ne">AttributeError</span><span class="p">:</span> <span class="s">'C'</span> <span class="nb">object</span> <span class="n">has</span> <span class="n">no</span> <span class="n">attribute</span> <span class="s">'__attr'</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">attr</span> <span class="c"># Accessible by the implemented getter.</span>
<span class="mi">0</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">attr</span> <span class="o">=</span> <span class="s">'Presto'</span> <span class="c"># Can be set by the implemented setter.</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">attr</span>
<span class="s">'Presto'</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">__attr</span> <span class="o">=</span> <span class="s">'Tricky?'</span> <span class="c"># Can we set it explicitly?</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">attr</span> <span class="c"># No. By doing that we have created a</span>
<span class="s">'Presto'</span> <span class="c"># new and different attribute.</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">__attr</span> <span class="c"># The dunder is a part of that </span>
<span class="s">'Tricky?'</span> <span class="c"># attribute's name.</span>
<span class="o">>>></span> <span class="n">f</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span> <span class="c"># Let's start again, so we can test del.</span>
<span class="o">>>></span> <span class="k">del</span> <span class="n">f</span><span class="o">.</span><span class="n">__attr</span> <span class="c"># Not directly delible.</span>
<span class="o">...</span>
<span class="ne">AttributeError</span><span class="p">:</span> <span class="n">__attr</span>
<span class="o">>>></span> <span class="k">del</span> <span class="n">f</span><span class="o">.</span><span class="n">attr</span> <span class="c"># Delete f.attr</span>
<span class="o">>>></span> <span class="n">f</span><span class="o">.</span><span class="n">attr</span> <span class="c"># Now it's gone.</span>
<span class="o">...</span>
<span class="ne">AttributeError</span><span class="p">:</span> <span class="s">'C'</span> <span class="nb">object</span> <span class="n">has</span> <span class="n">no</span> <span class="n">attribute</span> <span class="s">'_C__attr'</span>
</pre></div>
<p>(Actually, there is a way to access a “private” property while circumventing the <code>@property</code> functionality. Let’s use <code>i</code> to represent the instance name, <code>cls</code> the class name, and <code>a</code> the private attribute name. The private property can be read and assigned directly using the form <code>i._cls__a</code>.)</p>
<h2>2. Static vs. class vs. abstract methods</h2>
<h3>2a. Bound instance methods are the default</h3>
<p>Examples here are for Python 3; Python 2 behaves somewhat differently.</p>
<p>Methods are functions that are “bound” by default in Python 3: they are normally called on an instance of the class in which they are defined. That instance may be assigned to a variable:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s">'子程式'</span>
<span class="o">>>></span> <span class="n">e</span> <span class="o">=</span> <span class="n">Example</span><span class="p">()</span>
<span class="o">>>></span> <span class="n">e</span><span class="o">.</span><span class="n">default</span><span class="p">()</span>
<span class="s">'子程式'</span>
</pre></div>
<p>Or the class may be instantiated on the fly, by instantiating <code>Example</code> (as <code>Example()</code>) but not assigning it to a persistent variable.</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">default</span><span class="p">()</span>
<span class="s">'子程式'</span>
</pre></div>
<p>We can show that <code>default</code> is bound to a <em>particular</em> instance in either case, because we can ask for that instance’s memory location using the <code>__self__</code> attribute:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">default</span><span class="o">.</span><span class="n">__self__</span>
<span class="o"><</span><span class="n">__main__</span><span class="o">.</span><span class="n">Example</span> <span class="n">at</span> <span class="mh">0x10c0ce588</span><span class="o">></span>
<span class="o">>>></span> <span class="n">e</span><span class="o">.</span><span class="n">default</span><span class="o">.</span><span class="n">__self__</span>
<span class="o"><</span><span class="n">__main__</span><span class="o">.</span><span class="n">Example</span> <span class="n">at</span> <span class="mh">0x10c073780</span><span class="o">></span>
</pre></div>
<p>But it can’t be called on the uninstantiated class itself — here, <code>Example</code> without <code>()</code>:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">default</span><span class="p">()</span>
<span class="o">...</span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="n">default</span><span class="p">()</span> <span class="n">missing</span> <span class="mi">1</span> <span class="n">required</span> <span class="n">positional</span> <span class="n">argument</span><span class="p">:</span> <span class="s">'self'</span>
</pre></div>
<p>Here, when the interpreter says it requires the argument <code>self</code> it means it needs a particular instance of <code>Example</code> in order to call <code>default</code> on. It needs an instance because <code>default</code> was defined with <code>self</code> as its first parameter. But there is no such instance:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">default</span><span class="o">.</span><span class="n">__self__</span>
<span class="o">...</span>
<span class="ne">AttributeError</span><span class="p">:</span> <span class="s">'function'</span> <span class="nb">object</span> <span class="n">has</span> <span class="n">no</span> <span class="n">attribute</span> <span class="s">'__self__'</span>
</pre></div>
<h3>2b. Static methods: methods without an instance</h3>
<p>To call a method without having to have an instance, use the <code>@staticmethod</code> decorator, and omit the <code>self</code> argument:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">static</span><span class="p">():</span> <span class="c"># Note: no "self" argument</span>
<span class="k">return</span> <span class="s">'no instance required'</span>
<span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c"># Note: "self" argument present</span>
<span class="k">return</span> <span class="s">'instance definitely required'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">static</span><span class="p">()</span>
<span class="s">'no instance required'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">default</span><span class="p">()</span>
<span class="o">...</span>
<span class="ne">AttributeError</span><span class="p">:</span> <span class="nb">type</span> <span class="nb">object</span> <span class="s">'Example'</span> <span class="n">has</span> <span class="n">no</span> <span class="n">attribute</span> <span class="s">'default'</span>
</pre></div>
<p>In Python 3, a static method can be called on the class itself or on an instance. If you simply omit <code>self</code>, the method can be called on the class. Though, it cannot be called on an instance — <code>self</code> represents that instance itself.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">default</span><span class="p">():</span> <span class="c"># Note: no "self" argument</span>
<span class="k">return</span> <span class="s">'can be called on class but not on instance'</span>
<span class="k">def</span> <span class="nf">default2</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c"># Note: "self" argument present</span>
<span class="k">return</span> <span class="s">'can be called on instance but not on class'</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">default3</span><span class="p">():</span> <span class="c"># Note: no "self" argument</span>
<span class="k">return</span> <span class="s">'can be called on class or instance'</span>
</pre></div>
<p>Here are examples called on an uninstantiated class <code>Example</code> itself:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">default</span><span class="p">()</span>
<span class="s">'can be called on class but not on instance'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">default2</span><span class="p">()</span>
<span class="o">...</span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="n">default2</span><span class="p">()</span> <span class="n">missing</span> <span class="mi">1</span> <span class="n">required</span> <span class="n">positional</span> <span class="n">argument</span><span class="p">:</span> <span class="s">'self'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">default3</span><span class="p">()</span>
<span class="s">'can be called on class or instance'</span>
</pre></div>
<p>And here are examples called on an instance of the class, created non-persistently with <code>Example()</code>:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">default</span><span class="p">()</span>
<span class="o">...</span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="n">default</span><span class="p">()</span> <span class="n">takes</span> <span class="mi">0</span> <span class="n">positional</span> <span class="n">arguments</span> <span class="n">but</span> <span class="mi">1</span> <span class="n">was</span> <span class="n">given</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">default2</span><span class="p">()</span>
<span class="s">'can be called on instance but not on class'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">default3</span><span class="p">()</span>
<span class="s">'can be called on class or instance'</span>
</pre></div>
<p>(<strong>Note</strong>: In Python 2, <code>Example.default()</code> and <code>Example.default2()</code> are not allowed — an instance method <em>must</em> have that instance passed to it. <code>Example.default()</code> can’t receive the instance because has no <code>self</code> parameter at all, and <code>Example.default2()</code> has <code>self</code> but no instance is being passed to it.)</p>
<h3>2c. Class method: method called on a class itself, without instances</h3>
<p>This differs from a regular method that has no <code>self</code> parameter: it must have a <code>cls</code> parameter, which refers to the class itself, not the method.</p>
<p>This parameter can be used to access attributes of the class and modify them for all future instantiations:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
<span class="n">x</span> <span class="o">=</span> <span class="s">'original'</span>
<span class="k">def</span> <span class="nf">sample</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Output the instance and the attribute x, as found."""</span>
<span class="k">print</span><span class="p">(</span><span class="s">'instance: {}, x: {}'</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">))</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">class_method</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="sd">"""Modify the class attribute x."""</span>
<span class="n">cls</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">print</span><span class="p">(</span><span class="s">'x: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cls</span><span class="o">.</span><span class="n">x</span><span class="p">))</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">sample</span><span class="p">()</span> <span class="c"># first instantiation</span>
<span class="s">'instance: <__main__.Example object at 0x10c1605f8>, x: original'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">sample</span><span class="p">()</span> <span class="c"># second instantiation</span>
<span class="s">'instance: <__main__.Example object at 0x10c1591d0>, x: original'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">sample</span><span class="p">()</span> <span class="c"># third instantiation</span>
<span class="s">'instance: <__main__.Example object at 0x10c159320>, x: original'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">class_method</span><span class="p">(</span><span class="s">'changed by user'</span><span class="p">)</span>
<span class="s">'x: changed by user'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">sample</span><span class="p">()</span> <span class="c"># fourth instantiation; attribute changed!</span>
<span class="s">'instance: <__main__.Example object at 0x10c159400>, x: changed by user'</span>
</pre></div>
<p>Without this <code>cls</code> parameter, a class method does not seem to be callable at all:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Example</span><span class="p">:</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">class_method</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="s">'cls: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cls</span><span class="p">)</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">uncallable</span><span class="p">():</span>
<span class="k">return</span> <span class="s">'cannot be called'</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">class_method</span><span class="p">()</span>
<span class="s">"cls: <class '__main__.Example'>"</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">class_method</span><span class="p">()</span>
<span class="s">"cls: <class '__main__.Example'>"</span>
<span class="o">>>></span> <span class="n">Example</span><span class="o">.</span><span class="n">uncallable</span><span class="p">()</span>
<span class="o">...</span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="n">uncallable</span><span class="p">()</span> <span class="n">takes</span> <span class="mi">0</span> <span class="n">positional</span> <span class="n">arguments</span> <span class="n">but</span> <span class="mi">1</span> <span class="n">was</span> <span class="n">given</span>
<span class="o">>>></span> <span class="n">Example</span><span class="p">()</span><span class="o">.</span><span class="n">uncallable</span><span class="p">()</span>
<span class="o">...</span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="n">uncallable</span><span class="p">()</span> <span class="n">takes</span> <span class="mi">0</span> <span class="n">positional</span> <span class="n">arguments</span> <span class="n">but</span> <span class="mi">1</span> <span class="n">was</span> <span class="n">given</span>
</pre></div>
<h3>2d. Abstract method: leave implementation for creation or modification only by inheritance</h3>
<p>A method can be prepared for future implementation implicitly using <code>pass</code> or <code>return</code> as the dummy body, or explicitly using <code>@abc.abstractmethod</code>. Explicitly declaring a method to be abstract means that it cannot be called directly, and a class that contains only abstract methods cannot be instantiated at all, although it can be subclassed.</p>
<p>An explicit abstract method requires you to import the <code>abc</code> module and specify a special argument <code>metaclass=abc.ABCMeta</code> in the class definition:</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@abc.abstractmethod</span>
<span class="k">def</span> <span class="nf">an_abstract_method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
<p>Even with the <code>@abc.abstractmethod</code> decorator, some sort of nominal body seems to be needed in the method: a docstring or <code>pass</code>, for instance:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@abc.abstractmethod</span>
<span class="k">def</span> <span class="nf">an_abstract_method</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""(dummy docstring)"""</span>
</pre></div>
<p>The decorators <code>@classmethod</code> and <code>@abc.abstractmethod</code> can be composed, in order to create an abstract class method. <code>@classmethod</code> is applied after <code>@abc.abstractmethod</code> — in other words, <code>@classmethod</code> appears <em>before</em> <code>@abc.abstractmethod</code>:</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@classmethod</span>
<span class="nd">@abc.abstractmethod</span>
<span class="k">def</span> <span class="nf">abstract_class_method</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
<span class="sd">"""(dummy docstring)"""</span>
</pre></div>
<p>[end]</p>The English Level of This Year's Principal Presidential Candidates2016-11-01T11:49:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-11-01:english-level-of-presidential-candidates.html<p>During this year's Presidential debates, one thing struck me most forcibly, but I never heard anyone else else talking about it — the far greater articulateness that Clinton displayed. </p>
<p>I looked around for libraries to calculate the grade-level of body of English text, and settled on <a href="https://pypi.python.org/pypi/textstat/">textstat</a> (<a href="https://github.com/shivam5992/textstat">repo here</a>). </p>
<p>Using the transcripts of the three debates, I found that the English used by Clinton had a 8th-9th grade score and Trump had a 5th-6th grade score. Whether Trump's performance is by design or not is a question people have been arguing with me about — I have no opinion about that, but I was glad to find a way to assign numbers to my impression.</p>
<p><a href="https://github.com/DataBranner/clinton_trump_debate_language_stats">My little script here</a>.</p>
<p>[end]</p>Chao on Wenyan2016-10-10T11:49:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-10-10:chao-on-wenyan.html<p>"Current wenyan, which is still a living language, is modeled more closely after <em>Mencius</em> than after any other of the classical works."</p>
<p>— Yuen Ren Chao, <em>Grammar of Spoken Chinese</em>, sec. 1.2.2, p. 15</p>
<p>[end]</p>Face 面子2016-07-12T00:21:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-07-12:face-面子.html<p><strong>Face 面子</strong></p>
<div class="highlight"><pre>Substance empty —
shadow full.
Never tempt me
strings to pull.
Face is mask —
is shame's reverse.
Then "face" is "shameless"?
how perverse!
And mask is face —
concealment, still.
Façade in place,
but covering nil.
Fraud promoted —
worth destroyed.
Painted screens
obscure a void.
Nothing seen,
the veils unfurled?
I am sober —
drunk, the world.
</pre></div>
<p>[end]</p>Some Questions about the Recurse Center2016-05-22T23:40:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-22:some-questions-about-the-recurse-center.html<p>In February of 2013 I entered the <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Recurse Center</a> (RC) and have remained active in its alumn community ever since. I am fifty-four and this has been one of the most fruitful associations of my life. Now people often ask me questions about RC — here are some of those that I have heard less often than others and that I think may interest people considering application to RC:</p>
<h3><strong>What has the difference been for you between being at RC and coding/learning on your own?</strong></h3>
<p>RC has given me code review, pairing, stimulation in unexpected ways, and a network of extraordinary people. All four of those items are pretty hard to set up for oneself outside of the environment cultivated by RC.</p>
<h3><strong>How has coding been connected to your non-coding life or interests?</strong></h3>
<ol>
<li>
<p>In my sinological research, which remains my most abiding passion even though I no longer make a living from it, I have used my coding skills to speed tasks that would have been impossibly tedious if I’d attempted them manually. Those research projects have included:</p>
<p>a. Taiwanese cantillation, manually transcribed with music-notation software, from which XML can be output and then analyzed programmatically.</p>
<p>b. (In collaborative work with a mathematician) using Chernoff bounds to estimate the probability that</p>
<ol>
<li>
<p>prosodic behavior in medieval Chinese poetry is the result of random choice of word-tones, and</p>
</li>
<li>
<p>a certain medieval prosodic effect is observed by chance in Chinese poetry written 500 years earlier.</p>
</li>
</ol>
<p>c. A dictionary project organized using a database and Python code, and typeset in programmatically-generated LaTeX.</p>
<p>All of these are basically rudimentary applications of coding skill, and would not be of theoretical interest to people with minds inclined to the abstractions of computer science.</p>
</li>
<li>
<p>I have begun one project developing an idea I learned from theoretical computer science: a Classical Chinese grammar project that circumvents Chomsky’s argument about the need for transformational principles. I presented it at a programming conference and it represents new research territory for me — something I hope I am able to develop much more fully as my other obligations recede.</p>
</li>
<li>
<p>I hope to make the teaching of programming into the mainstay of my coding career, and I have found a number of the practices customary among programmers very useful to my own learning and to my study of how to teach programming:</p>
<p>a. blogging about things that interest me,</p>
<p>b. collecting miscellaneous notes (exposed on a public repository),</p>
<p>c. giving lightning talks,</p>
<p>d. mentoring junior coders, and</p>
<p>e. preparing finished slides to illustrate things for instruction.</p>
</li>
</ol>
<h3><strong>What did you find set you most apart from most other RC people?</strong></h3>
<p>In my first batch I was around twice the age of the average person — I was fifty, and the average age of the rest of my batch was, I think, twenty-six or so. I’m pretty sure I was the oldest person ever to enter RC up to that time.</p>
<p>I was also a mid-life “career-changer”. I put it in quotes because I don’t like the term — it means that I had already had a full first career in a field totally unrelated to programming or peripheral subjects such as math, physics, or formal logic. I believe I was the only such batchling up to that time who was also a very inexperienced programmer.</p>
<h3><strong>How did you deal with that?</strong></h3>
<p>I kept my head somewhat down about both my age and my past career, although my pedantic academic ways are hard to conceal for long. But my fellow batchlings were welcoming and tolerant, and have remained so.</p>
<p>But neither they nor RC were aware at first of the difficulties that mid-life career-changers generally encounter when trying to enter the tech industry. Overall, I find it an intrusion into my own space when a younger person, meaning well in every sense of that phrase, expresses regret about the prevalence of ageism in tech. Then again, my own reactions to various ways of life and outlook that I’ve encountered among the young are perhaps “ageist”, too. Having realized the need to face that error, I’m not in a position to complain about how the young view me and my situation. </p>
<h3><strong>Did you always think you were a fit for RC?</strong></h3>
<p>Initially I wasn’t sure, but a friend who was informally mentoring me urged me to try, so I submitted the best application I thought I could and then just put it out of my mind.</p>
<p>During my first batch, in the first day or so several JavaScript mavens found each other and began pair-programming together rather loudly. I had the impression that I was the only person in the entire batch who didn’t know JavaScript, and that gave me some discomfort for a time. After several such experiences, involving different technical skills, it dawned on me that I was misjudging the situation. Since then, I haven’t been bothered by other people’s superior technical skills, real or fancied.</p>
<p>Well, I guess, with one exception. There is a certain kind of intellectual aggressiveness exhibited by some programmers with strong backgrounds in mathematics or computer science theory. While engineering aggressiveness is normally avoided at RC, and indeed the <a href="https://www.recurse.com/manual#sec-environment">social rules</a> are designed to eliminate much of it, this one variety is likely to persist because it is a source of innocent pleasure for an important subset of the community’s members. (I do mean that it is innocent — I am not talking about the obstreperous way a gaggle of male engineers sometimes behaves.) The many batchlings who are uncomfortable with these fields will just have to deal with the situation, as I have. But there is a mild antidote I can recommend for people experiencing that discomfort.</p>
<p>Let me digress briefly but with purpose. There is an <a href="http://www.amazon.com/review/R403HR4VL71K8">Amazon review</a> by a well-known computer scientist who says that people who don’t like Sussman and Abelson’s <em>Structure and Interpretation of Computer Programs</em> (<em>SICP</em>) are — I paraphrase — lazy thinkers. In reality, getting through <em>SICP</em> requires a lot of abstract thinking of a particular kind. Programming was once the private playground of people with a knack for this kind of thinking and perhaps also a penchant for exclusivity. Fortunately, the field is now wide open to people with far more diverse kinds of minds. </p>
<p>Whenever I remember that <em>SICP</em> review, in the next gust of thought there arises this line from Alistair Cooke’s <em>Six Men</em> (New York: Random House, 1977; p. 6):</p>
<blockquote>
<p>André Malraux, in one of those blasting sentences with which [certain intellectuals] love to seal off whole tunnels of inquiry, said that “the death of Europe is the central fact of our time.”</p>
</blockquote>
<p>The antidote I am speaking of is this: don’t let other people seal off the tunnels of <em>your</em> inquiry. Pursuit your own quest and, if you care to, do it on terms you choose. Anyway, don’t let yourself be discouraged by people who tell you, as that eminent computer scientist is doing, that your way is no good.</p>
<h3><strong>Were there any expectations you found hard to meet, or needs at RC that you found yourself particularly suited to meeting?</strong></h3>
<p>I can think of no expectations I found hard to meet.</p>
<p>I think I’ve been of occasional use to people preparing conference presentations and proposals, young people contemplating marriage, people afraid of career-change or a hostile job market, and people who have found some inspiration from my intransigence in such petty matters as using an old-fashioned text editor or avoiding the use of a mouse.</p>
<p>It seems to me I made quite an impression on the faculty during my first batch because of my extensive note-taking habits. (Those poor people have since been almost drowned in my logorrhea.)</p>
<h3><strong>What has inspired you to stay connected to the RC community after your batch?</strong></h3>
<p>The network of alumns at RC is the organization’s crown jewel, and no “inspiration” has been necessary.</p>
<h3><strong>What motivated you the most when your progress seemed to slow at RC?</strong></h3>
<p>One tactic was to change to a short-term, small project to take my mind off some bigger project that had stalled.</p>
<p>Long walks — of an hour or two — helped, too. Movies helped, conversation helped, assorted distractions helped. Another trick was to time my work sessions and when the timer went off, immediately force myself to stop work and do something else entirely. I’ve read that that was Igor Stravinsky’s method of composition.</p>
<p>Above all, persistence and patience helped. <a href="http://melchua.com/">Mel Chua</a>, now and again a resident at RC, often speaks about the uneven progress that our brains make during the process of learning. Periodically the human brain seems to slow down to a crawl and you find yourself in a funk — but that is when it is consolidating what it has learned, and the crawl doesn’t mean you’ve stopped learning at all. That’s been helpful to remember.</p>
<h3><strong>How did your initial goals differ from what you actually did at RC?</strong></h3>
<p>I haven’t looked back at my diaries to check this, but my impression is that my initial goals bore very little relation to what I actually did in batch.</p>
<p>In some cases, what happened to me was far better than what I had “planned” for. In others, I failed to learn something that I really had my heart set on, and that I still hanker for control of.</p>
<h3><strong>Were you able to make the best possible use of RC during your batch? Is there anything you wish you had done differently?</strong></h3>
<p>I went through two batches, and there are things I wish I had done differently both times.</p>
<p>The first time, I pair-programmed relatively little — probably because others were intimidated of me when I asked if we could pair, meaning for them to be “driving”. In retrospect, I see that I should have pushed for more pairing encounters, inviting others to pair, with me driving. I failed to take steps that would have made pairing take place. The driver in a pairing arrangement is more emotionally vulnerable than the “navigator”, and since my age and past profession make me especially intimidating to many people, I should always have put myself in that position for the first encounter or two.</p>
<p>In addition, I had a long-scheduled class that I had to teach after hours two days a week. At that time, RC’s rules were not enforced as energetically as they are now about the inadvisability of working at a job while in batch. Realistically, I could neither reschedule the teaching job nor cancel it, so I just left a little early two days a week. But it happened that that was the first batch during which Thursday presentations (now a fixture of the weekly schedule) took place, and I had to miss all but two of them. I don’t know what I could have done about that, but I wish it hadn’t happened.</p>
<p>In my second batch, I paired and collaborated much more, but I continued two practices from my first batch: working mainly in Python and doing projects with heavy emphasis on string-manipulation, since my domain of greatest comfort is a branch of natural-language linguistics. In retrospect, I see that I should have worked entirely in a language either new or very unfamiliar to me, and I should have worked entirely in graphical or numerical data rather than strings.</p>
<h3><strong>What surprised you the most about RC?</strong></h3>
<p>The first really big surprise I had was realizing how pleasant and interesting all the people there were. At that time, the network was not yet featured on the website as RC’s most valuable aspect. I suspect, though I’m not sure, that the founders only really began to understand about the network around the time of my first batch.</p>
<h3><strong>Is there anything you wish you had known, going in? Or are there any questions you would advise applicants asking themselves as they consider applying?</strong></h3>
<p>Are you ready to take risks with your own learning, and persistently prevent yourself from getting too comfortable with any project? That would be the best way to get the most you can out of RC.</p>
<h3><strong>Has there been a single most important benefit for you?</strong></h3>
<p>Hard to name just one, but high on the list is my understanding of what it means to be a programmer — that was the paramount insight of my first batch. Joining the network of alumns is another item high on the list.</p>
<h3><strong>How about a single biggest struggle?</strong></h3>
<p>Many people enter RC with no more coding experience than I had but they are half my age. Seeing how much more easily they get job interviews than I do — granted that they may, even so, not get job offers — has been frustrating and I haven’t always handled that well at all. The only half-solution I can offer for that is to point out that most of those people are building a first career; this is my second career, and some differences arise inevitably from that point.</p>
<h3><strong>Was it difficult to make the time in your life to attend RC?</strong></h3>
<p>It was hard on my family for me to be so completely abstracted from them for three months.</p>
<p>I didn’t get much exercise while at RC — I had been following a substantial workout practice until then, but RC put an end to it utterly, and I’ve never really recovered from that.</p>
<p>I didn’t sleep much while at RC — I was too keyed up and learning too intensely, and during those months I often dreamt that I was writing code. That happened during both batches, and the state of hyperagrypnia gradually dissipated during the month after my batch ended.</p>
<h3><strong>Have you had any other experiences that in part resemble your experience at RC?</strong></h3>
<p>My first couple of years in graduate school were somewhat like RC, in that I felt newly admitted into a restricted guild where people helped each other to learn.</p>
<p>My two-and-a-half years in rural China doing dialect fieldwork for my dissertation were also similar, with respect to self-directed, hands-on learning. No academic research project I have done since then has been as much like RC as that was. I had only very occasional contact with my Doktorvater, far off in the United States somewhere — we communicated by paper letters at that time and between those places. (My <em>shymuu</em> 師母, my advisor’s widow, recently sent me the whole sheaf of letters he had kept.) While in the field I learned a vast amount from the old men I was collecting language from, and the younger men I interacted with in the Government offices that sponsored me, and most of all from struggle — on my own terms — to make sense of the language data I was gathering. </p>
<p>[end]</p>De-duplicate Apple Calendars on Mavericks2016-05-21T08:06:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-21:de-duplicate-apple-calendars-on-mavericks.html<p>Since OS 10.10 (Yosemite), Apple’s “Calendar” program and iCloud service reportedly now removes any duplicate events when two or more calendars are combined. But on OS 10.9 (Mavericks), that functionality doesn’t exist: when the merged calendar is uploaded to the iCloud server, each duplicate event generates an error that has to be dismissed manually.</p>
<p><a href="https://github.com/DataBranner/dedup_apple_calendars">This program</a> combines the timezones and events of any number of exported <code>.ics</code> calendars whose paths are passed in on the command line:</p>
<div class="highlight"><pre>python dedup_apple_calendars.py export_1.ics export_2.ics export_3.ics
</pre></div>
<p>and writes them to a single file called <code>merged_calendar.ics</code> in the present directory.</p>
<p>In the event of duplicate events that are fully identical, only one is retained by the program.</p>
<p>If events are duplicated but have different <code>LAST-MODIFIED</code> or <code>DTSTAMP</code> properties, I believe Calendar will select the item with the latest date-stamp. With that belief in mind, I have omitted any comparison of these properties in selecting between otherwise-identical items. That may prove to be a design error, and I should experiment to see whether finer comparison should be done by this program.</p>
<p>[end]</p>Transcribing Voice Recordings on OS X, 3 — another example2016-05-17T19:18:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-17:transcribing-voice-recordings-os-x-3-another-example.html<p>In a <a href="transcribing-voice-recordings-on-os-x.html">recent post</a> I described using Soundflower and Audio Hijack Pro to get Apple’s built-in Dictation tool to transcribe recordings of spoken text.</p>
<p>Below are nine successive transcription results from this process, from a <a href="https://github.com/DataBranner/transcription_on_apple/blob/master/20060920_interview_jln_0756-0838.m4a">good-quality original recorded on an MP3 device in 2006</a>. After the automated transcriptions I have placed a manual transcription. The speaker is a native U.S. English speaker.</p>
<p>It’s evident that the automated workflow as configured saves no time at all over manual transcription.</p>
<h3>Transcriptions</h3>
<ol>
<li>
<blockquote>
<p>So I gave up on the way I’m post with those extra euros when you learn I test text your asked you so give it go at the mall</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started gave up on the go since he’s better than to write I posted with is extremely useful when you were going to text your learning one at your so. It won’t work after all</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on the overview better than right I composed and kind which was extremely useful when you are going to have to text your learning when asked you so. It won’t work at the mall</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on my phone is even better than that right I composed and kind which was extremely useful when you are going to have to text your learning when asked you so. To go work at the mall</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on my phone is even better than that right I composed right and just kind which was extremely useful when you are
Just passed a text you’re learning when asked you so give me a chance to go back home</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on my love of the season better than to write so I composed this is extremely useful when you are going to have to text your learning what I mean you so baby won’t work after all</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on that my love is even better than that right I composed with is extremely useful when you are going to have to text your learning when asked you so give me a chance to go after the mall</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on that my love is even better than that write so I composed and discuss with is extremely useful when you are
Just passed the text you’re learning when asked when you’re so give me to go at the mall</p>
</blockquote>
</li>
<li>
<blockquote>
<p>So I started Dave up on my love is you better than that you write so I I wouldn’t compose to come with is extremely useful when you are going to have to text your only learned what mean you so baby what were at the mall</p>
</blockquote>
</li>
</ol>
<h3>Manual transcription</h3>
<blockquote>
<p>So I sort of gave up on that and I thought, well, since he’s literate in Manchu and can write Manchu, and so forth, I, um, I would… compose things in Chinese — or sometimes in Russian, because he knew Russian very well — and just ask him to translate, which was extremely useful, you know, because when you learn a language just from… passively… from looking at texts, uh, you’re only learning one aspect of the language, you know. I mean, you’re… So… that gave me a chance to… develop a more active knowledge of Manchu, so that eventually I could write sentences and such things. </p>
</blockquote>Transcribing Voice Recordings on OS X, 2 — more examples2016-05-17T16:43:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-17:transcribing-voice-recordings-os-x-2-more-examples.html<p>In a <a href="transcribing-voice-recordings-on-os-x.html">recent post</a> I described using Soundflower and Audio Hijack Pro to get Apple’s built-in Dictation tool to transcribe recordings of spoken text.</p>
<p>Here I present two transcriptions each (with a headset or with the built-in Apple microphone) of recordings made with two applications (Skype, QuickTime). The sample is too small to be called “sample” with any justice, but QuickTime does much better recording directly than Skype does when “hijacked” to a sound file, and Skype with a headset does much better than Skype without. The QuickTime files are <code>m4a</code> and the Skype files are <code>mp3</code>, but in other experiments it seems this makes no difference.</p>
<hr />
<h3>Recording from Skype (v. 7.26)</h3>
<p>Here is Dictation’s transcription of a recording made using Audio Hijack to divert a brief Skype conversation to a sound file. The passage I read is from “Shame”, in Primo Levi’s <em>The Drowned and the Saved</em> (tr. Raymond Rosenthal, [New York: Vintage International, 1989], p. 73)</p>
<h4>Transcriptions</h4>
<ol>
<li>
<p>Transcription by Dictation, from <a href="https://github.com/DataBranner/transcription_on_apple/raw/master/skype_call-testing_recording_headset.mp3">recording made with headset</a>.</p>
<p>“Accuracy” of 80%.</p>
<blockquote>
<p>Hello welcome just like what testing something’s off to the beep please record a message off to list your message will be played back to you the fake discomfort which accompanied wasn’t precisely but it was perceived to suck the fate discomfort which accompanied up or a she wasn’t precisely name but it was perceived to suck if you’re able to hit your invoice and you can pick up that correctly if you get this message but not to invoice the something is wrong with you or do your recording something’s please take your microphone and my conference team will visit Scott.com for more help I keep using Skype call testing service goodbye</p>
</blockquote>
</li>
<li>
<p>Transcription by Dictation, from <a href="https://github.com/DataBranner/transcription_on_apple/raw/master/skype_call-testing_recording_no_headset.mp3">recording made without headset</a></p>
<p>“Accuracy” of 60%.</p>
<blockquote>
<p>For testing something off to be going to message off to your message will be right back to you the vague discomfort which a company to bring she wasn’t the size you should but it was perceived in such which company I’ll bring what size but it was perceived if you are able to hear your voice</p>
<p>Correctly if you get this message to an voice something is wrong with you what you recording something please check your my good friend and I went to take or visit Scott don’t come for help if you can</p>
<p>Call testing service by</p>
</blockquote>
<p>One really remarkable thing is that every pass made at this recording by Dictation produces quite a different transcription:</p>
<ol>
<li>
<blockquote>
<p>Just got off the message your message late vague discomfort which accompanied the break she wasn't the size but it was perceived us which company but it was perceived you're able to voice text got correctly if you get this message I got your back was fucking is wrong with you recording something please check you might want to skype.com or help I can you've Scott call test this device</p>
</blockquote>
</li>
<li>
<blockquote>
<p>Welcome just got called testing 78 going to message with your message looking like you very discomfort with your company or a she wasn't the size you should but it was perceived us which company or a sure what precise is perceived if you're able to get you a voice</p>
<p>Correct if you get this message got your back always something is wrong with what you recording something please check you might like I sent you I don't come or help to give you a call test for this goodbye</p>
</blockquote>
</li>
<li>
<blockquote>
<p>Just got called testing 78 going to message with your message will be late to you that discomfort which company are you sure wasn't the size but it was perceived set of eggs which company you what size your purse see if you are able to get you a voice</p>
<p>Karen if you get this message but got your voice and something is wrong with what you recording something please check you might want to some it's going to call for help and give you a call testing service goodbye</p>
</blockquote>
</li>
</ol>
</li>
</ol>
<h4>Original text</h4>
<blockquote>
<p>Hello — welcome to Skype call-testing service. After the beep, please record a message. Afterwards, your message will be played back to you.</p>
<p>The vague discomfort which accompanied liberation wasn’t precisely shame, but it was perceived as such.</p>
<p>The vague discomfort which accompanied liberation wasn’t precisely shame, but it was perceived as such.</p>
<p>If you are able to hear your own voice, then you have configured Skype correctly. If you hear this message, but not your own voice, then something is wrong with your audio recording settings. Please check your microphone and microphone settings, or visit Skype.com for more help.</p>
<p>Thank you for using the Skype call-testing service. Goodbye!</p>
</blockquote>
<hr />
<h3>Recording from QuickTime (v. 10.3):</h3>
<p>Below are transcriptions of the passage from the <a href="transcribing-voice-recordings-on-os-x.html">first post</a>, recording directly from QuickTime.</p>
<h4>Transcriptions</h4>
<ol>
<li>
<p>Transcription by Dictation, from <a href="https://github.com/DataBranner/transcription_on_apple/blob/master/piston_harmony_intro_para2_edited_no_headset.m4a">recording using the built-in microphone (about two feet away)</a>.</p>
<p>“Accuracy” of 93%.</p>
<blockquote>
<p>There are those who consider that studies in harmony can order point and few are the exclusive province of the intended house but if we reflect that theory must follow practice where are we preceding it if by chance we must realize that musical theory is not a set of directions for composing music it’s rather the collective and system of times the actions gathered by the practice of composers over a long time and it attempts to set forth what is or has been very common practice it tells not how music will be with me in the future but her music has been with in the past water piston in production to harmony 1941</p>
</blockquote>
</li>
<li>
<p>Transcription by Dictation, from <a href="https://github.com/DataBranner/transcription_on_apple/blob/master/piston_harmony_intro_para2_edited_headset.m4a">recording using a headset</a>.</p>
<p>“Accuracy” of 92%.</p>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint a few are the exclusive province of the intended but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it’s rocking the collected and systematize deductions gathered by observing the practice of composers over Time and it attempts to set forth what is old has been there common practice it tells not how music but how music has been written in the past is the production harmony</p>
</blockquote>
</li>
</ol>
<h4>Original text</h4>
<blockquote>
<p>There are those who consider that studies in harmony, counterpoint, and fugue are the exclusive province of the intended composer. But if we reflect that theory must follow practice, rarely preceding it except by chance, we must realize that musical theory is not a set of directions for composing music. It is rather the collected and systematized deductions gathered by observing the practice of composers over a long time, and it attempts to set forth what is or has been their common practice. It tells not how music will be written in the future, but how music has been written in the past. — Walter Piston, Introduction to <em>Harmony</em> (1941)</p>
</blockquote>
<p>[end]</p>Transcribing Voice Recordings on OS X2016-05-16T12:54:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-16:transcribing-voice-recordings-os-x.html<p>As the first step in a small research project, I have been looking into automated transcription of recorded speech. What follows is merely notes on a published workflow by a sound engineer.</p>
<p>In summary, automated transcription from a recording works reasonably well (about 91% accuracy in a few tests), but my workflow requires use of several programs, one of which costs some money.</p>
<p>One small irritation is that you can’t use your computer for anything else while the Dictation software is at work.</p>
<h2>Workflow</h2>
<p>The workflow I used follows what is described in this <a href="http://telestreamblog.telestream.net/2013/12/using-dictation-to-turn-recorded-audio-to-text-2/">2013 post by Frank Lowney</a> on Lucas Bischofberger’s blog. Basic steps:</p>
<ol>
<li>Install Soundflower and Audio Hijack, to handle communication between the audio-playback application and Apple’s Dictation tool. Together these allow the use of whatever audio-playback application you choose, once "hijack" is enabled in Audio Hijack.</li>
<li>Pipe audio output to Soundflower as “auxiliary device output” in Audio Hijack.</li>
<li>Set both the input of Dictation tool and the output of main audio-playback application to Soundflower.</li>
<li>For transcription from a recording, begin audio playback and then quickly turn on Dictation in a text editor that supports it.</li>
</ol>
<p>Third-party software I used: Audio Hijack Pro (v. 2.11.6), Soundflower (v. 1.5.1), Audacity (v. 2.1.0), BBEdit (v. 11.5.2). Points for attention:</p>
<ol>
<li>
<p><strong>Audio Hijack</strong> costs money and was necessary for the workflow. Efforts to circumvent the need for this tool failed.</p>
</li>
<li>
<p><strong>Soundflower</strong> is the actual driver that enables output from an audio-playback application to be piped to Dictation. It is free and open-source.</p>
</li>
<li>
<p><strong>Audacity</strong> is also free and open-source, and it is helpful for editing recordings, increasing volume, adding seconds of silence at the start of the recording (ensures Dictation doesn’t miss the start of the recording), and slowing down fast-talking interviewees. </p>
</li>
<li>
<p><strong>Dictation</strong> is to be enabled in Apple’s System Preferences (<code>Dictation & Speech</code> pane). That pane also allows use of a keyboard shortcut to start dictation.</p>
</li>
<li>
<p><strong>BBEdit</strong> is what I used for receiving the output of Dictation. It has a no-cost parallel release, <strong>TextWrangler</strong>. Both support Dictation (menu <code>Edit => Start Dictation…</code>). It is useful to be able to turn Dictation on very rapidly. My keyboard is old and doesn’t have the key needed for Dictation’s keyboard shortcut; instead, I assigned a key-binding to the “<code>Start Dictation…</code>” menu command in BBEdit (<code>Preferences => Menus & Shortcuts</code>). </p>
</li>
<li>
<p><strong>Operating system</strong>. I am on Apple OS 10.9.5. I don’t know whether or not Soundflower works on later versions of the OS.</p>
</li>
<li>
<p><strong>Hardware</strong>. When recording the sample text, I used a headset to ensure clarity. I honestly have no idea whether Apple’s built-in microphone will do better or worse for this purpose; Dictation may well be optimized for use with that hardware. </p>
</li>
<li>
<p>Transcription takes place in real time, so an hour-long interview will take about an hour to transcribe. During that time the computer apparently can’t be used for any other tasks that might alter focus from the text editor.</p>
</li>
<li>
<p>Apple’s Dictation functionality doesn’t produce identical transcriptions on multiple runs, even from the same original recording. Under “Transcription”, below, are examples, all from the same original recording.</p>
</li>
<li>
<p>Comparing the original text to the transcription, by use of Python’s <code>Difflib</code> library:</p>
<p><code>python
difflib.SequenceMatcher(isjunk=None, string_1, string_2, autojunk=False).ratio()</code></p>
<p>the average “accuracy” is about 91% for the examples shown here, with QuickTime doing slightly worse in the two cases where the speed of the recording was changed.</p>
</li>
</ol>
<h2>Data</h2>
<p>The original text I read from: </p>
<blockquote>
<p>There are those who consider that studies in harmony, counterpoint, and fugue are the exclusive province of the intended composer. But if we reflect that theory must follow practice, rarely preceding it except by chance, we must realize that musical theory is not a set of directions for composing music. It is rather the collected and systematized deductions gathered by observing the practice of composers over a long time, and it attempts to set forth what is or has been their common practice. It tells not how music will be written in the future, but how music has been written in the past. — Walter Piston, Introduction to <em>Harmony</em> (1941)</p>
</blockquote>
<p>The recordings I used, edited to remove a garbled word and with five seconds of silence prepended, are posted to <a href="https://github.com/DataBranner/transcription_on_apple">a public repository</a>. I expect further development of my project to take place there, but I have posted the basic README here for a wider audience.</p>
<h2>Transcription</h2>
<h3>Transcription by Dictation of original recording, speed unchanged</h3>
<h4>Audacity (v. 2.1.0) playback:</h4>
<ol>
<li>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint a few of the exclusive province of the intended conference but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's wrapping the collected and systematize deductions gathered by observing the practice of composers over a long time and it is something that it attempts to set forth what is or has been there coming practice the tells not how music share but how music has been written in the past Walter piston introduction to Harmony making 41</p>
</blockquote>
</li>
<li>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint in a few of the exclusive province of the intended components but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's wrapping the collected and systematize deductions gathered by observing the practice of composers over long time and it is something that it attempts to set forth what is or has been there coming practice the tells not how music sure but how music has been written in the past Walter piston introduction to Harmony making 41</p>
</blockquote>
</li>
<li>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint in a few of the exclusive province of the intended components but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's rather the collected and systematize deductions gathered by observing the practice of composers over long time and it is something that it attempts to set forth what is or has been there coming practice the tells not how music share but how music has been written in the past Walter piston introduction to Harmony making 41</p>
</blockquote>
</li>
</ol>
<h4>QuickTime (v. 10.3) playback:</h4>
<ol>
<li>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint a few are the exclusive province of the intended but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's routing the collected and systematize deductions gathered by observing the practice of composers overlong hot and it attempts to set forth what is old has been there common practice it tells not how music but how music has been written in the past is the introduction to Harmony</p>
</blockquote>
</li>
<li>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint a few are the exclusive province of the intended but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's rocking the collected and systematize deductions gathered by observing the practice of composers over Time and it attempts to set forth what is old has been there common practice it tells not how music but how music has been written in the past is the production harmony</p>
</blockquote>
</li>
<li>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint you are the exclusive province of the intended components but if they reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's wrapping the collected and systematize deductions gathered by observing the practice of composers overwhelmed by and it attempts to set forth what is old has been there coming practice details not how music but how music has been written in the past is the introduction to Harmony</p>
</blockquote>
</li>
</ol>
<h3>Transcription by Dictation of original recording, slowed 15%</h3>
<h4>Audacity (v. 2.1.0) playback:</h4>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint a few are the exclusive province of the intended components but if we reflect that theory must follow practice rarely proceeding it except by chance we must realize that musical theory is not a set of directions for composing music it's robbing the collected and systematized productions gathered by observing the practice of composers over long time but it attempts to set forth what is rule has been there, practice it tells not how music chair but how music has been written in the past is introduction to Harmony biking 41</p>
</blockquote>
<h4>QuickTime (v. 10.3) playback:</h4>
<blockquote>
<p>There are those who consider the studies and harmony counterpoint a few are the exclusive province of the intended but if we reflect back theory must follow practice rarely proceeding except for chance we must realize that musical theory is not a set of directions for composing music it's Robin the collective and systematize productions gathered by observing the practice of composers fool talk and it attempts to set forth what is role has been there, practice it tells not how music but how music has been written in the past is the production harmony</p>
</blockquote>
<h3>Transcription by Dictation of original recording, sped up 15%</h3>
<h4>Audacity (v. 2.1.0) playback:</h4>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint if you are the exclusive province of the intended but if they reflect that theory must follow practice rarely proceeding by chance we must realize that musical theory is not a set of directions for composing music it's rather the collected and systematize deductions gathered budgeting the practice of composers over a long time any attempt to set forth what is has been there come practice it tells not how music but her music has been written in the past what is the introduction to Harmony</p>
</blockquote>
<h4>QuickTime (v. 10.3) playback:</h4>
<blockquote>
<p>There are those who consider that studies in harmony counterpoint if you are the exclusive province of the intended but if they reflect that theory must follow practice rarely proceeding into a chance we must realize that musical theory is not a set of directions for composing music it's rather the collected and systematize deductions gathered budgeting the practice of composers over Time and attempt to set forth what is O has been there compact it tells not how music but her music has been written in the past is the introduction to Harmony</p>
</blockquote>
<p>[end]</p>Interview with Rachel Vincent2016-05-11T00:00:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-11:interview-with-rachel-vincent.html<p>Conducted May, 2016 at the Recurse Center.</p>
<p><strong>RHV</strong>: What got you started programming and why did you come back?</p>
<p><strong>DPB</strong>: My mother moved me to a new school in 1975, when I was 13. There I was exposed for the first time to programming and to Latin, subjects foreign to me that I still recall today as tokens of life in a much healthier environment. The middle school computer teacher was a young woman and the class was coed. She taught us BASIC, which ran on an IBM 1130 mainframe with an “input hopper” for reading punchcards and a “lineprinter” for output; there was also a “console typewriter” for some input and output. By 15 I was stewing happily in Latin and FORTRAN IV, and remained so until I graduated. I did most of my coding using punchcards or, later, on a paper terminal connected to a PDP11, sometimes staying in the computer room into mid-evening to do so. I also owned a programmable calculator for which I could write a sort of procedural bytecode language, each code corresponding to a discrete keystroke on the calculator. </p>
<p>The new school adhered to the relic of a progressive educational philosophy, one of those that originated around the First World War and akin to the later Unschooling movement that now vivifies RC. Students had unstructured “lab” time scheduled every day, during which we were supposed to meet and study one-on-one with teachers, on the basis of “contracts” with each of them. But I discovered that at these times I could vanish into the library (which was enormous and boasted a complete set of Loeb Classics) or the computer room, and the Powers apparently considered me to be operating within appropriate parameters and left me alone. In retrospect, this liberty and this access to books and computers infected me with the spore of the “questing” life — the life spent in study.</p>
<p>So a lot of the time that I spent within the walls of my high school was invested in FORTRAN and Latin. But after graduation I abandoned them both for new loves. In college I immersed myself in Chinese language and articulatory phonetics, and after working for a while on a program to simulate the ritual of consulting the <em>Yìjīng</em> (“I Ching”), I gave up programming altogether. At the time I had only experienced strictly procedural programming — little more than scripting — and I had no more than the dimmest notion of basic things like time complexity and memory allocation.</p>
<p>Chinese and phonetics required assorted technical skills, skills I reveled in, but none of them were in any way automated. Proficiency in Chinese combined perhaps a half-dozen challenging skills involving reasoning and different sorts of memory (including kinesthetic memory and memory for pitch), and I turned out to be good at most of them; articulatory phonetics depended on one’s ear and tongue, and mine were sharp. I forgot all about procedural programming and eventually went on to graduate school to study at the feet of authorities in Chinese dialect classification, historical phonology, and general sinology (the philology of traditional Chinese literature). My dissertation advisor treated me in the traditional way of the Doktorvater that I think almost no one in the sciences and engineering ever encounters now — like a beloved child and colleague. For my dissertation research I spent a couple of years in the Chinese countryside, sometimes in places without electricity, documenting obscure dialects by hand and ear in order to study linguistic history in the region. I returned with a great mass of data, hand-written on paper, that would have to be manually collated.</p>
<p>My return to programming, or it would be better to say my eventual awakening to it, began when I was writing my dissertation in 1996, and got fed up with Microsoft Word. Word v5.1 did not handle the Chinese script or the International Phonetic Alphabet (IPA) satisfactorily, and the more advanced v6.0 would not run on my low-end laptop. I could write my own IPA font using special font-design software, but Chinese was a real headache — we graduate students passed around samizdat copies of Taiwan software and used hacks to support non-Western scripts. As a replacement for Word, I stumbled on the small application Nisus (still in production today), which supported multilingual word processing in the era before Unicode. Nisus’s search/replace tool used Perl-flavored regular expressions (regex), which I learned by trial and error and found very stimulating. Incorporated into in-application “macros”, regex let me write procedural scripts to search or edit the text files where my dialect data was stored.</p>
<p>But I really discovered true programming only in 2009. By then I had become a professor at a university, gotten tenure, and left my professorship after coming to suspect there must be more interesting challenges for me. I went to work in the tech industry, in a machine translation start-up, holding a responsible but relatively non-technical position. When the company closed after the 2008-9 economic collapse, Norman Kabir told me, “You should learn to code,” and being at loose ends I did, at age 47. I started learning Python, very hesitantly, dabbling with manipulating Chinese strings in Python 2, which forced me to learn about encodings. I was lucky to be taken in by Gloria Willadsen, who had founded the New York Python Meetup and was mentoring a few people at a time in Python in order to foster best practices. I felt I should try to get some sort of formal training, and so matriculated as a second-degree Engineering undergraduate at the City College of New York (“City”) in 2010. I soon decided to attend part-time, giving as much energy as I could to each class in order learn the content reasonably well (rather than skimming, as many undergraduates are forced to do). I was adjuncting to pay the bills, doing a lot of sinology and getting things published that I had had to put on hold earlier because of the academic grind, but in three years I finished the seven courses that made up the Computer Science (CS) minor, while teaching, publishing, and so on. It took me a while to find out, though, that in a CS program you learn CS, not programming. CS consists of things that are useful to programming, though. I only really started coding every day, following my own program of study, about a month before I came to RC — I was fifty at that point, at the end of 2012.</p>
<hr />
<p><strong>RHV</strong>: What were those “things that were useful to programming”?</p>
<p><strong>DPB</strong>: The most important ones were discrete math, data structures, and algorithms. I also gained from courses in probability theory and theoretical computer science. I am not very good at math, but I worked hard and managed to do well in them. There were also two hands-on coding courses in the core curriculum, and I have come to doubt their value. For one thing, articulation between them and the more theoretical curriculum was poor.</p>
<p>But those first five courses I mentioned I would recommend to anyone who wanted to enrich their programming life — they have all proven deeply useful, and it’s hard to describe what a pleasure it was to study them. </p>
<hr />
<p><strong>RHV</strong>: What’s the most frustrating day or event you’ve ever had as a programmer? </p>
<p><strong>DPB</strong>: There have been too many to name. Being frustrated is a regular part of my experience while programming. </p>
<p>One case that springs violently to mind happened during my last class at City, just before I joined RC — a course in Java and Android. I thought I would start learning the Android material by trying the official Google introductory tutorial. And the code it supplied didn’t work — I spent days and days and eventually identified five serious errors that had to be corrected before their code worked as prescribed. I learned a lot from the exercise, but the frustration exceeded whatever satisfaction I had. After that, I managed to write an app, but I have never felt like working in Android again. I’d rather work with tools that seem carefully maintained and documented.</p>
<p>I like detail, I’m curious, and I’m stubborn — that combination makes me willing to dig interminably for answers. It is not an unusual mix of traits but I think I have it to a severe degree, and it taints much of what I do. Among other things, it makes me slow to ask for help, to my detriment. </p>
<p>If I ever learn to give up sooner and ask for help, I’m sure I’ll be a better programmer. One of the signs of being a good programmer is observing yourself to be flailing. That is why programming seems much easier when you’re pair-programming, because you can see the other person flailing and then easily conclude that you, too, must be flailing. But when you’re alone, self-observation is difficult. So a day goes by and then another, and you’re still struggling, or perhaps your struggle has branched off into some sub-struggle or meta-struggle or para-struggle, or all of these at once. Pairing is much more efficient than by just a factor of two. Your learning is deeper, and there are many more lines of experience running into your mind — you are reading your partner’s body language, which includes responses to your own body language, and all sorts of useful things are happening.</p>
<hr />
<p><strong>RHV</strong>: How has your background in academia informed your approach to programming itself and to learning new things in relation to programming?</p>
<p><strong>DPB</strong>: People often think of me as an academic who moved into coding. I don’t think of myself that way at all. The mix of traits I’ve described above — love of detail, curiosity, and stubbornness — has led me to, among other things, an academic career and coding life. But I think it has led me to each separately.</p>
<p>In the earlier, “typewriter age” when a lot of my learning habits were formed, it wasn’t always easy to go and simply look things up. Reference books, if you had access to them, were selective by nature, and sometimes you didn’t have access to them at all. You couldn’t necessarily just go get whatever you wanted, because you didn’t necessarily have access, and sometimes it wasn’t obvious at all where you would have to go to get what you wanted to know. That affected the kind of searching you did for information — you did not automatically assume that you could or would find it. I have the feeling these days that computational resources lead me to use my mind in ways that are different from how I did when there were only paper resources — I have the impression that paper resources required more factual and spatial memory and less reasoning and kinesthetic memory. I have an idea that programming involves, for me, nothing less than my kinesthetic imagination as a form of visualization. (Actually, I have the same experience when reading Classical Chinese.) But I’m not sure how that affects programming itself. And it’s easy to imagine today that everything you want to know is somewhere on the Internet, if you just phrase your search query the right way. I’m pretty sure that sensation, vivid as it is, is quite wrong.</p>
<hr />
<p><strong>RHV</strong>: Do you find parallels between programming as a practice and academic research? or life in academia in general, if not research? </p>
<p><strong>DPB</strong>: I understand you’re asking about social issues rather than how we establish what is true — about the Thomas Kuhn angle rather than the Karl Popper angle. One point is that industry is a lot more hard-headed than a Humanistic department in a university. Another point concerns collaboration. And then there’s the question of power dynamics among people. </p>
<p>First the question of hard-headedness. College professors, especially after tenure and especially in the Humanities, often think of themselves as independent contractors — they may go for decades without any supervision or validation of their teaching and research. That is very different from the experience of most programmers in a company, where your work contributes to a collective business product and where anyone not meeting expectations may be dismissed without warning.</p>
<p>Teaching may sometimes require you to adhere to some external syllabus or rubric — but in my courses, from graduate school onward, I don’t think there were more than ten occasions, over about 25 years, when a visitor sat in one one of my classes to make a neutral observation of how I taught. When I ran my university’s Chinese Program I strongly encouraged all language faculty to observe each other’s classes regularly, but that was done for mutual enlightenment, not critical evaluation. In research, I never had to worry about meeting external criteria imposed by funding agencies — what few grants there were in my stone-cold fields generally went to an individual for individual work, and as a professor — in theory, at least — I had plenty of time to work on whatever I wanted. (I say “in theory” because in practice, as head of the Chinese program, I had a lot of administrative chores to discharge, and those cut into my research time.)</p>
<p>On the other hand, academic programs where graduate students live on funding from their professors — these are much more common in the sciences, engineering, and power-oriented fields like linguistics and education — are quite different from what I experienced in an unmodish Chinese philology program. In a hot field, there are satanic quantities of paperwork to be done, budgets to be planned and expenses justified, and a participant who fails to fulfill expectations may be sacked. </p>
<p>Now, as to collaboration. My academic research life was solitary, apart from fieldwork. I didn’t learn to collaborate on academic projects until after I left academia. I think collaborating on programming projects is easier — it’s certainly more accepted among engineers than in the Humanities — although it’s not easy to find coders who want to commit with whole heart to a long-term but possibly non-commercial collaboration.</p>
<p>Power dynamics between people seem to me about the same in both environments — there’s a lot of chitchat and wasted time, unless you take care. There are servile flatterers in low positions and stuffed shirts in high positions. There are “honeysuckles” (and other climbing creepers) at all levels. And human beings generally pay more attention to prestige and reputation than to substance.</p>
<hr />
<p>Although you’re asking a Thomas Kuhn question, I’m more interested in the Karl Popper reading of what you’ve asked: what strategies can we use to establish knowledge? Briefly, I can think of three. First, software testing has a lot in common with hypothesis-falsification, an important feature dividing good scholarship from bad. Second, theoretical computer science seems to offer models for exploring formal symbolic systems, one of my sinological research interests — how do things like the Chinese “rime tables” (<em>děngyùntú</em> 等韻圖), the Chinese script, or the Gwoyeu Romaztyh 國語羅馬字 romanization system actually represent the things they do? Finally, the coder ideal of favoring “primary sources of truth”, which I discuss later on, is congruent to the practice in philology of consulting either primary or standard sources, rather than derivative works whose relationship to the originals is uncertain.</p>
<hr />
<p><strong>RHV</strong>: What is your approach to learning, let’s say, a new programming language, as when you had to learn Python?</p>
<p><strong>DPB</strong>: When I learned regex, I did so entirely by futzing — I didn’t even know it was a real (and efficiently elaborated) system — I thought I was figuring out some arbitrary notation invented by the Nisus developers. </p>
<p>When I decided to try Python, I bought a couple of simple-looking books and started writing code immediately. I didn’t do a tutorial — I got reference tools and tried my hand at the code directly. Within about six months I had discovered David Beazley’s <em>Python Essential Reference</em>, which I carried with me all the time and read in whenever I had a free moment (just as when I was in graduate school I carried the reduced-type <em>Tsyryuan</em> 辭源 dictionary with me all the time and read in it constantly).</p>
<p>In the time since then, I’ve tried tutorials many times, but I don’t think they’ve ever worked satisfactorily for me. What they promise is attractive but I always end up disappointed.</p>
<p>As I observe myself, it seems I combine two activities when I learn. One is to dabble and try things out with my own paws, sometimes indulging in compulsive-looking repetition. The other is to sketch out a kind of system that encompasses what I am learning. I sorely need system, but apparently I also need to organize it myself. I’ve often tried using pre-fabricated schemata for what I’m learning — that was true in my study of Chinese historical phonology and Chinese medicine, too, in earlier lives — but it always turns out that I can’t do much with a systematic scheme unless I’ve composed it myself.</p>
<hr />
<p><strong>RHV</strong>: How has academia affected your approach to programming itself?</p>
<p><strong>DPB</strong>: The effects of my scholarly life on my approach to programming are a problem for me. I’ve tended, when left to myself, to work in the domains of expertise in which I made my original academic career. Those domains still interest me very much, even though I don’t make a living in Chinese any more. I mean questions involving Chinese diction or the ordering of sound in Chinese literature — these interest me a lot, and computers can spare me vast amounts of benumbing, repetitive manual labor and answer my questions efficiently. So the kinds of projects that tend to attract me in practice are ways of making manual work efficient, not the sorts of things that fill other programmers with awe at my craftiness.</p>
<p>I would have been wiser, in my second batch, to break away from my expertise and maybe even from every language and tool I was now familiar with, and to dedicate those three months to working in ways new to me — say, only with images, or only with color and shapes. That would be an act of self-fertilization, manuring my own roots. Partly, I return to sinology problems because there are so many sinological questions that I’m still interested in asking, and of course you can learn a lot even by writing code to support an expert domain, rather than just solving puzzles in which you don’t have an emotional investment. But it isn’t healthy that I’ve rarely broken out of my home domains — it means that I’ve tended to let my past interests inform my present work, and I’m now certain I’ve done that too much.</p>
<hr />
<p><strong>RHV</strong>: Are you still getting a lot out of projects like that — are you holding yourself up to where you could be if you did these very different things and seeing that you’re not still growing as a programmer because you’re working in this one sphere, or are you still growing as a programmer even though you’re working in this one sphere, and that’s why you’re loath to jump out.</p>
<p><strong>DPB</strong>: There are several factors to think about: growth overall, growth surrounding familiar tools, and growth in non-programmatic matters supported by programming.</p>
<p>Yes — at this stage of my life as a programmer, in order to grow most overall I must work in some language other than Python. It’s like walking in New York — it’s enormously stimulating but if you want it to remain so over time, at some point you have to start varying your paths. If you’ve been up and down all the long north-south streets, at some point you have to start walking across the island the short way. That’s one aspect to the situation you’re asking about: recognizing the need to wrench oneself into a new paradigm so as to grow in a different way than one has before. RC wisely advises junior programmers to get control of one language very thoroughly, first of all. But exactly when to take on another language is harder to decide.</p>
<p>The BASIC and FORTRAN and bytecode-language that I studied in childhood and the regex-macros that I found myself writing in my thirties share a purely procedural style. It’s possible to write Python the same way, as a scripting tool or with functions (the FORTRAN I learned had “subroutines” rather than named functions). Even in object-oriented style, it’s common for Python methods to be basically procedural, internally. More abstract styles of coding — recursion, higher-order functions, asynchronous execution with callbacks — are possible in Python, but it isn’t clear to me how often they are necessary in the service of your average, practical use case. I have no facility with mathematical puzzles or abstract board games, nor even much interest in them, and I think the puzzle-and-game mindset draws some people to abstract styles of programming much earlier in their coding education than happened in my case. </p>
<p>But that is not the only dynamic in play. Working in corporations for the last year and a half, I’ve learned a lot of tools new to me. Even in Python, I’ve learned some tools and techniques that you tend not to learn when you simply “learn Python” proper. I’ve also learned production tools that I think must be almost impossible to learn outside of a working production environment. That’s another aspect to the situation: I’m certainly growing as a programmer, even though I’ve continued working in Python. I think it would have been out of character for me to have gone on quickly to another language after Python. I tend to perfuse myself with whatever I study. When I imagine myself as a complex computer program, I think of this trait as a depth-first search algorithm.</p>
<p>A third dynamic is this: my research projects are all cases of application; the code is not the important thing. So the code is often much simpler than what I write when learning an algorithm or a new tool, and with good reason: I’m pursuing a different kind of discovery. The research problem isn’t usually so much hard as it is tedious, and the computer lets me answer some questions by doing repetitive tasks for me — something I couldn’t feasibly do by hand. That makes possible kinds of research of great interest to me, but in those cases I’m learning more as a sinologist than as a programmer. With the computer I can pose questions that I couldn’t have posed before, or anyway couldn’t have answered. For instance, there are questions about Chinese usage and prosody that I thought of in the 1980s and only recently became able to answer because I can code. So that’s another aspect to the situation: some of my growth is as a sinologist, and that’s acceptable to me. I think I am in the minority among engineers I know, in or out of the RC clan, in maintaining a life-activity whose level of complexity is that of a career, yet intrinsically apart from programming. I learned to code in the service of that activity, and it’s necessary for me to continue to grow in it. </p>
<p>In sum, I think I’ve delayed one kind of growth that is important to me and that RC considers distinctive of the experience here, but I’ve grown nonetheless in other respects that are considerable — it hasn’t been a waste to have proceeded the way I have, but I find the pressure within me to learn more abstract styles is getting strong.</p>
<hr />
<p><strong>RHV</strong>: You have done two batches at RC. Before your first batch, what were your expectations of what RC would be like?</p>
<p><strong>DPB</strong>: Actually, I now realize that I had no idea what I was walking into.</p>
<p>I would summarize the issues as: meetup culture, skill-level and pairing, generational differences, community, and socialization. And the greatest of these was socialization.</p>
<p><strong>Meetup culture</strong>. I heard about RC in mid-September of 2012, after the media blitz surrounding the Summer ‘12 batch. I had to wait two and a half months for the application-window to open and then applied, with no way to estimate my chances of getting in — I assumed the application queue would be mobbed with the kinds of people I met at the various coding meetups. It was not. But meetups were the only model I had, apart from the ACM club at City College, for how programmers might interact socially while also technically. The model was no use. RC turned out to be entirely different.</p>
<p><strong>Skill-level and pairing</strong>. I knew that batchlings would be at different levels of skill and that mine would be relatively low, and I also thought there would be a lot of interaction between batchlings of different levels — there was much less of that than I expected. I did much of my work alone, rarely pairing. I remember that I felt both surprised and intimidated by some of the pairing that I observed between some parties from the very first day on — it involved people not just sitting together but sometimes located in different parts of the room yet still working together and calling out to one another. It seemed ostentatious to me. In practice it was harder than I expected to get people to pair with me during my first batch.</p>
<p><strong>Generational differences</strong>. That I would be older than most batchlings, I expected — actually, I was the oldest person to attend RC up to that point (though I’ve since been bested). I don’t remember being fazed about that at all — for the previous three years I had been taking college classes, and I was used to being around much younger people. The average undergraduate in my classes at at City was, I suppose, about 20, with a few people up in their thirties; the average age at RC was around 28, and the range in my batch was around 20-48, not including me. But an interesting difference was that at City, the professors (ages around 30-60) were my social peers — I could talk to them about grading policies and pre-tenure strategies and handling plagiarism, even though technically I was studying under them as an undergraduate. In that environment the young were my fellows, but as undergraduates our relationships were subtly competitive and we had relatively little interaction with one another, even though I joined the ACM and served as chapter secretary for a year. At RC, however, the young are my social peers and collectively we are each other’s teachers and students.</p>
<p>There are sometimes small accommodations of attitude that the young and I have to effect in order to “make room” for each other — it’s useful for me to remind myself that doing so is as much my responsibility as theirs. Certainly, it’s been an education and a privilege to enter a peer-group that includes many, many batchlings half my age.</p>
<p>Another aspect of the age issue is that, when I entered, neither RC nor I had any idea how hard it would be for someone senior in years and work-experience, but junior in coding, to be taken seriously for jobs in the tech industry. However, to any fellow “old” people reading this (especially career-changers over 45) — my advice is that persistence is much more effective than despair. It’s also more pleasant, for us and for others.</p>
<p><strong>Community</strong>. The chat-client Zulip (then called Humbug) was not introduced until my first batch. Having a really good internal chat-client enabled the kind of communication that made the community possible, so at the time of my first batch I didn’t expect, and even RC’s founders didn’t yet realize, that the community would turn out to be the crown jewel of the whole RC movement. </p>
<p><strong>Socialization</strong>. I didn’t anticipate how much I would become socialized as a programmer. I had no idea there was even any need for that to happen. But it turned out to be my primary area of growth during my first batch. I don’t mean I didn’t also learn a lot of skills — I learned to write tests, I learned to write SQL properly, I learned how to use an API, how to scrape websites, how to use a range of libraries; I learned a little JavaScript and did a bit of SICP in Racket. I took part in code reviews with Zach Allaun — he even let me sit in on reviews he did of other people’s code, a great education all by themselves. But the primary thing that happened in batch was that I began to think of myself as a programmer, and to understand what that meant. That did not happen during my three years of study at City; it didn’t happen when I was writing FORTRAN in high school — I wasn’t aware till some time after my first batch at RC ended that there exists a “programmer” mindset and that a person could adopt or cultivate it, that there were things you had to make your mind do in order to learn and adjust to this work and its culture — and to realize that I had already begun doing so. I had imagined that I was going to RC to learn new programming methods or improve at those I already knew, and while that certainly happened, it wasn’t nearly as important as my socialization.</p>
<p><strong>RHV</strong>: You mentioned that you cultivated the mindset of a programmer in your first batch. How would you describe that mindset?</p>
<p><strong>DPB</strong>: Programmer culture expresses itself through many memes (in the original, Susan Blackmore sense of the word). Some of those I became alive to through RC are best practices, prototyping, openness to jargon, and avoiding tertiary sources of information. Two of those can be covered quickly. First, best practices. Python has exceptionally well-described norms, but during and after my first batch I gradually caught on to the fact that the several facilitators who specialized in it had different coding habits. The lesson for me in that was to look to the prescriptions and the practice in Python’s docs and sourcecode, rather than to trust the expert advice I got from anyone, albeit given in good faith. Second, prototyping. Because RC is a learning rather than a production environment, it was useful to set a project aside as soon as I had “made the point”, rather than trying to bring it to a perfect state. One of the things RC seems less suited to is learning production techniques. Thinking of my projects as sketches rather than finished works has been helpful for making the most of limited time during batch.</p>
<p><strong>Jargon</strong>. During my first batch I made progress overcoming the psychological obstacle of jargon. One of the signs that you are not yet socialized as a programmer is a feeling of unease when trying to draw breath in the terminological miasma of modern coding life. I learned to do this by noticing technical jargon, recognizing it as jargon, and remembering it, even if I didn’t yet understand it. Sometimes, when I now encounter a new term, all I really have time to do is to make a note of it and its context — as though I were encapsulating a function’s state-environment in a closure — for later reconstitution. </p>
<p>A lot of programming terminology is arbitrary. There is almost no way the name of a language or framework could be otherwise, and in our time these things are burgeoning like strains of bacteria in a damp, dark place. But even when a term has a straightforward motivation, that motivation tends to be hard to retrieve without special knowledge, and so transparency is defied. Think of “currying” a function — it is named after a mathematician and has nothing to do with putting a horse’s hair in order or making an egg more interesting. Think of a “lambda” function — it was meant presumably to suggest the initial <em>l</em> (Greek <em>λ</em>) of <em>logical</em>, in lambda (= logical) calculus.* And why do you suppose time complexity is represented with a “big O”?**</p>
<p>[* A comment by Lindsey Kuper let me to an unsourced remark by Henk Barendregt ("<a href="http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=FE67E24FDC9F2E1F68EE9EF731B49C21?doi=10.1.1.26.7908&rep=rep1&type=pdf">The Impact of the Lambda Calculus in Logic and Computer Science</a>", <em>The Bulletin of Symbolic Logic</em>, 3/2 [June, 1997]: 182), to the effect that <code>λ</code> was an accident propagated from <code>x̂</code> to <code>⋀x</code> to <code>λx</code>. I'm dubious, as the circumflex was common in the era of lead type, and it's hard to imagine it not being to hand or being hard to position. Also, I think it was rare to use recognizable letters without their standing for a word in someone's mind.]</p>
<p>[** I've given my thoughts about the origin of <code>𝑂()</code> in a <a href="https://www.researchgate.net/publication/261974470_The_Chinese_Roots_of_Linear_Algebra_by_Roger_Hart">review of Roger Hart's <em>The Chinese Roots of Linear Algebra</em></a> (<em>Journal of the American Oriental Society</em> 131[4; January 2011]: 652-655), p. 654.]</p>
<p>Using jargon is a sociolinguistic tactic for delimiting an in-group from out-group, so with that in mind, junior programmers should exert themselves to neutralize this obstacle. I began to be aware that this was possible for me during my first batch, and that doing so was part of the programmer mindset. </p>
<p><strong>Avoiding tertiary sources</strong>. Another aspect of programmer culture is to avoid derivative sources of truth, even when they are convenient, and to prefer secondary and primary sources when feasible. I did not really start to understand this point until my second batch, and it has only been in the past year that I have come to feel it in my marrow.</p>
<p>One of our goals as coders is to try to formulate a model of how any particular tool works. What are our options for that? Exploring the tool first-hand is a common way to form that model. Native docs are an important source, although they are secondary — as are comprehensive reference works. A more difficult way, but a powerful one, is to examine the tool’s own source code — source code is the ultimate definition of what a piece of code does, so this is the most direct path we have to forming our model. </p>
<p>It’s common for programmers, when they’re puzzled about something, to turn first to derivative sources on sites like StackExchange or Quora, where you can read answers, and sometimes very good ones, to your questions. Googling an error message is a very common first step in debugging. But while going to a derivative source often gets you an answer quickly, it’s also the worst option from the point of view of learning, because you can get an answer without, usually, contributing to your intellectual model of the tool. (Blog posts can be an exception to this.) Part of what I understand as the programmer’s mindset is to cultivate the discipline of playing with the tool using your own hands, consulting the docs, and perhaps reading the sourcecode — all before visiting derivative sites. Learning from primary and secondary sources is easier now than it once was, because there are now REPLs and code sandboxes for many languages; many libraries and applications now have open-source code. Among secondary sources, man pages go back a long way, but now we can also read docs on the web or packaged into apps for mobile devices; there are also GUI-based doc-readers. </p>
<hr />
<p>An aside: How about a “locked-box Recurse Center”, an “RC @ Sea”, where the participants would have no access to the Internet for, say, a three-month batch. We would have only source code for the tools we chose to bring with us, built-in documentation for those tools, and each other to consult if we wanted to understand something. No StackExchange or other third-hand sites — in fact, even at second-hand, ideally nothing further-removed from the code itself than built-in documentation. The goal of this disciplined exercise would be to cultivate resourcefulness.</p>
<hr />
<p><strong>RHV</strong>: Why do you choose to program?</p>
<p><strong>DPB</strong>: I don’t think I choose to program; I usually have something within me that just has to come out. I don’t choose to write prose, either. There seems to be a kind of compulsiveness involved. Neither the code nor the prose necessarily comes out easily, sometimes I can’t get into the state of mind to do it, or get the “things” to form correctly, but there are these “things” that have to come out and eventually they do. </p>
<hr />
<p><strong>DPB</strong>: What’s your goal in doing this?</p>
<p><strong>RHV</strong>: My goal in doing this is to collect as many different origin-stories of people, as programmers, of the RC community, as possible. Because I think that in the scheme of communities of programmers we have a lot of very interesting ones, and it would be very nice to share them because I feel that programming still has a mystique about it — it seems that programmers are sort of “other’ — they’re often lumped in with “genius astrophysicist” and things like that: “I could never do that.” </p>
<p>[end]</p>The Pre-Morse Origin of Two Morse Code Symbols2016-05-07T11:30:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-07:the-pre-morse-origin-of-two-morse-code-symbols.html<p>Yuen Ren Chao writes:</p>
<blockquote>
<p>It may be noted in passing that the symbol <code>•••---•••</code>, with no spaces, was originally made up as an arbitrary symbol for distress and only subsequently read as symbols for the letters SOS, which strictly would have spaces between the dots and dashes.</p>
</blockquote>
<p><em>Language and Symbolic Systems</em>, (Cambridge: Cambridge University Press, 1968), p. 199.</p>
<p>[end]</p>“The Man Who Knew Infinity” — 2015 movie about Ramanujan2016-05-07T00:15:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-07:the-man-who-knew-infinity.html<p>This was not a bad movie, although I was annoyed that the actor playing Ramanujan really doesn't look anything like the historical character. </p>
<p>But the movie contains certain narrative formulas that have begun to irritate me a lot in movies about people who are good at math and other sorts of abstract thinking. The main ones are listed below this spoiler-line:</p>
<hr />
<p><strong>(spoilers below)</strong></p>
<hr />
<ul>
<li>young genius taught a lesson (or mostly so) by older hands</li>
<li>justification by faith vs. works (end vs. means)</li>
<li>suddenly the whole thing came to me in a flash</li>
</ul>
<p>Some of this stuff is actually documented as part of Ramanujan's life and experiences, and the issues are worth talking about when they correspond to real life. </p>
<p>But I'm struggling against over-familiarity with these commonplaces. The 2014 Turing movie “Imitation Game” disturbed me because of these issues — it seems to be thought quite acceptable to present a completely fictional Alan Turing for some reason that I can't understand. It is not acceptable, and I keep meaning to write a about this. But not here.</p>
<hr />
<p>It's nice to see attention paid to the proper pronunciation of someone's name, and that issue figured in the plot.</p>
<p>[end]</p>Why does Python have two ways to filter a comprehension?2016-05-06T22:25:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-05-06:why-does-python-have-two-ways-to-filter-a-comprehension.html<p>“Filtering” means placing a restriction on the elements to be added to a list returned by Python’s comprehension structure or the widely implemented <code>map</code> function. In Python it normally looks like this:</p>
<p>You can map a range of integers to a list:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)]</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
</pre></div>
<p>And you can filter it, so to include only odd numbers, by placing an <code>if</code>-clause <em>after</em> the <code>for</code> clause:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span><span class="p">]</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
</pre></div>
<p>But if you use the fuller <code>if-then</code> syntax to filter or supplement the mapping process — say, to include <code>0</code> if an element is not odd — you place it <em>before</em> the <code>for</code> clause:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="p">[</span><span class="n">i</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)]</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">9</span><span class="p">]</span>
</pre></div>
<p>Why does Python have two different syntaxes for filtering in a comprehension, one before the <code>for</code> clause and one after?</p>
<p><strong>Answer</strong>: It doesn’t. There are two different things happening here.</p>
<p>Only the first example is genuine filtering, which modifies the <code>for</code> clause with an <code>if</code> clause.</p>
<p>The second example is a two-way decision expression, an in-line <code>if-else</code> statement determining the assignment of <code>i</code> at the far left of the comprehension.</p>
<p>Keyword <code>else</code> never occurs in genuine filtering, while it is required in a two-way decision expression. It's coincidental that these two structures both seem to be serving the same function — in reality, they are serving different functions.</p>
<p>[end]</p>There is no ternary operator in Python2016-04-30T18:10:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-04-30:there-is-no-ternary-operator-in-python.html<p>In this post I describe the “ternary operator” and argue that although people refer to a certain Python structure by this name, in reality Python doesn’t have a ternary operator at all.</p>
<h2>What does it mean to be “ternary”?</h2>
<p>“The ternary operator” usually means a specialized <code>if...else...</code> construction, first introduced in C:</p>
<div class="highlight"><pre><span class="n">condition</span> <span class="o">?</span> <span class="n">if_true</span> <span class="o">:</span> <span class="n">if_false</span>
</pre></div>
<p>(Kernighan and Ritchie, <em>The C Programming Language</em>, second edition, secs. 2.11, A7.16.)</p>
<p>The word “ternary” itself is well known — maybe best known in the tech community — in this usage. It isn’t limited to computer science — it just means “three-part” or “of order 3”, and it corresponds to <em>unary</em> for “one-”, <em>binary</em> for “two-”, and <em>quaternary</em> for “four-” in the same senses. An important usage of <em>ternary</em> other than in programming is in music: <em>ternary measure</em>: ‘triple time’ (a time signature of 3/4, 3/8, etc.).</p>
<p>In programming we are really talking about what we should call a “two-way decision expression”. In C this expression is “an operator” because it is a single entity, even though it has two parts that always appear separated by one of the arguments. Granted that the format is anomalous, many languages have adopted it: JavaScript, Java, Ruby, Bash, PHP. Here is Bash, for instance:</p>
<div class="highlight"><pre><span class="k">$((</span> condition ? if_true : if_false <span class="k">))</span>
</pre></div>
<p>This is the only C <em>operator</em> that requires three arguments — we don’t bother using ternary to describe functions that take three arguments, or series of keywords acting on three expressions. </p>
<p>Does Python have something comparable?</p>
<h2>Arguments against a Python ternary operator</h2>
<p>Below I make three arguments against the idea that Python has a comparable structure:</p>
<ol>
<li>
<p>argument by form: Python syntax</p>
</li>
<li>
<p>argument by effect: Python bytecode</p>
</li>
<li>
<p>argument by design: Python expression grammar</p>
</li>
</ol>
<h3>Argument by form: Python syntax</h3>
<p>In C, significantly, the element <code>?</code> isn’t otherwise used as an operator. In particular, it doesn’t otherwise have the meaning <code>if</code>. Operator <code>:</code> appears only in an unrelated use (declaring the bits assigned to a field in a struct). Together,</p>
<div class="highlight"><pre><span class="o">?</span> <span class="o">:</span>
</pre></div>
<p>in C constitutes a single operator that cannot reasonably be confused with anything else.</p>
<p>Contrast the situation in Python. The Python structure that many people refer to as a ternary operator is not an operator at all — it is an expression, and in terms of its superficial form it is just a variety of <code>if</code>-statement syntax, differing in the placement and order of its keywords:</p>
<div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">if</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">else</span> <span class="bp">False</span>
</pre></div>
<p>That is an inline equivalent to this ordinary <code>if...else...</code> statement:</p>
<div class="highlight"><pre><span class="k">if</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">False</span>
</pre></div>
<p>Such a structure does not deserve the name “ternary” because it is not a single operator — it is a series of keywords.</p>
<p>Question: Does the rearranged syntax mean that, internally, Python handles it differently from a standard <code>if...else...</code> statement?</p>
<h3>Argument by effect: Bytecode instructions in CPython</h3>
<p>To answer that, we can use the <code>dis</code> module to examine empirically the bytecode instructions into which a two-way decision expression is parsed, and compare it with traditional <code>if...else...</code>. </p>
<p>Here is a simple example:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="kn">import</span> <span class="nn">random</span>
<span class="o">>>></span> <span class="k">def</span> <span class="nf">if_else</span><span class="p">():</span>
<span class="o">...</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">if</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">else</span> <span class="bp">False</span>
<span class="o">...</span>
<span class="o">>>></span> <span class="n">dis</span><span class="o">.</span><span class="n">dis</span><span class="p">(</span><span class="n">if_else</span><span class="p">)</span>
<span class="mi">2</span> <span class="mi">0</span> <span class="n">LOAD_GLOBAL</span> <span class="mi">0</span> <span class="p">(</span><span class="n">random</span><span class="p">)</span>
<span class="mi">3</span> <span class="n">LOAD_ATTR</span> <span class="mi">1</span> <span class="p">(</span><span class="n">randint</span><span class="p">)</span>
<span class="mi">6</span> <span class="n">LOAD_CONST</span> <span class="mi">1</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="mi">9</span> <span class="n">LOAD_CONST</span> <span class="mi">2</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="mi">12</span> <span class="n">CALL_FUNCTION</span> <span class="mi">2</span> <span class="p">(</span><span class="mi">2</span> <span class="n">positional</span><span class="p">,</span> <span class="mi">0</span> <span class="n">keyword</span> <span class="n">pair</span><span class="p">)</span>
<span class="mi">15</span> <span class="n">POP_JUMP_IF_FALSE</span> <span class="mi">22</span>
<span class="mi">18</span> <span class="n">LOAD_CONST</span> <span class="mi">3</span> <span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="mi">21</span> <span class="n">RETURN_VALUE</span>
<span class="o">>></span> <span class="mi">22</span> <span class="n">LOAD_CONST</span> <span class="mi">4</span> <span class="p">(</span><span class="bp">False</span><span class="p">)</span>
<span class="mi">25</span> <span class="n">RETURN_VALUE</span>
</pre></div>
<p>We can see that the function loads <code>randint</code>, chooses 0 or 1 at random, and then based on the result either jumps to address 22 (<code>return False</code>) or continues to address 18 (<code>return True</code>). </p>
<p>And here is an equivalent function using a standard <code>if...else...</code> block:</p>
<div class="highlight"><pre><span class="o">>>></span> <span class="k">def</span> <span class="nf">if_else_standard</span><span class="p">():</span>
<span class="o">...</span> <span class="k">if</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span>
<span class="o">...</span> <span class="k">return</span> <span class="bp">True</span>
<span class="o">...</span> <span class="k">else</span><span class="p">:</span>
<span class="o">...</span> <span class="k">pass</span>
<span class="o">...</span> <span class="k">return</span> <span class="bp">False</span>
<span class="o">...</span>
<span class="o">>>></span> <span class="n">dis</span><span class="o">.</span><span class="n">dis</span><span class="p">(</span><span class="n">if_else_standard</span><span class="p">)</span>
<span class="mi">2</span> <span class="mi">0</span> <span class="n">LOAD_GLOBAL</span> <span class="mi">0</span> <span class="p">(</span><span class="n">random</span><span class="p">)</span>
<span class="mi">3</span> <span class="n">LOAD_ATTR</span> <span class="mi">1</span> <span class="p">(</span><span class="n">randint</span><span class="p">)</span>
<span class="mi">6</span> <span class="n">LOAD_CONST</span> <span class="mi">1</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="mi">9</span> <span class="n">LOAD_CONST</span> <span class="mi">2</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="mi">12</span> <span class="n">CALL_FUNCTION</span> <span class="mi">2</span> <span class="p">(</span><span class="mi">2</span> <span class="n">positional</span><span class="p">,</span> <span class="mi">0</span> <span class="n">keyword</span> <span class="n">pair</span><span class="p">)</span>
<span class="mi">15</span> <span class="n">POP_JUMP_IF_FALSE</span> <span class="mi">22</span>
<span class="mi">3</span> <span class="mi">18</span> <span class="n">LOAD_CONST</span> <span class="mi">3</span> <span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="mi">21</span> <span class="n">RETURN_VALUE</span>
<span class="mi">4</span> <span class="o">>></span> <span class="mi">22</span> <span class="n">LOAD_CONST</span> <span class="mi">4</span> <span class="p">(</span><span class="bp">False</span><span class="p">)</span>
<span class="mi">25</span> <span class="n">RETURN_VALUE</span>
</pre></div>
<p>The sequence of instructions — opcodes, instruction-addresses, and arguments — is identical. These are the same function, apart from the trivial disparity of how many lines the original code is spread over.</p>
<p>Question: Granted that the <code>if...else...</code> statemnt and the two-way decision expression are fundamentally the same in syntax and underlying bytecode instructions, does the parser travel from syntax to bytecode by the same path in both cases?</p>
<h3>Argument by design: Python grammar</h3>
<p>To answer that, we can look at the Python expression grammar — the roadmap describing how Python is parsed. An expression grammar is a series of lines — on the left part of the line is a single symbol, followed by a colon; to the right of the colon is some expression or series of expressions that can be decomposed into keywords (in quotes), symbols, and a few basic operators:</p>
<ul>
<li><code>(...)*</code> (parentheses and asterisk) for zero or more occurrences of what is contained in the parentheses;</li>
<li><code>|</code> (pipe) for logical disjunction;</li>
<li><code>[...]</code> (square brackets) for optional content that occurs at most once.</li>
</ul>
<p>Python today uses a symbol <code>test</code> for basic conditional evaluation, beginning in <a href="https://docs.python.org/release/2.6/reference/grammar.html">v. 2.6</a>. Here is a pertinent snippet of the expression grammar defining <code>if</code> and the <code>test</code> symbol:</p>
<div class="highlight"><pre><span class="n">if_stmt</span><span class="p">:</span> <span class="s">'if'</span> <span class="n">test</span> <span class="s">':'</span> <span class="n">suite</span> <span class="p">(</span><span class="s">'elif'</span> <span class="n">test</span> <span class="s">':'</span> <span class="n">suite</span><span class="p">)</span><span class="o">*</span> <span class="p">[</span><span class="s">'else'</span> <span class="s">':'</span> <span class="n">suite</span><span class="p">]</span>
<span class="o">...</span>
<span class="n">test</span><span class="p">:</span> <span class="n">or_test</span> <span class="p">[</span><span class="s">'if'</span> <span class="n">or_test</span> <span class="s">'else'</span> <span class="n">test</span><span class="p">]</span> <span class="o">|</span> <span class="n">lambdef</span>
<span class="n">or_test</span><span class="p">:</span> <span class="n">and_test</span> <span class="p">(</span><span class="s">'or'</span> <span class="n">and_test</span><span class="p">)</span><span class="o">*</span>
<span class="n">and_test</span><span class="p">:</span> <span class="n">not_test</span> <span class="p">(</span><span class="s">'and'</span> <span class="n">not_test</span><span class="p">)</span><span class="o">*</span>
<span class="n">not_test</span><span class="p">:</span> <span class="s">'not'</span> <span class="n">not_test</span> <span class="o">|</span> <span class="n">comparison</span>
<span class="n">comparison</span><span class="p">:</span> <span class="n">expr</span> <span class="p">(</span><span class="n">comp_op</span> <span class="n">expr</span><span class="p">)</span><span class="o">*</span>
<span class="n">comp_op</span><span class="p">:</span> <span class="s">'<'</span><span class="o">|</span><span class="s">'>'</span><span class="o">|</span><span class="s">'=='</span><span class="o">|</span><span class="s">'>='</span><span class="o">|</span><span class="s">'<='</span><span class="o">|</span><span class="s">'<>'</span><span class="o">|</span><span class="s">'!='</span><span class="o">|</span><span class="s">'in'</span><span class="o">|</span><span class="s">'not'</span> <span class="s">'in'</span><span class="o">|</span><span class="s">'is'</span><span class="o">|</span><span class="s">'is'</span> <span class="s">'not'</span>
<span class="n">expr</span><span class="p">:</span> <span class="n">xor_expr</span> <span class="p">(</span><span class="s">'|'</span> <span class="n">xor_expr</span><span class="p">)</span><span class="o">*</span>
<span class="n">xor_expr</span><span class="p">:</span> <span class="n">and_expr</span> <span class="p">(</span><span class="s">'^'</span> <span class="n">and_expr</span><span class="p">)</span><span class="o">*</span>
<span class="n">and_expr</span><span class="p">:</span> <span class="n">shift_expr</span> <span class="p">(</span><span class="s">'&'</span> <span class="n">shift_expr</span><span class="p">)</span><span class="o">*</span>
<span class="o">...</span>
</pre></div>
<p>(Symbols <code>suite</code>, <code>lambdef</code>, <code>shift_expr</code>, and subsequent replacement expressions are omitted for simplification.)</p>
<p>Notice is that the <code>if...[elif...]else...</code> statement is now a kind of wrapper around conditional evaluation with <code>test</code>:</p>
<div class="highlight"><pre><span class="n">if_stmt</span><span class="p">:</span> <span class="s">'if'</span> <span class="n">test</span> <span class="s">':'</span> <span class="n">suite</span> <span class="p">(</span><span class="s">'elif'</span> <span class="n">test</span> <span class="s">':'</span> <span class="n">suite</span><span class="p">)</span><span class="o">*</span> <span class="p">[</span><span class="s">'else'</span> <span class="s">':'</span> <span class="n">suite</span><span class="p">]</span>
</pre></div>
<p>Interestingly, <code>test</code> is more rigid:</p>
<div class="highlight"><pre><span class="n">test</span><span class="p">:</span> <span class="n">or_test</span> <span class="p">[</span><span class="s">'if'</span> <span class="n">or_test</span> <span class="s">'else'</span> <span class="n">test</span><span class="p">]</span> <span class="o">|</span> <span class="n">lambdef</span>
</pre></div>
<p>It <em>requires</em> <code>else</code>, which is optional in an <code>if</code> statement. Symbol <code>test</code> itself resolves ultimately to a <code>comparison</code> expression</p>
<div class="highlight"><pre><span class="n">comparison</span><span class="p">:</span> <span class="n">expr</span> <span class="p">(</span><span class="n">comp_op</span> <span class="n">expr</span><span class="p">)</span><span class="o">*</span>
</pre></div>
<p>In other words, in Python a two-way decision expression is not a distinct structure from an <code>if</code> statement at all.</p>
<p>So there is simply no “ternary operator” in Python. </p>
<hr />
<h2>Addendum: How the two-way decision statement got into Python</h2>
<p>Symbol <code>test</code> had initially been introduced along with <code>testlist</code> in v. <a href="https://docs.python.org/release/2.3/ref/lists.html">2.3</a> for support of filtering (without an <code>else</code> option) in list comprehensions, already in existence since v. <a href="https://docs.python.org/release/2.0/ref/lists.html">2.0</a>.</p>
<p>Actual two-way decision expressions entered Python in the rule for the <code>expression</code> symbol, between versions <a href="https://docs.python.org/release/2.4/ref/grammar.txt">2.4</a>:</p>
<div class="highlight"><pre><span class="n">expression</span> <span class="p">::</span><span class="o">=</span> <span class="n">or_test</span> <span class="o">|</span> <span class="n">lambda_form</span>
</pre></div>
<p>and <a href="https://docs.python.org/release/2.5/ref/grammar.txt">2.5</a>:</p>
<div class="highlight"><pre><span class="n">expression</span> <span class="p">::</span><span class="o">=</span> <span class="n">or_test</span> <span class="p">[</span><span class="k">if</span> <span class="n">or_test</span> <span class="k">else</span> <span class="n">test</span><span class="p">]</span> <span class="o">|</span> <span class="n">lambda_form</span>
</pre></div>
<p>In versions <a href="https://docs.python.org/release/2.5.1/ref/grammar.txt">2.5.1</a> through <a href="https://docs.python.org/release/2.5.4/ref/grammar.txt">2.5.4</a> this rule was amplified to:</p>
<div class="highlight"><pre><span class="n">expression</span> <span class="p">::</span><span class="o">=</span> <span class="n">conditional_expression</span> <span class="o">|</span> <span class="n">lambda_form</span>
<span class="o">...</span>
<span class="n">conditional_expression</span> <span class="p">::</span><span class="o">=</span> <span class="n">or_test</span> <span class="p">[</span><span class="s">"if"</span> <span class="n">or_test</span> <span class="s">"else"</span> <span class="n">expression</span><span class="p">]</span>
</pre></div>
<p>But in <a href="https://docs.python.org/release/2.6/reference/grammar.html">v. 2.6</a> the symbol <code>test</code> was restored, to replace <code>conditional_expression</code>, and that is how things remain in <a href="https://docs.python.org/3.5/reference/grammar.html">v. 3.5</a>. </p>
<p>In <a href="https://docs.python.org/release/2.6/reference/grammar.html">v. 2.6</a>, symbol <code>comparison</code> now pointed to <code>expr</code>, rather than <code>or_expr</code>, as it had from <a href="https://docs.python.org/release/1.4/ref/ref5.html#HDR16">v. 1.4</a> onward; <code>expr</code> now pointed to <code>xor_expr</code>. What that means is that the <code>test</code> symbol that ultimately supported <code>if</code> statements until v. 2.6 was founded on logical <code>OR</code>.</p>
<h2>Addendum on <em>quaternary</em></h2>
<p>Note that it has only two instances of letter <em>r</em> — <em>quaternary</em>, not *<em>qua<strong>R</strong>ternary</em>.</p>
<p>Before you ask: <em>quinary</em>: ‘five-part’ or ‘of order 5’. <em>Sexenary</em>, <em>septenary</em>, <em>octonary</em>, <em>nonary</em>/<em>novenary</em>, and <em>decenary</em> are also attested. <em>Vicenary</em>/<em>vigenary</em>/<em>vigesimal</em> for twenty, <em>triacontad</em> for thirty, <em>centenary</em> for one hundred, <em>millenary</em> for one thousand. Stop me, someone.</p>
<p>[end]</p>Does Fortran have a two-way decision function?2016-04-29T21:00:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-04-29:does-fortran-have-a-two-way-decision-function.html<p>A “two-way decision function” usually means something that emulates the The ternary operator, an in-line <code>if...else...</code> construction, first introduced in C:</p>
<div class="highlight"><pre><span class="n">condition</span> <span class="o">?</span> <span class="n">if_true</span> <span class="o">:</span> <span class="n">if_false</span>
</pre></div>
<p>(Kernighan and Ritchie, <em>The C Programming Language</em>, second edition, secs. 2.11, A7.16.)</p>
<p>Some writers describe <a href="https://gcc.gnu.org/onlinedocs/gfortran/MERGE.html"><code>merge</code></a>, from the 1995 revision of Fortran, as such a function. But it differs somewhat from a generic two-way decision. This <code>merge</code> performs element-by-element comparison of two arrays and produces a third array:</p>
<div class="highlight"><pre><span class="nb">merge</span><span class="p">(</span><span class="nv">source_if_condition_true</span><span class="p">,</span> <span class="nv">source_if_condition_false</span><span class="p">,</span> <span class="nv">condition</span><span class="p">)</span>
</pre></div>
<p>This is comparable to Python</p>
<div class="highlight"><pre><span class="p">[</span><span class="n">x</span> <span class="k">if</span> <span class="n">condition</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">else</span> <span class="n">y</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">list_x</span><span class="p">,</span> <span class="n">list_y</span><span class="p">)]</span>
</pre></div>
<p>where <code>condition()</code> is a “mask” function returning the truth-state of some condition.</p>
<p>The Fortran function could model a simple two-way decision if used on single-element arrays, but its actual purpose is to recombine the arrays, element by element, hence its name.</p>
<p>[end]</p>Debugging the Art Museum2016-04-28T11:53:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-04-28:debugging-the-art-museum.html<p>I don’t have a very good relationship with representational art, but yesterday I made an effort, which I report now.</p>
<hr />
<p>I took two children of a friend to the Met. They are aged twelve and ten years and I don’t know how much time they’ve ever spent in art museums. I have spent a lot of time — too much for my own well-being. The school where I was immured in my teens is in a part of the world so thickly-grown with museums that they became ordinary hang-out places after school. Not naturally sympathetic to visual art, I feel I’ve been overexposed.</p>
<p>And I don’t think I pass muster as museum docent — I find I am not an inspiring explainer of the meaning or importance of art. I have a lot of doubts, myself, about what I see in museums, and that probably affects what I can do for other people.</p>
<p>A work of art has both physical form and some set of messages, intended or unintended. The physical form has technical issues of execution associated with it, but also style, which grades into the area of messages. I’m never sure what interplay there is or should be between my reaction to the physical form and the other matters. And often what I know about the messages — frankly — does not interest me. Compared to such organized abstractions as a well-constructed sonata movement or handwritten <em>kanji</em>, which seize my attention if not my very soul, it’s hard for me to get stirred up about almost any landscape or portrait. I realize saying this may condemn me as a boor, but there it is.</p>
<p>On top of that, in a museum I feel that works of art on formal display seem to insist that I deal with them and decide what I think about them, and their aggressiveness disturbs me. So maybe it is best that I be kept away from the impressionable young.</p>
<hr />
<p>After my charges led me to see some Oceanian ritual objects and Roman statuary, and after we had been disappointed that musical instruments, costumes, and the Temple of Dendur were all closed, I took them to see the Met’s large <a href="http://www.metmuseum.org/art/collection/search/488978">Jackson Pollack</a>, in the Twentieth Century Art section. (“Autumn Rhythm [Number 30]”)</p>
<p><img alt="Jackson Pollock: Autumn Rhythm (Number 30)" src="images/jackson_pollock_autumn_rhythm_no_30.jpg?raw=true" /></p>
<p>The reaction was instant. Twelve Years Old sat down in front of the painting and looked at it without interruption. Ten Years Old didn’t waste any time but blurted out from ten feet away, “How is that art?”</p>
<p>All right — I don’t know much about art and what I think I know is probably wrong and in any case I don’t convey it well. But I know something about teaching, and I know how to <em>try</em> to debug a puzzling problem, whether a Classical Chinese sentence or an English poem or a block of code. Analysis comes into it, but so does listening to one’s inner reactions. So I felt summoned to argue.</p>
<p>First, to soften up Ten Years Old I asked him for a definition of art. He didn’t have one ready. That’s a good first step — I don’t have one, either. I admit I’ve had enough years to prepare, but I think I’m in a better state to deal with the confusion that artworks cause me if I don’t have a ready standard to apply to them. </p>
<p>I also asked my charges to look at the painting for a while and see if the way it appeared to them changed at all. And I told them I didn’t think they needed to have an opinion as to whether it was art or not, or good or not, or interesting or not — that day. The picture would be there for a long time and they could spend as long as they needed to think about the question and make up their minds later. I hope they keep thinking about it.</p>
<p>I haven’t made up my mind yet, by the way. That picture has been in the Met or MoMA since I was a boy, and I’m still interacting with it fruitfully. I still don’t know if I like it or not, much less what it means or whether it means anything. I’d say it’s interesting, though.</p>
<p>We tossed around a few possible interpretations. At the end of our time there, we agreed that it could be, in Ten Years Old’s words, “a representation of New York City.”</p>
<p>Twelve Years Old, temperamentally disinclined to disputation, declined to offer any opinions at all. I hope he’s still thinking about it.</p>
<p>Against the implied claim that the piece is not “art”, I also pointed out that it was placed next to <a href="http://www.metmuseum.org/art/collection/search/488914">“The Battle” by Conrad Marca-Relli</a>, which I think invites the viewer to consider contrasts and points of concord with the Pollock.</p>
<p><img alt="Conrad Marca-Relli: The Battle)" src="images/conrad_marca-relli_the_battle.jpg?raw=true" /></p>
<p>I don’t know where this will lead. I hope to have other chances to interact with them about the Pollock. I don’t care if they like it or understand it — what I fear is that they will fail to challenge their own over-quick analysis of it. I’d like to exert gentle pressure on them to keep engaging with it.</p>
<p>Whether out of laziness or lack of aptitude, I don’t really know anything about art. But I do know that holding a difficulty in mind and continuing to engage with it, emotionally as well as analyticallly, is one way of learning to solve not just that problem but problems in general. And I think that’s a skill worth having — coming face to face with an unexpected painting is a chance to practice it.</p>
<p>[end]</p>Learning to Throw Books Away2016-04-28T00:23:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-04-28:learning-to-throw-books-away.html<p>This is a story of learning how to discard books. I’ll tell you why it happened, and then how I handled the imperative for different book collections in my library, and finally where it has left my state of mind.</p>
<h2>January: A burst pipe in the alcheringa</h2>
<p>After I changed careers from academia to tech, I began a long, swampy trudge to find work as a programmer. But once I did find it, I observed myself yielding somewhat to my wife’s entreaties to get rid of at least some of my scholarly library. Reason was hers, because sections of the library are in fields I’m certain I’ll never work in again. Someone else, somewhere, could surely use those books, and for our part we would like to reclaim some of the cubic yards they occupy. In 2014, not long after finding my first coding job, I contacted a large academic society about donating them and started cataloguing them, but work pressures left me little time — what time I had I coveted for more immediate rewards.</p>
<p>At the end of this January, when I was in a state of anguish over a corrosive work environment, Heaven sent a solution (in characteristic dreamtime fashion). I had noticed for some weeks that the boards in our dining room floor were uneven. (I know now that I was being nudged to notice the unevenness in my own emotional floor.) The problem turned out to be a burst radiator pipe, inaccessible underfoot. Recognizing that I might soon burst a hidden pipe of my own, I resigned the job and before long we had the floor ripped up.</p>
<p>There turned out to be very interesting things under the floors of this 107-year-old building! Piles of garbage from the construction process a century ago, among other things. Much of that has decomposed into soil, but there were bits of paper, wood, broken brick and so on. It was wet from the leaking radiator steam, but the floor stayed open for weeks and the soil dried out. The Super and his workers decided not to remove what was under the floor and eventually sealed it up again.</p>
<p>In order to fix the warped floorboards, our entire dining room had to be emptied. It housed several thousand scholarly books tightly packed in a cluster of bookcases. In order to move the bookcases, within the passage of a week or so I handled every last one of the books. The awakened dust stung my fingertips. Once the floor was repaired and refinished, I handled all those thousands of books a second time, and by then I knew I was going to get rid of many of them. I did not yet know how.</p>
<h2>February: Books banished to an adoptive home</h2>
<p>In late February, after the floor was first ripped up, I took a hundred or more math and programming books to the <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Recurse Center</a> for immediate, forcible adoption.</p>
<p>The heuristics for keeping programming books were easy to set: Some are useful because they write about ideas, or because they’re good reference on fact. I have kept most of those. But others are hard to place in terms of these two features. When I was in doubt, books met with banishment.</p>
<p>I tried to recognize when I wanted to a book only because I’m interested in the subject but feel insecure about my knowledge of it. If I think the book useful only out of insecurity, that’s a poor reason. Such a book is neither philosophy nor reference. Many such books have now left my possession.</p>
<p>A small mass of books deal with Turing and Bletchley, from research for an unfinished blog post. Those have stayed — interpreting my motives, it seems I believe the blog post will yet be written.</p>
<p>Some programming books are beautifully designed but not useful — those were all banished.</p>
<p>All the algorithm and theoretical CS books are still living with me, I find. Of those, all but one have been useful at various times and fun to read. But <em>SICP</em> — and its (much more interesting) instructor’s manual — are now living with a friend. I don’t think I’ll see them again.</p>
<p>I had thought of limiting myself to keeping just 20 programming books. I think I ended up with eighty or so. Possibly that is a tactical failure. There is also the loudening claim that on-line documentation is better than any printed volume. I can’t discuss the general assertion, but I know of specific counterexamples — some of those counterexamples still have residency permits in my home — Cormen et al., Kernighan and Pike, <em>The LaTeX Companion</em>, <em>The Python Essential Reference</em>, and others. Some books contain one or two really splendid chapters that justify keeping the whole volume — Mertz’s <em>Text Processing in Python</em>, for instance. Some are useless for reference but superb for wandering around in — the Knuth <em>Art of Computer Programming</em> volumes, Lopes’s <em>Exercises in Programming Style</em>.</p>
<h2>March: “Ordinary” books</h2>
<p>Dealing with ordinary, non-scholarly but also non-programming books has been more difficult. I have had to learn to throw books actually and finally away. Several dozen I abandoned initially on a nearby street corner — most were taken in by kind strangers on short order. Others were destroyed there by rain or feet.</p>
<p>Some of the books that I am no longer willing to keep I have owned since high school — forty years or so. A few of those I gave away to a friend, a bad idea, as it is easier to do than throwing them away on the street and requires less reflection. I mean that books seem more likely to be read if I hand them off to someone. Another issue is that ease of disposal obscures the essential poison of a book — its physical form suggests that it contains concentrated wisdom, but it may actually hold nothing but hokum.</p>
<p>Books that have come down to me from my father and grandfather but that I will certainly never read, books that I bought as a teenager and that shaped me early, books that I have read dozens of times, books that I have never read but imagine contain something good — many of those are now out of my possession. Others rest in a special place of limbo, awaiting judgment.</p>
<p>One book in limbo is Benét’s <em>Reader’s Encyclopedia</em>, which I have owned from my teens. It was, in its day, an essential once-volume reference book — filled with odd details about culture and literature. I don’t think anyone would use such a book today except in the paper form that allows a particular kind of manual random access, “browsing”: leisurely grazing and at moments rooting for truffles. Right now it is hard to imagine either keeping or discarding this book. I have interred it among the limbo books, to be resurrected and called to judgment later. Perhaps I’m doing in my library what the construction workers did with the garbage under our floorboards.</p>
<p>I also own the <em>Standard Dictionary of Facts</em>, which my grandfather used to peddle door-to-door when he had been in the United States just three years or so. It came with a <em>Standard Question Book and Home Study Outlines</em>, which offered trivia questions, answered by page-numbers of the <em>Standard Dictionary</em> where you could find the information. The earliest copyright notice is 1908; my grandfather wrote his name on a flyleaf in November, 1924. The preface to the <em>Standard Question Book</em> begins:</p>
<blockquote>
<p>The days of the cave man have passed. Physical strength no longer gives prowess to the individual. What the twentieth century demands is the trained intellect. The man who <em>knows</em> is the man of the hour.</p>
</blockquote>
<p>My grandfather loved trivial detail, as do I. How could I remember him in full — the old man I knew, grown from out of the young man who owned and peddled this book — except in part through his copy of the book itself? All his life he believed that these words “twentieth century” meant humanity was finally going to do new and different things — that idea was deeply imprinted on him. But he died in 1992, before the World Wide Web or smartphones — before the modern world came into being. I wonder if he would have remained as optimistic about the twenty-first century as he was about the twentieth. I do not think I am as optimistic now as he was at my age. At the age I am now, he founded a business, which he ran for twenty years. I've been wondering for most of a year if I will do the same thing soon.</p>
<h2>March: Scholarly books</h2>
<p>Dealing with my scholarly library has been most difficult of all. I began facing that struggle in mid-March. I doubt I will act until I find either a buyer or some kind of reasonable home for these books. Individually, many of them are of little interest except to a specialist. Collectively, they represent a considerable well of negative entropy, and I would like to preserve the order in that arrangement somehow.</p>
<p>Most of the dialectology books must go to someone who will use them. Some are pretty rare. I stopped doing comparative-historical fieldwork in 2006. I have all the materials I need to work on some unfinished dialectology projects deriving from that labor, and I’m still active in Taiwanese (and in fact very interested in it), but if I keep just a small subset of Taiwanese materials, they will suffice.</p>
<p>I am preparing to get rid of many copies of classical texts, all but those few that interest me particularly. Modern Taiwan and China produce serviceable reading editions — somewhat comparable to the Loeb Classics — with corrected texts, scholia (which the Loebs lack), a Mandarin translation, and exegetical commentary. These version are looked steeply down upon by most Western scholars — but at the same time most Western scholars I know have a large collection of them, sometimes hidden where students and colleagues can’t see them. I, however, have no one to impress with the false purity of my library. Keeping mostly just the Chinese “Loebs” leaves me with a lean but nutritious reference library of classical and medieval texts.</p>
<p>Epigraphy (the study of the ancient script and inscriptions) and historical phonology are troublesome, since I now think I’m unlikely to do major research or teaching in these areas, but they are connected with etymology as practiced in Chinese, which remains a major interest. Worse, many of these books are dictionaries — and whether or not to discard dictionaries is the most vexed of questions, since lexicographic history has been one of my research interests, and sometimes you can’t decide anything unless you have access to a particular edition. Rimebooks (<em>yùnshū</em> 韻書), it appears, I am keeping for the most part. My teacher left me some that had come down to him from his own teacher; I can’t see parting with any of those — they combine sentimental and research interest.</p>
<h2>April: Discarding tools, keeping tools</h2>
<p>It is harder for me to throw away a dictionary than any other kind of book.</p>
<p>Two of the large reference works important to my sinological work are the <em>Hànyǔ dà cídiǎn</em> 漢語大詞典 and <em>le Grand Ricci</em> 利氏漢法辭典, both multiple volumes. I have both both of them on my phone now, occupying as close to no space as possible. What does that mean about whether or not I should keep the paper copies, which occupy two cubic feet and weigh more than I can lift without bursting a gut? And what does it mean that those two sets happen to be in the background when I am conducting technical interviews over Skype? The presence of these books in my life has been advertised to hundreds of prospective <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Recurse Center</a> people that way.</p>
<p>Most academic libraries I have visited simply discard old dictionaries as though they were out-of-date cellphones. No dictionary app or on-line dictionary tool I’ve used very much includes all the prefaces and other meta-content of the original. Exceptionally, the on-line <em>Oxford English Dictionary</em> includes the 7000-word preface to the third edition (2000) and a more recent 1200-word update (2007), but it isn’t obvious how to find them. And all earlier prefatory matter is gone. The <em>New Oxford American Dictionary</em> is the source of the “Dictionary” app that comes built-in on the modern Apple operating system, but there is no trace of the front matter of the original work.</p>
<p>And will I always have access to the apps and websites that serve the dictionary data itself? It’s hard to be really sure of that.</p>
<p>I think my nascent strategy is to keep a modest core library in paper form. If I have to flee New York, at best I’ll probably have only my phone with me. But I can stay, or can leave at a measured pace, some paper will stay with me.</p>
<p>For a long time I have been struggling with the conflict between paper and electronic forms. A diary note from some years back remarks that when I read a physical book, sometimes I find myself glancing at the corner of a printed page to see the time, as though it were a screen. Competing instincts are in collision as my grandfather’s century meets mine.</p>
<p>In the process of examining each book, I removed hundreds of old bookmarks, nearly all left in place from past research projects, though not all the passages I had marked ended up being used. Remembering the research question that led to each being placed is like looking through old photographs. I don’t see how to do that with PDFs or documents in app form.</p>
<p>It is now late April, three months since the radiator’s apoplexy. Undertaking the project to discard books, I am finding many interesting ones I haven’t read in years — in some cases, volumes I bought to read but never did, and the intention itself was buried along with the book. For the first time in years I am reading quite a bit every day.</p>
<p>So something is happening to me, some element of convalescence from my unhappy corporate experiences of late. Since the burst radiator pipe (to those who choose to divine from it) intimates a state of being that calls for repair of hidden damage, for me to cut back my weighty library seems to be metaphorically in order and even urgent — like losing weight after a mild stroke.</p>
<p>Even so, I am still not spending time every day doing much of the personal coding and scholarship I have decided is most important for me to do now. That means I haven’t yet learned the most important lesson offered to me by my sojourn into and out of Corporatia.</p>
<h2>Soon it will be May: Wolves</h2>
<p>These days I have been listening to keyboard music of Sweelinck, a little-heard master composer of a century before Bach. <a href="https://www.youtube.com/watch?v=MKn3XGK4eHo">This fine video</a>, Irene De Ruvo playing the “Fantasia Chromatica”, features a major composition rich in non-diatonic melody, performed in the wrenching meantone temperament. Meantone is not intended for chromaticism, and “wolves” appear — harmonic intervals whose overtones seem to howl because they deviate from expected consonances. It is for the ear as looking through imperfect lenses is for the eye, and it very much suits my mood.</p>
<p>(I find that “wolf” is the name in all the European languages I’ve examined, including Magyar, for this phenomenon.)</p>
<p>[end]</p>About Me2016-04-25T22:43:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-04-25:about.html<p>Basically, I am a teacher and scholar. These days I work as a kind of consulting engineer — conducting technical interviews of programmers and trying to examine their personalities as coders through conversation, pair-programming, and the examination of their past coding work. My path to date must seem roundabout, but the dominant issues have been language, sound, and the ideas entailed in challenging hypotheses rigorously with evidence. </p>
<p><strong>First career</strong>: My first career was in Chinese philology — the study of the nature and history of Chinese language. I ran a university Chinese language and literature program and was active in a number of scholarly societies; the subjects I taught included Mandarin at all levels, translation, and Classical Chinese, as well as literature and civilization courses in English and technical courses in Chinese linguistics. I held the full range of administrative responsibilities typical of the head of a university department: hiring and firing, curriculum development, student advising, career-mentoring for junior faculty, and of course all the “service” (meetings and paperwork) usual in a Research–1 state university. I have also dealt extensively with local Chinese officials, both during my research and in my role as a professor. Teaching and learning are related activities in my experience, and even though I’m no longer in the Chinese classroom, teaching programming is basic to my continued learning of programming.</p>
<p><strong>Second career</strong>: A few years after achieving tenure, I left academia for a good opportunity in New York’s computer industry, where I have remained active since then. Initially I ran a department involving Chinese language at a machine translation company, but eventually I decided to get a Computer Science education so that I could work in more purely technical roles. I completed the minor coursework in the subject (though without a full second baccalaureate degree) at the City College of New York in 2012, taking courses part-time while teaching Classical Chinese part-time at Columbia University, editing, and tutoring Chinese executives in English pronunciation. After that, I attended two “batches” at the <a href="http://recurse.com"><a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Recurse Center</a></a> in New York (2013–14).</p>
<p>I have continued to do research on Chinese (most recently holding the position of Member at the <a href="http://ias.edu">Institute for Advanced Study</a>), but it is likely that Chinese philology will be in the nature of a hobby for me in future — I now work in industry proper, in a technical role. Much of my linguistic research has revolved around the idea of “fingerprinting” — deciding the identity or position of something based on its most essential characteristics. I’ve done that with the historical taxonomy of a variety of regional languages (chiefly Mǐn 閩 and Hakka 客家 varieties), identifying non-standard Mandarin accents, pinning down the part of speech of words in written Chinese (Chinese parts of speech are notoriously fluid), and other subjects. In 2014-15 I worked in an industry where an everyday task is “fingerprinting” entities encountered on the Internet.</p>
<p>For several months I taught at a high-pressure coding “bootcamp”, where the teaching philosophy was that “people learn best at the edge of panic.” I don’t believe that’s normally true, and I’d like to find a venue where I can teach programming on a different basis.</p>
<p><strong>Where I stand on various things</strong>: <strong>Collaboration</strong>. Most of my scholarly work has been single-author, as is usual in the Humanities. I did not learn to collaborate until after leaving academia, and it has been a salutary change for me. My 2011 book was edited jointly with another scholar; my lexicographic work has almost all been done jointly with a native speaker of Chinese, and most of my prosodic study since 2012 has been done jointly with a mathematician. In industry, of course, collaboration and collective authorship are normal parts of life.</p>
<p><strong>Interests</strong>. It’s hard to list all the things I have been interested in, but here is a short list, limiting myself to those I’ve studied in the classroom: In high school I studied computer programming and Latin. In college I threw those things entirely aside and gave myself over to Chinese and articulatory phonetics. After false starts in plant evolutionary biology and Chinese medicine I went to graduate school in Chinese. As mentioned above, more recently I have studied undergraduate computer science (2010–12). Among things I have not studied in the classroom, music, words, and interesting things to eat are high on my list of interests. Linguistic fieldwork and more broadly the first-hand documentation of detail discovered through exploration have a very strong hold on me.</p>
<p>I keep a <a href="https://brannerchinese.com/resumes/vita.pdf">full academic vita online</a>; it explains the meaning of what I think of as the main topics I have worked on.</p>
<p><strong>Teachers</strong>: My principal college teacher was the phonetician <a href="http://en.wikipedia.org/wiki/Robert_Austerlitz">Robert Austerlitz</a> (1923–1994); my graduate advisor was <a href="http://en.wikipedia.org/wiki/Jerry_Norman">Jerry Norman</a> (1936–2012). Although Norman was a student of <a href="http://en.wikipedia.org/wiki/Yuen_Ren_Chao">Yuen Ren Chao</a>* , I think both he and Austerlitz owe more to the tradition of <a href="http://en.wikipedia.org/wiki/Li_fang_kuei">Li Fang Kuei</a> and his Americanist teachers than to Chao.</p>
<hr />
<p><strong>To reach me</strong>: I use a handle of <code>dpb</code> at the <code>com</code> domain <code>brannerchinese</code> and my ancient log-in at columbia.edu is my three initials followed by the ninth prime number. </p>
<hr />
<p>* I am proud of having gotten Chao duly registered at the <a href="http://genealogy.math.ndsu.nodak.edu/id.php?id=159329">Mathematics Genealogy project</a>. </p>
<p>[end]</p>Walter Murch on Standing at Work2016-04-25T22:40:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2016-04-25:walter_murch_on_standing_at_work.html<blockquote>
<p>[Film] editing is a kind of surgery — and have you ever seen a surgeon sitting to perform an operation? Editing is also like cooking — and no one sits down at the stove to cook. But most of all, editing is a kind of dance — the finished film is a kind of crystallized dance — and when have you ever seen a dancer sitting down to dance?</p>
</blockquote>
<p>(Walter Murch, <em>In the Blink of an Eye</em>, 2nd ed., [Los Angeles: Silman-James Press, 2001], pp. 44-45.)</p>
<p>[end]</p>“Our Kind of Story”2015-11-28T16:15:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2015-11-28:our_kind_of_story.html<p>The things I have enjoyed studying are mostly those that have required me to contend with myself for a long time before making what I felt to be progress. Here is a paragraph from Primo Levi that tells me he has the same experience.</p>
<p>He attends a school reunion, reflecting on the fact that many of his classmates are no longer chemists and no longer have chemical tales to recount. But the organizer of the reunion still has some tales, and Levi invites the organizer to contribute a story to his book:</p>
<blockquote>
<p>I asked him if he would like to contribute to this book. If he would, he should tell me a story and, if he would allow me to make a suggestion, it should be our kind of story, in which you thrash about in the dark for a week or a month, it seems that it will be dark forever, and you feel like throwing it all up and changing your trade; then in the dark you espy a glimmer, proceed groping in that direction, and the light grows, and finally order follows chaos.</p>
</blockquote>
<p>(Primo Levi, <em>The Periodic Table</em>, tr. Raymond Rosenthal; “Silver”.)</p>
<p>[end]</p>Revisiting the Taiwan national anthem2015-11-28T15:57:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2015-11-28:revisiting-the-taiwan-national-anthem.html<p>Arriving in Taiwan in the last few years of the martial-law era (1949–87), I encountered a kind of formal nationalism that I had never known growing up. There were pictures of the President (Chiang Ching-kuo [Jiǎng Jīngguó] 蔣經國) in all school classrooms and you could buy them in many stores. There were also pictures of his late father (Chiang Kai-shek 蔣中正) and of Sun Yatsen in many of the same places. The flag was called the “national flag” (<em>guóqí</em> 國旗); the standard language was called the “national language” (<em>guóyǔ</em> 國語); and there were other “national” arts and practices, also so labelled. This sort of labelling was not unique to Taiwan — it was seen all over East Asia in the late nineteenth century. Under Manchu rule of China, my teacher used to say, <em>guóyǔ</em> actually meant Manchu rather than Chinese.</p>
<p>Most of those things had no great effect on me. But I was deeply moved by the national anthem of the time, both words and music. It is rather in disfavor now for a variety of reasons. For one, thing, it was originally the anthem of a political party. For another, it is associated with the Nationalist government of China, which both Taiwan progressives and China-leaning people today find objectionable. Many people in Taiwan seem to find the old national anthem a little embarrassing.</p>
<p>Taking it on its own merits, though, and ignoring its associations, I find it more appealing than many other national anthems I’ve examined. The melody is majestic, and it doesn’t run for long. The text is not militaristic, nor does it celebrate a ruler or even the nation itself. It exhorts the listener to improve society:</p>
<div class="highlight"><pre>三民主義 The Three Principles of the People
吾黨所宗 are the founding ideals of our party.
以建民國 May a democratic republic be founded upon them,
以進大同 and through them may social harmony be advanced.
咨爾多士 O you many men and women of ability,
為民前鋒 act as vanguard to our people,
夙夜匪懈 work without rest, day and night,
主義是從 taking these Principles as your guides.
矢勤矢勇 Swear diligence; swear bravery —
必信必忠 never abandon your trust, and never your loyalty.
一心一德 Let us be united in heart and in our sense of goodness
貫徹始終 and carry out our mission from beginning to end.
</pre></div>
<p>As these things go, I doubt I can imagine much I would take less exception to from a national anthem. The reference to <em>wúdǎng</em> 吾黨 ‘our party’ certainly meant the Nationalists when the words were written. But it also means “fellows”, “comrades”, “confederates” — and I think the force of that meaning is entirely praiseworthy.</p>
<hr />
<p>For some time now there has been a version in which the harmony has been revised, and the result seems to me to have rather lost the majesty of what I heard in the 1980s. Nearly all YouTube recordings I’ve examined this morning are of that setting.</p>
<p><a href="https://www.youtube.com/watch?v=fHsZRfOurQ8">Here is a performance</a> of the harmonization I remember from the 1980s by Chang Hui-mei [Zhāng Huìmèi] 張惠妹 (<a href="https://www.youtube.com/watch?v=QcjknLBA14E">another copy here</a>). She came into some political disfavor because of this performance — the venue was the 2000 inauguration of President Chen Shui-bian [Chén Shuǐbiǎn] 陳水扁, a hero of the struggle against authoritarianism in the 1970s and deeply unpopular with some of Taiwan’s citizens.</p>
<p><a href="https://www.youtube.com/watch?v=dCvlZoByRVc">Here’s a much older recording</a> with still fewer modulations.</p>
<p>[end]</p>Review of Button, Phonetic Ambiguity in the Chinese Script2015-07-26T20:47:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2015-07-26:review-of-button-phonetic-ambiguity.html<p>I have posted a long-delayed review, of <a href="http://brannerchinese.com/publications/Branner_review_Button_2014.pdf">Christopher Button’s <em>Phonetic Ambiguity in the Chinese Script</em></a>.</p>
<p>Button evaluates the hypothesis of “polyphony” — coexistence of more than one etymologically productive reading per graph, and particularly the “crypto-phonogram” aspect of the hypothesis: that early in history it was forgotten that many graphs had phonetically unrelated readings.</p>
<p>Although this idea has had many detractors, Button’s may be the first rigorous effort to undermine the theory. </p>
<blockquote>
<p>On balance, I think the arguments fair. What Button is offering is not a rebuttal to the whole polyphonic hypothesis but a substantial counter-interpretation of the evidence, case by case.</p>
</blockquote>
<p>I don’t consider the theory fully undermined, though — and urge a response from the Crypto-Phonogrammatic camp.</p>
<p>[end]</p>Importing Modules under Pytest2015-07-25T19:48:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2015-07-25:importing-modules-under-pytest.html<p>I have been converting some tests written earlier for Unittest and am having trouble with import statements when running them with Pytest.</p>
<p>As an example, in the older code the module <code>create.py</code> in directory <code>lib</code> might be imported as</p>
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">lib.create</span>
</pre></div>
<p>but this syntax usually raises errors when I run the code with Pytest.</p>
<p>The solution is include a <code>setup.py</code> file at the top-level directory of the project, and then to use <code>pip</code> to install it in "editable mode":</p>
<div class="highlight"><pre>pip install -e .
</pre></div>
<p>That will generate a directory whose name ends in <code>.egg-info</code> and which contains a number of configuration files. After that, running with Pytest takes place without difficulties.</p>
<p>I have posted a minimal working example <a href="https://github.com/DataBranner/pytest_import_question">here</a>.</p>
<p>[end]</p>Two Git Accounts on One Computer2015-07-25T19:00:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2015-07-25:two-git-accounts-on-one-computer.html<p>Imagine you have two or more different hosted Git accounts, and each is associated with a different SSH key:</p>
<div class="highlight"><pre><span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa_first</span>
<span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa_second</span>
</pre></div>
<p>How do you make sure the correct key is used with a given account?</p>
<p>I realize now, nine months after initially posting this, that what I've described is needlessly complex. </p>
<p>I've left the original post further down on the page, but in practice when I want to push to or pull from one of my several hosted Git accounts, here is what I do:</p>
<ol>
<li>
<p><strong>First remove <em>all</em> SSH identities</strong> from the authentication agent, and then add only the one that is correct for the repository I am working with.</p>
<div class="highlight"><pre><span class="n">ssh</span><span class="o">-</span><span class="n">add</span> <span class="o">-</span><span class="n">D</span>
<span class="n">ssh</span><span class="o">-</span><span class="n">add</span> <span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa_second</span>
</pre></div>
<p>(In theory it is supposed to be possible to set one's <code>.ssh/config</code> file to use different identities with different accounts, but in practice I find that doesn't always work as expected.)</p>
</li>
<li>
<p><strong>Set up a script to rewrite the repository’s commit history</strong>. This may be useful if the repository has been added to at different times when you were using more than one distinct SSH identity. Configure <a href="https://help.github.com/articles/changing-author-info/"><code>git-author-rewrite.sh</code></a> with <code>first</code> and <code>second</code> as below:</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></div></td><td class="code"><div class="highlight"><pre><span class="c">#!/bin/sh</span>
git filter-branch --env-filter <span class="s1">'</span>
<span class="s1">OLD_EMAIL="first@email.com"</span>
<span class="s1">CORRECT_NAME="Second Name"</span>
<span class="s1">CORRECT_EMAIL="second@email.com"</span>
<span class="s1">if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]</span>
<span class="s1">then</span>
<span class="s1">export GIT_COMMITTER_NAME="$CORRECT_NAME"</span>
<span class="s1">export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"</span>
<span class="s1">fi</span>
<span class="s1">if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]</span>
<span class="s1">then</span>
<span class="s1">export GIT_AUTHOR_NAME="$CORRECT_NAME"</span>
<span class="s1">export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"</span>
<span class="s1">fi</span>
<span class="s1">'</span> --tag-name-filter cat -- --branches --tags
</pre></div>
</td></tr></table>
</li>
<li>
<p>A reader kindly commented to mention setting Git's <code>credential.useHttpPath</code> configuration in a given repository in order to let the Mac OS X KeyChain handle the choice of which identity will be used for authentication. But unhappily that seems to work only for HTTP access, not SSH.</p>
</li>
</ol>
<hr />
<p>Long-winded original post follows:</p>
<p>Date: 2014-10-13 11:00</p>
<p>I have long wanted to have a Git account where I can keep only finished, presentable code, and have it be completely separate from my messy working account. One way to do this is to use a different hosting service for the two accounts, but it can also be done with both accounts on GitHub itself. </p>
<p>It took me a while to learn all the necessary steps, which I describe below. I am assuming the user-name of your original account is <code>first</code> and the new one <code>second</code>. And I am assuming you are using SSH.</p>
<p>Below there are “one-time” (initialization) steps, and then a separate set of steps that have to be done for each repository you want to move to user <code>second</code>.</p>
<hr />
<h2>One-time set-up steps</h2>
<ol>
<li>
<p>(optionally) <strong>Use a Git user-switch</strong>. Set up <a href="https://github.com/joealba/gitswitch"><code>gitswitch</code></a> (published as a Ruby gem):</p>
<div class="highlight"><pre><span class="n">gem</span> <span class="n">install</span> <span class="n">gitswitch</span>
<span class="n">gitswitch</span> <span class="n">init</span>
</pre></div>
<p>This program allows you to maintain two or more git user identities on a single computer, and to switch conveniently among them. One will be <code>first</code>, your default identity, the one you have presumably been using all along. Gitswitch will enable you to mark a given repository as belonging to <code>second</code>.</p>
</li>
<li>
<p><strong>Create a new Git hosting account</strong>, associated with a new email address, <code>second@email.com</code>, that you control. Bear in mind that if you are keeping both accounts on the same host (e.g., GitHub) and intend to maintain access to both accounts simultaneously, you will need to log into them from different browsers.</p>
</li>
<li>
<p><strong>Create a new SSH key</strong>. Here I am assuming you have already been using SSH with Git and already have an SSH key for your default user, <code>first</code>. Now create a new SSH key for user <code>second</code>. </p>
<div class="highlight"><pre><span class="n">ssh</span><span class="o">-</span><span class="n">keygen</span> <span class="o">-</span><span class="n">t</span> <span class="n">rsa</span> <span class="o">-</span><span class="n">C</span> <span class="s">"second@email.com"</span>
</pre></div>
<p>You will be asked what the name of the new private key ID file should be; use <code>id_rsa_second</code>; private key ID file is presumably <code>id_rsa</code>, though you may like to name it something else. After the program completes make sure it has been created at <code>~/.ssh/id_rsa_second</code>.</p>
<p>Add both private key identities to the SSH authentication agent:</p>
<div class="highlight"><pre><span class="n">ssh</span><span class="o">-</span><span class="n">add</span> <span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa</span>
<span class="n">ssh</span><span class="o">-</span><span class="n">add</span> <span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa_second</span>
</pre></div>
<p>If later on you have trouble using SSH, it may be necessary to delete the agent’s record of these IDs, using </p>
<div class="highlight"><pre><span class="n">ssh</span><span class="o">-</span><span class="n">add</span> <span class="o">-</span><span class="n">D</span>
</pre></div>
<p>After that use <code>ssh-add</code> again as above.</p>
</li>
<li>
<p><strong>Add your new public key to the Git hosting service</strong>. Go to the SSH-key area of your Git hosting service (on GitHub that would be https://github.com/settings/ssh and click “Add SSH key”). Copy the contents of <code>~/.ssh/id_rsa_second.pub</code> (note the extension <code>.pub</code>) into the key-field and save it to the server with some appropriate name. </p>
</li>
<li>
<p><strong>Set up <code>.ssh/config</code> for multiple users</strong>. Create or open file <code>~/.ssh/config</code> and enter the following in it:</p>
<div class="highlight"><pre><span class="n">Host</span> <span class="n">first</span>
<span class="n">HostName</span> <span class="n">github</span><span class="p">.</span><span class="n">com</span>
<span class="n">User</span> <span class="n">git</span>
<span class="n">IdentityFile</span> <span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa</span>
<span class="n">Host</span> <span class="n">second</span>
<span class="n">HostName</span> <span class="n">github</span><span class="p">.</span><span class="n">com</span>
<span class="n">User</span> <span class="n">git</span>
<span class="n">IdentityFile</span> <span class="o">~/</span><span class="p">.</span><span class="n">ssh</span><span class="o">/</span><span class="n">id_rsa_second</span>
</pre></div>
<p>Of course, if you are not using the same host for both accounts, then alter the <code>HostName</code> entries accordingly. Now check that SSH recognizes multiple users:</p>
<div class="highlight"><pre><span class="n">ssh</span> <span class="o">-</span><span class="n">T</span> <span class="n">first</span>
<span class="n">ssh</span> <span class="o">-</span><span class="n">T</span> <span class="n">second</span>
</pre></div>
<p>You should see evidence of successful log-in after each of these commands.</p>
</li>
<li>
<p><strong>Set up a script to rewrite the repository’s commit history</strong>. Configure <a href="https://help.github.com/articles/changing-author-info/"><code>git-author-rewrite.sh</code></a> with <code>first</code> and <code>second</code> as below:</p>
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></div></td><td class="code"><div class="highlight"><pre><span class="c">#!/bin/sh</span>
git filter-branch --env-filter <span class="s1">'</span>
<span class="s1">OLD_EMAIL="first@email.com"</span>
<span class="s1">CORRECT_NAME="Second Name"</span>
<span class="s1">CORRECT_EMAIL="second@email.com"</span>
<span class="s1">if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]</span>
<span class="s1">then</span>
<span class="s1">export GIT_COMMITTER_NAME="$CORRECT_NAME"</span>
<span class="s1">export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"</span>
<span class="s1">fi</span>
<span class="s1">if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]</span>
<span class="s1">then</span>
<span class="s1">export GIT_AUTHOR_NAME="$CORRECT_NAME"</span>
<span class="s1">export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"</span>
<span class="s1">fi</span>
<span class="s1">'</span> --tag-name-filter cat -- --branches --tags
</pre></div>
</td></tr></table>
</li>
<li>
<p>Now push to remote. </p>
</li>
</ol>
<hr />
<h2>Steps to be repeated for each repository</h2>
<ol>
<li>
<p><strong>Enter the directory containing the repository</strong> on your local machine. (If you plan to maintain two versions of the same repository, then make a copy of the repository and enter its top-level directory.)</p>
</li>
<li>
<p><strong>Switch user from <code>first</code> to <code>second</code></strong>. If you are using <code>gitswitch</code> enter:</p>
<div class="highlight"><pre><span class="n">gitswitch</span> <span class="k">switch</span> <span class="n">second</span>
</pre></div>
<p>If you are not using <code>gitswitch</code>, then edit the <code>[user]</code> section of <code>.git/config</code> so that it reads</p>
<div class="highlight"><pre><span class="k">[user]</span>
<span class="na">email</span> <span class="o">=</span> <span class="s">second@email.com</span>
<span class="s"> name = Second Name</span>
</pre></div>
</li>
<li>
<p><strong>Revise your Git configuration file</strong>. Rewrite the <code>url</code> line in the <code>[remote "origin"]</code> section of <code>.git/config</code>, using <code>second</code> and <code>Repository_Name</code>:</p>
<div class="highlight"><pre><span class="n">url</span> <span class="o">=</span> <span class="n">git</span><span class="err">@</span><span class="n">second</span><span class="o">:</span><span class="n">second</span><span class="o">/</span><span class="n">Repository_Name</span><span class="p">.</span><span class="n">git</span>
</pre></div>
<p>Note that <code>second</code> appears <strong>twice</strong> here: normally this line would read</p>
<div class="highlight"><pre><span class="n">url</span> <span class="o">=</span> <span class="n">git</span><span class="err">@</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">:</span><span class="n">second</span><span class="o">/</span><span class="n">Repository_Name</span><span class="p">.</span><span class="n">git</span>
</pre></div>
<p>but if "<code>github.com:</code>" appeared after the @-sign, default identity <code>first</code> would be used for pushing to the origin, and in that case you would get an error trying to write to <code>second</code>'s repository.</p>
</li>
<li>
<p><strong>Rewrite your commit history</strong>. Run <code>git-author-rewrite.sh</code></p>
<div class="highlight"><pre><span class="n">sh</span> <span class="n">git</span><span class="o">-</span><span class="n">author</span><span class="o">-</span><span class="n">rewrite</span><span class="p">.</span><span class="n">sh</span>
</pre></div>
<p>Note that if you have to run this script more than once in a given repository for some reason, you must add <code>-f</code> after <code>git filter-branch</code> in the script under "<strong>Set up a script to rewrite…</strong>", above, in order to force the overwriting of a backup file. </p>
</li>
<li>
<p>(optionally) <strong>Revise your Git log</strong>. In order to ensure that all user-references in the log are also to the new account, edit the Git log with <code>filter-branch</code>:</p>
<div class="highlight"><pre><span class="n">git</span> <span class="n">filter</span><span class="o">-</span><span class="n">branch</span> <span class="o">-</span><span class="n">f</span> <span class="o">--</span><span class="n">msg</span><span class="o">-</span><span class="n">filter</span> <span class="s">"sed 's/first/second/'"</span> <span class="o">--</span><span class="n">tag</span><span class="o">-</span><span class="n">name</span><span class="o">-</span><span class="n">filter</span> <span class="n">cat</span> <span class="o">--</span> <span class="o">--</span><span class="n">branches</span> <span class="o">--</span><span class="n">tags</span>
</pre></div>
</li>
</ol>
<p>You may like to check to see that <code>first</code> is completely removed from your git log — any remaining occurrences would be listed with:</p>
<div class="highlight"><pre> <span class="n">grep</span> <span class="o">-</span><span class="n">FR</span> <span class="n">second</span><span class="err">@</span><span class="n">email</span><span class="p">.</span><span class="n">com</span> <span class="p">.</span><span class="n">git</span><span class="o">/*</span>
</pre></div>
<p>and can be edited manually.</p>
<ol>
<li>
<p><strong>Push the repository to <code>second</code>'s hosted account</strong>. Make sure git will behave as you expect using the <code>--dry-run</code> option first:</p>
<div class="highlight"><pre><span class="n">git</span> <span class="n">push</span> <span class="o">--</span><span class="n">force</span> <span class="o">--</span><span class="n">tags</span> <span class="n">origin</span> <span class="err">'</span><span class="n">refs</span><span class="o">/</span><span class="n">heads</span><span class="o">/*</span><span class="err">'</span> <span class="o">--</span><span class="n">dry</span><span class="o">-</span><span class="n">run</span>
</pre></div>
<p>You should see no error messages, and the output will be as if you had really pushed. Then push to repository, using the same command but without <code>--dry-run</code>.</p>
</li>
</ol>
<p>[end]</p>Pytest parametrization — passing multiple data-items to a single test2015-03-11T09:56:00-04:00David Prager Brannertag:https://dpb.bitbucket.io,2015-03-11:pytest-parametrization.html<p><strong>The problem</strong>: I have a single test function that I want to run many times on different data. I don't want to just get a single pass/fail result — I want to see whether each item of data makes the test pass or fail individually. But I also don't want to write a whole bunch of nearly identical tests, with only the data changing each time.</p>
<p><strong>The solution: "parametrization" in the Pytest tool</strong>. Parametrization means defining parameters that will populate your function-arguments.</p>
<p>Define an iterable (here called <code>the_iterable</code>) containing the multiple items each of which you want passed to your test functions. Both it and a string containing an argument name (here called <code>argument_name</code>) are passed to a decorator called on any test function (here called <code>test_name</code>).</p>
<div class="highlight"><pre><span class="c"># test_file.py</span>
<span class="kn">import</span> <span class="nn">pytest</span>
<span class="n">the_iterable</span> <span class="o">=</span> <span class="p">[</span><span class="s">'sequence'</span><span class="p">,</span> <span class="s">'of'</span><span class="p">,</span> <span class="s">'items'</span><span class="p">,</span> <span class="s">'etc.'</span><span class="p">]</span> <span class="c"># Etc.</span>
<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">'argument_name'</span><span class="p">,</span> <span class="n">the_iterable</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_name</span><span class="p">(</span><span class="n">argument_name</span><span class="p">):</span>
<span class="c"># Code here makes use of each item of `the_iterable` in turn, passed</span>
<span class="c"># in as `argument_name`.</span>
<span class="k">pass</span>
</pre></div>
<p>The names <code>the_iterable</code>, <code>argument_name</code>, and <code>test_name</code> are dummies that you can change to whatever you want, although the name of the function has to start with <code>test_</code> in order for Pytest to discover it. </p>
<p>You don't need to iterate manually through <code>the_iterable</code> or summon specific indices of it, as <code>the_iterable[0]</code>, etc. Pytest will handle that. Pytest will iterate through <code>the_iterable</code> and assign each of its elements, in turn, to the target variable <code>argument_name</code>. It will call your test function <code>test_name</code> on that argument over and over again, with the argument representing each of the elements of <code>the_iterable</code> in turn, and report the results to you one by one.</p>
<p>Run from the command line as</p>
<div class="highlight"><pre>py.test test_file.py
</pre></div>
<p>Note:</p>
<ol>
<li><code>test_file.py</code> can contain as many test-functions as you like, and each can be decorated with <code>pytest.mark.parametrize</code> if needed.</li>
<li>Pytest normally runs all tests in sequence even if some fail. If you want Pytest to stop on the first failing test, use option <code>-x</code>.</li>
<li>To see which arguments are passed into each test, use option <code>-v</code>. Unless the arguments are strings, numbers, or booleans, they will probably appear as automatically generated id-names — to include an identifying string for each data item, do so using the keyword-argument <code>ids</code>:</li>
</ol>
<div class="highlight"><pre><span class="nd">@pytest.mark.parametrize</span><span class="p">(</span>
<span class="s">'argument_name'</span><span class="p">,</span>
<span class="n">the_iterable</span><span class="p">,</span>
<span class="n">ids</span><span class="o">=</span><span class="p">[</span><span class="s">'list'</span><span class="p">,</span> <span class="s">'of'</span><span class="p">,</span> <span class="s">'id-names'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">test_name</span><span class="p">(</span><span class="n">argument_name</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
<p><code>argument_name</code> can also contain multiple arguments, comma-separated, if your test function takes multiple arguments (and if <code>the_iterable</code> contains tuples). For instance</p>
<div class="highlight"><pre><span class="n">the_iterable</span> <span class="o">=</span> <span class="p">[(</span><span class="s">'sequence'</span><span class="p">,</span> <span class="mi">56</span><span class="p">),</span> <span class="p">(</span><span class="s">'of'</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="s">'items'</span><span class="p">,</span> <span class="mi">0</span><span class="p">)]</span> <span class="c"># Etc.</span>
<span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s">'arg1, arg2'</span><span class="p">,</span> <span class="n">the_iterable</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_name</span><span class="p">(</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">):</span>
<span class="c"># Code here makes use of each tuple `(arg1, arg2)` in turn.</span>
<span class="k">pass</span>
</pre></div>
<p>I have used this pattern to pass in 2-tuples containing an external function to be called and a boolean describing whether the external function is expected to return <code>True</code> or <code>False</code>. (A more official way of marking specific test cases as "expected to fail" is with the <code>pytest.mark.xfail()</code> function, within <code>the_iterable</code>.)</p>
<p>If you want to see the actual data passed into each iteration of the test function, use the <code>pytest.fixture</code> decorator, with the <code>params</code> keyword:</p>
<div class="highlight"><pre><span class="nd">@pytest.fixture</span><span class="p">(</span><span class="n">params</span><span class="o">=</span><span class="p">[</span><span class="s">'sequence'</span><span class="p">,</span> <span class="s">'of'</span><span class="p">,</span> <span class="s">'items'</span><span class="p">,</span> <span class="s">'etc.'</span><span class="p">])</span> <span class="c"># Etc.</span>
<span class="k">def</span> <span class="nf">test_name</span><span class="p">(</span><span class="n">argument_name</span><span class="p">):</span>
<span class="c"># Code here makes use of each item of `params` in turn, passed</span>
<span class="c"># in as `argument_name`.</span>
<span class="k">pass</span>
</pre></div>
<hr />
<p>Note that the first decorator example above is shorthand for the following:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">pytest_generate_tests</span><span class="p">(</span><span class="n">metafunc</span><span class="p">):</span>
<span class="k">if</span> <span class="s">'argument_name'</span> <span class="ow">in</span> <span class="n">metafunc</span><span class="o">.</span><span class="n">fixturenames</span><span class="p">:</span>
<span class="n">metafunc</span><span class="o">.</span><span class="n">parametrize</span><span class="p">(</span><span class="s">"argument_name"</span><span class="p">,</span> <span class="n">the_iterable</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_name</span><span class="p">(</span><span class="n">argument_name</span><span class="p">):</span>
<span class="c"># Code here makes use of each item of `the_iterable` in turn, passed</span>
<span class="c"># in as `argument_name`.</span>
<span class="k">pass</span>
</pre></div>
<p>Here are links to <a href="http://pytest.org/latest/parametrize.html">more details</a> on Pytest parametrization and <a href="http://pytest.org/latest/example/parametrize.html">examples</a>.</p>
<p>[end]</p>Markdown Basic References2015-02-26T12:36:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2015-02-26:markdown-basic-references.html<p>Markdown is a system for generating HTML from readable but lightly marked-up text. It is now very widely used in blogs, README files and other repository-content, and wikis. I use it for a great deal of my own note-taking, much of which ends up in repositories (public and private).</p>
<h3>Resources for learning Markdown</h3>
<ul>
<li><a href="http://daringfireball.net/projects/markdown/syntax">Syntax of the <strong>original Markdown</strong> project</a>. It dates from 2004 and was the work of John Gruber and Aaron Swartz.</li>
<li><a href="https://help.github.com/articles/github-flavored-markdown/">GitHub Flavored Markdown (<strong>GFM</strong>)</a> is now very widely used because of its association with GitHub. It supports tables and has several resources for better presentation of code within a non-code document, such as "fenced code blocks" and syntax highlighting.</li>
<li>
<p>GitHub publishes </p>
<ul>
<li><a href="https://help.github.com/articles/markdown-basics/">a basic presentation of original Markdown rules</a> and </li>
<li>a <a href="https://guides.github.com/features/mastering-markdown/">shinier presentation</a> of both original and GFM flavors.</li>
</ul>
</li>
</ul>
<h3>Tools for previewing the output of a Markdown file</h3>
<p>Be aware that you may occasionally have to tweak your files to get them to appear as you want them to. Not only is there no single Markdown standard, but the various tools for converting to HTML seem to vary subtly in their results.</p>
<ul>
<li><a href="http://daringfireball.net/projects/markdown/dingus">The "dingus"</a> for viewing original Markdown as formatted text or HTML.</li>
<li><a href="http://pad.haroopress.com/user.html">HarooPad</a> is the most flexible desktop tool I've found, although the current version (0.13.0) has small flaws. It supports GFM and <a href="http://www.mathjax.org/">MathJax</a>, and it can be used to display slides written in Markdown.</li>
<li>
<p><a href="http://johnmacfarlane.net/pandoc/README.html">Pandoc</a> can convert Markdown to HTML. For example, to convert a GFM file "file.md" to an HTML file "file.html", use:</p>
<div class="highlight"><pre><span class="n">pandoc</span> <span class="o">-</span><span class="n">sf</span> <span class="n">markdown_github</span> <span class="o">-</span><span class="n">t</span> <span class="n">html</span> <span class="n">file</span><span class="p">.</span><span class="n">md</span> <span class="o">></span> <span class="n">file</span><span class="p">.</span><span class="n">html</span>
</pre></div>
<p>Here</p>
<ul>
<li><code>-s</code> indicates we want a "stand-alone" file, rather than a fragment for inclusion into a pre-existing header and footer frame</li>
<li><code>-f</code> specifies the format of the input file</li>
<li><code>-t</code> specifies the format of the output file</li>
</ul>
<p>It seems to me that HarooPad and Pandoc sometimes give slightly different output. My Pelican-based blog uses Pandoc (via IPython's <code>markdown.py</code>), but it sometimes produces results that look different from the output of HarooPad and GitHub.</p>
</li>
</ul>
<p>[end]</p>Two Curious Things about screen.width and screen.height on Mobile Firefox and under iOS.2015-01-19T13:07:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2015-01-19:two-curious-things-about-screen-width.html<p>I have been experimenting in my spare time with browser-fingerprinting, something that my current job deals with. Below are two curious things I have noticed.</p>
<p><strong>Background</strong>: In the mobile versions of Chrome and Opera, the values of <code>screen.width</code> tend to be swapped with <code>screen.height</code> when the device's orientation toggles between portrait and landscape. And <code>screen.availWidth</code> is swapped with <code>screen.availHeight</code> at the same time.</p>
<p><strong>Curious Thing One</strong>: In the mobile version of Firefox, the values are not always simply swapped; often they are changed somewhat. Relevant cases are boldfaced below.</p>
<p><strong>Browser: Firefox v. 35</strong></p>
<table>
<thead>
<tr>
<th align="center">device & OS</th>
<th align="center">portrait <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center">landscape <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">portrait <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">landscape <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center"><code>screen.pixelDepth</code> & <code>.colorDepth</code></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><strong>Nexus 4, Android 5.0.1</strong></td>
<td align="center">384</td>
<td align="center">384</td>
<td align="center"><strong>592</strong></td>
<td align="center"><strong>598</strong></td>
<td align="center">24</td>
</tr>
<tr>
<td align="center"><strong>Nexus 5, Android 5.0.1</strong></td>
<td align="center">360</td>
<td align="center">360</td>
<td align="center"><strong>592</strong></td>
<td align="center"><strong>598</strong></td>
<td align="center">24</td>
</tr>
<tr>
<td align="center"><strong>Verizon Ellipsis, Android 4.4.2</strong></td>
<td align="center"><strong>600</strong></td>
<td align="center"><strong>522</strong></td>
<td align="center"><strong>912</strong></td>
<td align="center"><strong>960</strong></td>
<td align="center">24</td>
</tr>
</tbody>
</table>
<hr />
<p><strong>Browser: Chrome v. 39.0.2171.93</strong></p>
<table>
<thead>
<tr>
<th align="center">device & OS</th>
<th align="center">portrait <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center">landscape <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">portrait <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">landscape <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center"><code>screen.pixelDepth</code> & <code>.colorDepth</code></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><strong>Nexus 4, Android 5.0.1</strong></td>
<td align="center">384</td>
<td align="center">384</td>
<td align="center">640</td>
<td align="center">640</td>
<td align="center">32</td>
</tr>
<tr>
<td align="center"><strong>Nexus 5, Android 5.0.1</strong></td>
<td align="center">360</td>
<td align="center">360</td>
<td align="center">640</td>
<td align="center">640</td>
<td align="center">32</td>
</tr>
<tr>
<td align="center"><strong>Verizon Ellipsis, Android 4.4.2</strong></td>
<td align="center">601</td>
<td align="center">601</td>
<td align="center">692</td>
<td align="center">692</td>
<td align="center">32</td>
</tr>
</tbody>
</table>
<hr />
<p><strong>Browser: Opera v. 26.0.1656.87080</strong></p>
<table>
<thead>
<tr>
<th align="center">device & OS</th>
<th align="center">portrait <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center">landscape <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">portrait <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">landscape <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center"><code>screen.pixelDepth</code> & <code>.colorDepth</code></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><strong>Nexus 4, Android 5.0.1</strong></td>
<td align="center">384</td>
<td align="center">384</td>
<td align="center">640</td>
<td align="center">640</td>
<td align="center">32</td>
</tr>
<tr>
<td align="center"><strong>Nexus 5, Android 5.0.1</strong></td>
<td align="center">360</td>
<td align="center">360</td>
<td align="center">640</td>
<td align="center">640</td>
<td align="center">32</td>
</tr>
<tr>
<td align="center"><strong>Verizon Ellipsis, Android 4.4.2</strong></td>
<td align="center">601</td>
<td align="center">601</td>
<td align="center">692</td>
<td align="center">692</td>
<td align="center">32</td>
</tr>
</tbody>
</table>
<hr />
<p><strong>Curious Thing Two</strong>: On the current version of iOS for the iPad mini, it seems that toggling the orientation is handled in such a way that <code>screen.width</code> and <code>.height</code> are not changed at all. That is, even when in landscape orientation, the width of the screen is reported as narrower than the height of the screen:</p>
<p><strong>Browser: Chrome v. 39.0.2171.50</strong>:</p>
<table>
<thead>
<tr>
<th align="center">device & OS</th>
<th align="center">portrait <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center">landscape <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">portrait <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">landscape <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center"><code>screen.pixelDepth</code> & <code>.colorDepth</code></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><strong>iPad mini, iOS 7.1.1</strong></td>
<td align="center">768</td>
<td align="center"><strong>1024 (& 1004)</strong></td>
<td align="center">1024 (& 1004)</td>
<td align="center"><strong>768</strong></td>
<td align="center">32</td>
</tr>
</tbody>
</table>
<p><strong>Browser: Opera v. 9.1.0.8673</strong>:</p>
<table>
<thead>
<tr>
<th align="center">device & OS</th>
<th align="center">portrait <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center">landscape <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">portrait <code>screen.height</code> & <code>.availHeight</code></th>
<th align="center">landscape <code>screen.width</code> & <code>.availWidth</code></th>
<th align="center"><code>screen.pixelDepth</code> & <code>.colorDepth</code></th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><strong>iPad mini, iOS 7.1.1</strong></td>
<td align="center">768 (& 748)</td>
<td align="center"><strong>1024</strong></td>
<td align="center">1024</td>
<td align="center"><strong>768 (& 748)</strong></td>
<td align="center">32</td>
</tr>
</tbody>
</table>
<hr />
<p><strong>Notes</strong>:</p>
<ol>
<li>On iOS, <code>screen.width</code> and <code>screen.availWidth</code> differ slightly in Opera, unlike on Nexus 4, Nexus 5, or Verizon Ellipsis. In Chrome, <code>screen.height</code> and <code>screen.availHeight</code> likewise differ slightly.</li>
<li>At the time of this writing, Firefox is not available for iOS.</li>
<li>For the iOS results, it does not seem to make a different what the orientation of the device is at startup or when the apps are launched. Clearing the browser caches and browsing history makes no difference, either.</li>
<li>This research was done 2015.01.15-19, using one version of each reported device. I have made no attempts to confirm these results on additional versions of the devices.</li>
</ol>
<p>[end]</p>Where Do I Stand on Digital Advertising?2015-01-01T19:34:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2015-01-01:where-do-i-stand-on-digital-advertising.html<p>Today I have thinking about this: On the Internet am I “stealing” any content that I view or service that I use, if I neither pay for it nor experience advertising that its creator expects to earn money from? It’s an old question and I don’t have an answer, but I do have some thoughts about it.*</p>
<p>In a article last month reporting <a href="http://www.i-programmer.info/news/152-epub/8096-dr-dobbs-bites-the-dust-after-38-years.html">the doleful demise of Dr. Dobb’s Journal</a>, <em>I Programmer</em>’s Mike James writes:</p>
<blockquote>
<p>The web is a very hostile place for anyone with the idea that they might encourage professional technical writing by paying for it rather than just expecting it to be given for free. Dr Dobb’s is a victim of this impossible environment. What we were once willing to buy on paper, we expect to be given away on web pages. </p>
</blockquote>
<p><em>I Programmer</em> has discussed this issue frankly for some time. Sue Gee wrote a substantial article there about the problem (<a href="http://www.i-programmer.info/the-stone-tapes/6309-adblocking-looking-for-a-solution.html">1</a>, <a href="http://www.i-programmer.info/the-stone-tapes/6309-adblocking-looking-for-a-solution.html?start=1">2</a>) in August, 2013. Gee cites a <a href="http://downloads.pagefair.com/reports/the_rise_of_adblocking.pdf">report</a> on the effects of ad-blocking by <a href="https://pagefair.com/">PageFair</a>, which does business measuring the extent of ad-blocking. (<a href="http://downloads.pagefair.com/reports/adblocking_goes_mainstream_2014_report.pdf">Here</a>’s a newer PageFair report, from 2014 — there is a <a href="https://pagefair.com/press_release/pagefair-2014-report/">20140909 press release</a> associated with it.)</p>
<p>I’m surprised to find how gripping this topic has become to me. I am recently hired into my first paid programming job, and it happens to be in the digital advertising industry, but before that I had a career as a tenured professor in a field within the Humanities that was a <em>lěngmén</em> 冷門 ‘cold gate’, a subject as devoid of popular interest as your imagination might portray for you. Baldly speaking, as a capitalistic ad-man I should be stereotyped as in favor of advertising and as a cranky ivory-tower type I should be stereotyped as against it. So where does that leave me, speaking morally and emotionally?</p>
<hr />
<p>As a Humanist I was usually paid nothing — or once in a while a tiny royalty — for my published work. I saw clearly that the world expected me to give my work away for nothing. Humanist professors, apart from the famous, are usually badly paid, too. The publishers who ushered my writing into print, however, have made some profit on it, though usually a small one (so cold was my gate). At the same time, I’ve gotten used to a life in which I encounter almost no advertising at all, and I’m happy about that — even in the days when I owned and watched a television set I cultivated habits allowing me to see as little advertising as possible. I always found the construction of television and flat-media ads very interesting, but I organized my viewing and reading so as to encounter as few of them as possible except when I was in a position to control my experience of them, usually in order to study how they affected the viewer. This is less a privacy issue for me than an issue of controlling my own time and attention. Not being interrupted still seems to me a crucial right in my life both as scholar and engineer — it is not possible for me to do good intellectual work when I know I may be broken in on by demands for attention. There’s a fine maxim about this by <a href="http://www.dailyenglishquote.com/2013/08/donald-rumsfeld/">Donald Rumsfeld</a>:</p>
<blockquote>
<p>If you are working from your inbox, you are working on other people’s priorities.</p>
</blockquote>
<p>Here’s <a href="william-deresiewicz-on-multitasking-and-solitude-2009.html">another good thought on a kindred subject</a>, by William Deresiewicz.</p>
<p>But now I am in the pay of a digital advertising company, rapidly growing and with justice called a leader in the field — while also preparing to bring out my first self-published book in many years. Working in ad-tech has already taught me a lot about technical obstacles to on-line advertising and how to erect them for myself. Beyond blocking third-party cookies, and beyond installing Adblock Plus and Ghostery (both of which now earn money from the advertising industry!), I’ve also begun using <a href="https://noscript.net">NoScript</a>, which lets me examine the analytics- and advertising-trackers (these are JavaScript programs) embedded in any website before I choose to permit those trackers to operate. And I’ve recently begun using Google Adsense and PageFair on some of my own sites, the better to understand the mechanics of this crazy business. (It does not appear that PageFair works as expected on my browser.)</p>
<p>Preparing to bring out a book at my own expense, I remember that it will probably be pirated and made available on line on very short order, so that the only way I am likely to recoup my publication costs is through advertising of some sort. The whole situation is luscious with irony.</p>
<p>In this I am in the same state of paradox† as many creative people: I receive little or no pay for my own creative work, and pay little or nothing in return for others’ creative work. Why paradox? Because I don't want to be stolen from but I steal from others. Well, that <em>is</em> an extreme statement. In reality, I pay to subscribe to the two newspapers I read on line most often, as well as to an on-line dictionary I use a great deal. I know of ways to get my paws on that content surreptitiously at no cost, but I pay anyway and forego the delights of guile. Beyond that, I am a dues-paying member of the Authors Guild (legal defender of the collective copyright of individual writers), and I also donate substantially to an organization that gives away free software. I pay either to rent or purchase every movie I watch and every book I read or refer to significantly, apart from what I borrow from libraries. In consequence I possess, I think, vastly more physical copies of books, DVDs, and CDs than most of the other engineers I know. I possess on the order of ten thousand paper books, and many hundreds of CDs and DVDs, not to mention more electronic editions than I know how to count. Yes, I pay with neurotic honesty for a lot more content and services than many engineers I know. But it’s true that even if I pay a lot, I still surely don’t pay for as much as I’m expected to by some people. The question is, is their expectation right and reasonable?</p>
<p>In the end, I’m not sure where I stand on the issue of digital advertising now. Ultimately, I’d like to be paid properly for <em>my</em> intellectual work, but the likelihood of doing so seems even smaller now than it did when I first became an author. One of the current business slogans to which my employer subscribes is "software as a service" (SaaS) — it seems that not only my company but I, too, am paid as part of that model. But some people who are creating intellectual content are not paid for it at all, except through advertising, most of which I never see.</p>
<hr />
<p>.* I’ve written about these issues a little before: <a href="distribution-of-fonts-competing-models-are-coexisting.html">1</a>, <a href="a-poor-analogy-on-intellectual-property-rights.html">2</a>.</p>
<p>† Maybe a better name would be <em>enantiodromia</em>, lit. “running in opposite directions”, the condition (considered inevitable by some) of turning into one’s own opposite. <em>Paradox</em> may be a state, but <em>enantiodromia</em> is evidently an evolving condition. The term today is associated with Heraclitus (who denied the possibility of stasis) and appears in <a href="http://www.perseus.tufts.edu/hopper/text?doc=Perseus%3Atext%3A1999.01.0257%3Abook%3D9%3Achapter%3D1#note-link11">Diogenes Laërtius’s résumé of his ideas, <em>Lives of Eminent Philosophers</em>, book IX: α.7</a>, (<a href="http://www.perseus.tufts.edu/hopper/text?doc=urn:cts:greekLit:tlg0004.tlg001.perseus-eng1:9.1">English here</a>). The <a href="http://www.oed.com/view/Entry/61554">earliest English citations in the Oxford English Dictionary</a> are to editions of Jung.</p>
<p>[end]</p>Progressing to the Next Level after Two Years at Hacker School2014-11-21T01:07:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2014-11-21:progressing-to-the-next-level-after-two-years-at-hacker-school.html<p>I packed up all my things and left <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a> a little after nine this past evening. It is likely to be my last time there as a regular <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a>er, for whatever future I can envisage. Over the past twenty-two months <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a> has been the center of my intellectual life as a programmer. I expect to return for Monday-night lectures and to remain in active contact with the community, but time spent coding on-site is likely to be rare for me now that I have full-time work. </p>
<p>When younger I would have seized on “bittersweet” to describe my sensations tonight, but a moment ago I reached for the word and found it gone stale on me. More vividly, I am aware that I am at a joint in time — a rapid, stark shift in my experience of the world. These days between <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a> and my job are a “moment”, in its etymological sense as a “moving instant”. I accept the passage of time, or more precisely my passage along time, and also the wreckage I leave after me in memory because of that passage. I was conscious of a mood of ceremony as I took one last look at my table and left the building alone.</p>
<p>I did one programming exercise today, start to finish, in the HS space: a <a href="https://github.com/DataBranner/AlgorithmPlay/tree/master/python_kmp">Python generator-implementation</a> of the Knuth-Morris-Pratt (KMP) sequence-matching algorithm (<a href="http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/">here is a patient, readable presentation</a> in case you’re tired of going to Wikipedia for everything). I wrote my code along with a suite of 15 <code>Pytest</code> unit-tests, but next I want to write a <code>Unittest</code> version in parallel to the <code>Pytest</code>, since the company I am joining seems to prefer that. After that, perhaps I’ll find time to use <code>cProfile</code> and <code>pdb</code> to explore the code a little, as a way of refreshing my knowledge of those tools. Actual coding probably won’t start at work till after Thanksgiving, and I can believe I’ll still be working on my own projects for a little while.</p>
<p>I have wanted for a long time to understand KMP — I was exposed to the germ of the idea in the Fall of 2010, during a professor’s digression as he gave my class a review session for a test on finite automata. It has been sitting in a raw state in the back of my attention ever since. So today I picked it out of the cobwebs and wrote it up. I based my implementation on the presentation in the fat algorithm book by Cormen et al., so there is nothing very original in my work. But for me there’s no better way to understand a computational idea than to wrestle with it in the form of actual code. There are always off-by-one errors that come about when you convert Cormen’s 1-indexed arrays, along with all that they imply for loops, to Python’s 0-indexed lists. Rubbing those gremlins out is a good way to make sure I understand how an algorithm actually works. Cormen’s variable names are always abstract, too, so doing the study necessary to pick fresh ones helps clarify the moral philosophy of the algorithm. Besides all that, I decided to return the result lazily with a <code>yield</code> statement rather than as a finished array. That’s all, then — a good, low-key piece of hands-on-learning, an ideal project for a single day’s work on Alumni Thursday. It was a good mark with which to punctuate my time at <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a>. And since it took me four years to get around to this famous problem and its clever solution, it is the perfect seal to affix at the end of the period* I spent preparing myself to become a software engineer.</p>
<p><a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a>’s motto is “Never Graduate”. I understand that is meant to answer the conventional understanding of “school” as a place you attend for a little while and then leave, supposedly complete in some rigid course of study. “Graduate” in this view equals “stop learning and leave,” but <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a> wants its students to think of learning as an unending process. Quite right, too. Then again, my background is different from that of most other <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a>ers — I’ve been “in” school, in various capacities, for almost half a century. And I understand “to graduate” in the sense “to rise a step or progress to the next level”. It was not in error that graduating used to be called “commencing”, which survives in our “commencement” for a graduation ceremony; to graduate is to begin, not only to end. So I am happy to accept that I have graduated many times in the past without ceasing to learn, and hope to do so again many times more. Today I did experience a moment of graduation from <a href="https://www.recurse.com/scout/click?t=61e1baec0cdd25caf86b60b6efafde65" target="_blank">Hacker School</a>, in that sense. I won’t insist on the word, though, since the Institution dislikes it. But I think no one would deny me the sense of ceremony, right now, that is entailed on both “graduate” and “progress to the next level”.</p>
<hr />
<ul>
<li>Isn’t it interesting that a “period” is both a cycle and a mark you use to indicate the joint between two cycles?</li>
</ul>
<p>[end]</p>Health Insurance $5,600/year ⇨ $12,600/year to Keep Our Doctor2014-11-04T22:25:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2014-11-04:health-insurance-5600-year-12600-year.html<p>In 2015 our insurance will jump from $5,600/year to $12,600/year if we want to keep our family doctor. Even if we do nothing and let the forces of darkness send us to a doctor of their choice, our insurance is scheduled to jump to $9,240/year.</p>
<p>Our doctor will only be on two insurance networks in 2015 — I’ve called both and only one of them knew what its rates would be next year. One thing we do already know is that in 2015 no plans in New York State cover out-of-network services, so in order to have our doctor in-network we are being forced to choose one of these two plans. And in either case, that means paying the high price of a much lower deductible than we feel we can afford — it has been much more cost-effective, since the COBRA coverage from my last job ended, for us to pay a low premium for a high deductible. I thought that was a good and responsible decision on our parts, and I had hoped we would be living with it for a number of years. But that option has now ended for us. The choice now is either to give up our doctor and pay $9,240/year for a much lower deductible than we want, or else pay $12,600/year and keep him, and also have a lower deductible than we want. 65% more to lose him vs. 125% more to keep him. </p>
<p>We will keep our doctor, and we will adjust our budget one way or another. And we now know, in case we didn’t before, that our government is working for lobbyists rather than for us, so I suppose before long we will find we have adjusted our states of mind, too. But it’s hard to figure out specifically who is directly responsible for this twisted situation. My U.S. Senators, <a href="https://www.opensecrets.org/politicians/industries.php?type=C&cid=N00001093&newMem=N&cycle=2014">Schumer</a> and <a href="https://www.opensecrets.org/politicians/industries.php?cycle=2014&type=C&cid=N00027658&newMem=N&recs=20">Gillibrand</a>, together took close to a million and a half dollars from the insurance industry in the most recent campaign cycle, according to <a href="http://OpenSecrets.org">the Center for Responsive Politics</a>, but I don’t know where to go to find numbers on my state representatives. The one thing I <em>am</em> sure of is that when the Affordable Care Act was being proposed, the current state of affairs was certainly not what was intended. </p>
<p>There is said to be some sort of official subsidy for people with low income, but it isn’t yet possible to find out whether the plans that include our doctor are eligible for that. In any event this subsidy, like the pressure to give up our doctor, smacks of welfare. I will do my best to avoid it for that reason. I am unwilling to be forced onto the public dole, and I will vote against all political parties that would have me do that. I sense that this imperative is going to replace the political issues that have been most important to me since I began voting in 1980. Watching my mind’s reaction to these things — that’s what I’m doing now.</p>
<p>Today was election day. Although I was tempted to vote against every incumbent politician, in practice that wasn’t possible. For one thing, my State Assemblyperson is running unchallenged, and for another he has appeared reasonable on the occasions I’ve interacted with his office. I had badly wanted to vote against the Governor because of a very suspicious-looking action of his, suppressing a commission investigating corruption. But when I looked hard at the challengers and their parties, I saw only ideologues with varying degrees of coherence, and none of them with hands-on administrative experience. The Governor is at least competent at running government offices, even if he should turn out to be a crook. I am naïve and stubborn enough that I don’t want to waste my vote in a gesture of protest. And on reflection, I see that the Governor has made two high-level decisions that I consider reasonable — both of them seem to have lost him a lot of support among voters adhering to ideologies I don’t care for. So I voted for him but on a minor party affiliation, a form of subdued protest that is possible in New York State. </p>
<p>I am dissatisfied with the entire situation, not least my choices at the polls, and I’m sure I’m not the only person in this state of mind. I worry, though, that other people may respond to this predicament less reasonably than I have. This sucker is fed up and no longer wants to see the rest of the circus, but he hesitates at the exit. Better to stay in the tent if you can. But will they let you? Can you get your nickel back if you leave?</p>
<hr />
<p>One of today’s three New York State ballot proposals was a bond act to raise funds for “school technology”. I had read discussions about it and felt myself siding with those opponents who called it a boondoggle for certain technology firms. But at the polling site today I observed myself voting for it. If even just a few thousand kids get into the serious study of technology because of this act, I mean kids who wouldn’t otherwise have because they’re from rural or ghetto areas and their parents don’t know how to make this gift to them, then the interest money we State taxpayers have to pay will be money well spent. I’d much rather see that happen than not. Technology is one of the few things you can study that is genuinely good for your mind, and we should pay what it costs to bring people into it.</p>
<p>[end]</p>Always Use Dry-run Options If Possible2014-11-04T16:50:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2014-11-04:always-use-dry-run-options-if-possible.html<p>When I learn a new command-line tool, I have taken to checking the documentation for “dry-run” functionality. Using an option <code>--dry-run</code> (sometimes <code>--dry_run</code> or <code>--dryrun</code>) simulates a command without actually running it. That way, if there is an error or something you didn’t expect, you can make changes before actually running the command for real. Especially when the command may cause expense (opening a connection and writing files to a server) or some far-reaching change (deleting or altering code or state), it’s a good idea to take a little time to be sure you expect what is coming.</p>
<p>Below I list six programs that have dry-run options, illustrating various characteristics of the principle: Git, Homebrew, Make, Bash, TeX Live Manager, and Trial. But before I begin, I want to make two larger points.</p>
<p>First, one of the most common causes of inadvertent damage at the command line is the use of <code>rm</code> to delete files and directories. And <code>rm</code> has no dry-run option at this time. But there is <a href="https://github.com/andreafrancia/trash-cli"><code>trash-cli</code></a>, which moves files to the trash while leaving you the option of restoring anything you inadvertently delete. Note that the author recommends against mapping <code>rm</code> to <code>trash-cli</code>.</p>
<p>Second, I’m aware of three issues to be cautious about when doing dry runs. </p>
<ol>
<li>A dry run may print full prospective output to the terminal; but sometimes, depending on the program, it merely reports errors. It is good to know which of these you are getting.</li>
<li>Some programs use <code>-n</code> as shorthand for the dry-run option or even instead of it. But the <code>-n</code> option is also widely used for “number” and for “not [some other default functionality]”, and you can get into a serious pickle if <code>-n</code> doesn’t behave as you thought it would. Read the docs, Comrade Coder.</li>
<li>Some programs report to you explicitly that a dry-run is merely that; others assume you are aware of what you are doing. That means that if you are not careful, you may think you have run a command when you have only done a dry run of it. In the first Git example, below, a dry run produces output indistinguishable from actually running the command; in the second and third Git examples, the output distinguishes them quite clearly.</li>
</ol>
<h2>1. Git</h2>
<p>Version control systems tend to have dry-run functionality, since you can create a huge snarl of work for yourself and others if you gum up a repository with erroneous commits. Here are two examples from Git, where <code>--dry-run</code> is usually available; in some cases <code>-n</code> has the same effect:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">git</span> <span class="n">add</span> <span class="o">-</span><span class="n">Avn</span> <span class="p">..</span>
<span class="n">add</span> <span class="p">...</span>
</pre></div>
<p>I am asking git to verbosely <code>add</code> any changed files in the current directory and below, including any files previously committed. The output gives no indication that this is a dry run, so you must remember to use <code>git add -Av ...</code> afterwards so that the files are actually staged.</p>
<div class="highlight"><pre><span class="err">$</span> <span class="nx">git</span> <span class="nx">commit</span> <span class="o">--</span><span class="nx">dry</span><span class="na">-run</span>
<span class="k">On</span> <span class="nx">branch</span> <span class="nx">master</span>
<span class="nx">Your</span> <span class="nx">branch</span> <span class="nx">is</span> <span class="nb">up</span><span class="na">-to-date</span> <span class="k">with</span> <span class="s1">'origin/master'</span><span class="nx">.</span>
<span class="nx">Changes</span> <span class="k">to</span> <span class="nx">be</span> <span class="nx">committed</span><span class="p">:</span>
<span class="p">(</span><span class="nx">use</span> <span class="s2">"git reset HEAD <file>..."</span> <span class="k">to</span> <span class="nx">unstage</span><span class="p">)</span>
<span class="nx">modified</span><span class="p">:</span> <span class="nx">...</span>
</pre></div>
<p>An actual commit, in contrast, would report something like this:</p>
<div class="highlight"><pre><span class="p">[</span><span class="n">master</span> <span class="mi">52</span><span class="n">a0905</span><span class="p">]</span> <span class="o"><</span><span class="n">commit</span> <span class="n">message</span><span class="o">></span>
<span class="mi">1</span> <span class="n">file</span> <span class="n">changed</span><span class="p">,</span> <span class="mi">19</span> <span class="n">insertions</span><span class="p">(</span><span class="o">+</span><span class="p">),</span> <span class="mi">3</span> <span class="n">deletions</span><span class="p">(</span><span class="o">-</span><span class="p">)</span>
</pre></div>
<p>If you include other options with <code>git commit</code>, you will see that full prospective commit behavior in the terminal output. I’m partial to <code>git commit -v</code> for “verbose” commit-content and <code>git commit -o</code> for committing “only” specified files.</p>
<p>Note that <code>git commit -n</code> is <em>not</em> the same as <code>git commit --dry-run</code>; this is a case where you must avoid being lazy about typing out the full option.</p>
<p>When pushing, the dry run does actually contact the server but omits the rest of the rigamarole:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">git</span> <span class="n">push</span> <span class="o">--</span><span class="n">dry</span><span class="o">-</span><span class="n">run</span>
<span class="n">Host</span> <span class="n">key</span> <span class="n">fingerprint</span> <span class="n">is</span> <span class="mi">16</span><span class="o">:</span><span class="mi">27</span><span class="o">:</span><span class="n">ac</span><span class="o">:</span><span class="n">a5</span><span class="o">:</span><span class="mi">76</span><span class="o">:</span><span class="mi">28</span><span class="o">:</span><span class="mi">2</span><span class="n">d</span><span class="o">:</span><span class="mi">36</span><span class="o">:</span><span class="mi">63</span><span class="o">:</span><span class="mi">1</span><span class="n">b</span><span class="o">:</span><span class="mi">56</span><span class="o">:</span><span class="mi">4</span><span class="n">d</span><span class="o">:</span><span class="n">eb</span><span class="o">:</span><span class="n">df</span><span class="o">:</span><span class="n">a6</span><span class="o">:</span><span class="mi">48</span>
<span class="n">To</span> <span class="n">git</span><span class="err">@</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">:</span><span class="n">brannerchinese</span><span class="o">/</span><span class="n">MelodyOfLyric</span><span class="p">.</span><span class="n">git</span>
<span class="mi">1</span><span class="n">bceabf</span><span class="p">.</span><span class="mf">.53033</span><span class="n">b0</span> <span class="n">master</span> <span class="o">-></span> <span class="n">master</span>
<span class="err">$</span> <span class="n">git</span> <span class="n">push</span>
<span class="n">Host</span> <span class="n">key</span> <span class="n">fingerprint</span> <span class="n">is</span> <span class="mi">16</span><span class="o">:</span><span class="mi">27</span><span class="o">:</span><span class="n">ac</span><span class="o">:</span><span class="n">a5</span><span class="o">:</span><span class="mi">76</span><span class="o">:</span><span class="mi">28</span><span class="o">:</span><span class="mi">2</span><span class="n">d</span><span class="o">:</span><span class="mi">36</span><span class="o">:</span><span class="mi">63</span><span class="o">:</span><span class="mi">1</span><span class="n">b</span><span class="o">:</span><span class="mi">56</span><span class="o">:</span><span class="mi">4</span><span class="n">d</span><span class="o">:</span><span class="n">eb</span><span class="o">:</span><span class="n">df</span><span class="o">:</span><span class="n">a6</span><span class="o">:</span><span class="mi">48</span>
<span class="n">Counting</span> <span class="n">objects</span><span class="o">:</span> <span class="mi">9</span><span class="p">,</span> <span class="n">done</span><span class="p">.</span>
<span class="n">Delta</span> <span class="n">compression</span> <span class="n">using</span> <span class="n">up</span> <span class="n">to</span> <span class="mi">8</span> <span class="n">threads</span><span class="p">.</span>
<span class="n">Compressing</span> <span class="n">objects</span><span class="o">:</span> <span class="mi">100</span><span class="o">%</span> <span class="p">(</span><span class="mi">5</span><span class="o">/</span><span class="mi">5</span><span class="p">),</span> <span class="n">done</span><span class="p">.</span>
<span class="n">Writing</span> <span class="n">objects</span><span class="o">:</span> <span class="mi">100</span><span class="o">%</span> <span class="p">(</span><span class="mi">5</span><span class="o">/</span><span class="mi">5</span><span class="p">),</span> <span class="mi">484</span> <span class="n">bytes</span> <span class="o">|</span> <span class="mi">0</span> <span class="n">bytes</span><span class="o">/</span><span class="n">s</span><span class="p">,</span> <span class="n">done</span><span class="p">.</span>
<span class="n">Total</span> <span class="mi">5</span> <span class="p">(</span><span class="n">delta</span> <span class="mi">4</span><span class="p">),</span> <span class="n">reused</span> <span class="mi">0</span> <span class="p">(</span><span class="n">delta</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">To</span> <span class="n">git</span><span class="err">@</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="o">:</span><span class="n">brannerchinese</span><span class="o">/</span><span class="n">MelodyOfLyric</span><span class="p">.</span><span class="n">git</span>
<span class="mi">1</span><span class="n">bceabf</span><span class="p">.</span><span class="mf">.53033</span><span class="n">b0</span> <span class="n">master</span> <span class="o">-></span> <span class="n">master</span>
</pre></div>
<h2>2. Homebrew</h2>
<p>Homebrew, the package management system for Unix software on Darwin (Macintosh), allows a <code>--dry-run</code> option, which can be shortened to <code>-n</code>:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">brew</span> <span class="n">link</span> <span class="o">-</span><span class="n">n</span> <span class="n">ghostscript</span>
<span class="n">Would</span> <span class="n">link</span><span class="o">:</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">dvipdf</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">eps2eps</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">font2c</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">gs</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">gsbj</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">gsc</span>
<span class="p">...</span>
<span class="err">$</span> <span class="n">brew</span> <span class="n">link</span> <span class="n">ghostscript</span>
<span class="n">Linking</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">Cellar</span><span class="o">/</span><span class="n">ghostscript</span><span class="o">/</span><span class="mf">9.15</span><span class="p">...</span> <span class="mi">64</span> <span class="n">symlinks</span> <span class="n">created</span>
</pre></div>
<p>Its output is more explicit than actually running the command, and it thoughtfully uses the modal auxiliary verb “would” to indicate the counterfactual state.</p>
<h2>3. Make</h2>
<p>The <code>make</code> program is a build-process manager. Running it can initiate a very long process during which many sorts of things may go wrong, so it is a good idea to do a dry run first. Using</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">make</span> <span class="o">-</span><span class="n">n</span>
</pre></div>
<p>prints to <code>stdout</code> all commands that would be executed by <code>make</code>, without actually executing them; there is not necessarily any output other than those commands. But I have seen a case (<a href="https://www.mailvelope.com/"><code>mailvelope</code></a>) where it marks prospective output as counterfactual, too, by use of <code>echo</code>: so rather than </p>
<div class="highlight"><pre><span class="n">build</span> <span class="o">-</span> <span class="n">copy</span> <span class="n">common</span> <span class="n">folder</span> <span class="n">and</span> <span class="n">dependencies</span>
</pre></div>
<p>it prints</p>
<div class="highlight"><pre><span class="n">echo</span> <span class="s">"build - copy common folder and dependencies"</span>
</pre></div>
<p>Option <code>-n</code> can be replaced more explicitly with <code>--dry-run</code>. Both options are also available for <code>rake</code> (Ruby’s equivalent to <code>make</code>).</p>
<h2>4. Bash</h2>
<p>The Bash Unix shell, when invoked to read shell scripts, has a dry-run option:</p>
<div class="highlight"><pre><span class="nx">bash</span> <span class="na">-n</span> <span class="o"><</span><span class="nb">script</span><span class="o">></span>
</pre></div>
<p>This reads <code><script></code> without executing it and reports any syntax errors. It does not show the actual commands issued or their results, and if there are no syntax errors there will be no output at all.</p>
<h2>5. TeX Live Manager (tlmgr)</h2>
<p>TeX Live Manager, the package manager for LaTeX, has a <code>--dry-run</code> option for <code>update</code>, <code>install</code>, <code>backup</code>, and several other commands. It shows the expected output for the command, though without valid download-timing data:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">sudo</span> <span class="n">tlmgr</span> <span class="n">update</span> <span class="o">--</span><span class="n">all</span> <span class="o">--</span><span class="n">dry</span><span class="o">-</span><span class="n">run</span>
<span class="nl">Password:</span>
<span class="nl">tlmgr:</span> <span class="n">package</span> <span class="n">repository</span> <span class="n">http</span><span class="o">:</span><span class="c1">//ctan.math.washington.edu/tex-archive/systems/texlive/tlnet</span>
<span class="nl">update:</span> <span class="n">dry</span> <span class="n">run</span><span class="p">,</span> <span class="n">no</span> <span class="n">changes</span> <span class="n">will</span> <span class="n">be</span> <span class="n">made</span>
<span class="nl">tlmgr:</span> <span class="n">saving</span> <span class="n">backups</span> <span class="n">to</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">texlive</span><span class="o">/</span><span class="mi">2014</span><span class="o">/</span><span class="n">tlpkg</span><span class="o">/</span><span class="n">backups</span>
<span class="p">[</span> <span class="mi">1</span><span class="o">/</span><span class="mi">18</span><span class="p">,</span> <span class="o">??:??/??:??</span><span class="p">]</span> <span class="n">update</span><span class="o">:</span> <span class="n">biblatex</span><span class="o">-</span><span class="n">anonymous</span> <span class="p">[</span><span class="mi">53</span><span class="n">k</span><span class="p">]</span> <span class="p">(</span><span class="mi">35451</span> <span class="o">-></span> <span class="mi">35491</span><span class="p">)</span>
<span class="p">[</span> <span class="mi">2</span><span class="o">/</span><span class="mi">18</span><span class="p">,</span> <span class="mo">00</span><span class="o">:</span><span class="mo">00</span><span class="o">/</span><span class="mo">00</span><span class="o">:</span><span class="mo">00</span><span class="p">]</span> <span class="n">update</span><span class="o">:</span> <span class="n">biblatex</span><span class="o">-</span><span class="n">realauthor</span> <span class="p">[</span><span class="mi">76</span><span class="n">k</span><span class="p">]</span> <span class="p">(</span><span class="mi">35452</span> <span class="o">-></span> <span class="mi">35499</span><span class="p">)</span>
<span class="p">[</span> <span class="mi">3</span><span class="o">/</span><span class="mi">18</span><span class="p">,</span> <span class="mo">00</span><span class="o">:</span><span class="mo">00</span><span class="o">/</span><span class="mo">00</span><span class="o">:</span><span class="mo">00</span><span class="p">]</span> <span class="n">update</span><span class="o">:</span> <span class="n">bibleref</span><span class="o">-</span><span class="n">french</span> <span class="p">[</span><span class="mi">642</span><span class="n">k</span><span class="p">]</span> <span class="p">(</span><span class="mi">27098</span> <span class="o">-></span> <span class="mi">35497</span><span class="p">)</span>
<span class="p">...</span>
</pre></div>
<p>TeX Live Manager tells you clearly, “dry run, no changes will be made;” here is how the actual output would look:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">sudo</span> <span class="n">tlmgr</span> <span class="n">update</span> <span class="o">--</span><span class="n">all</span>
<span class="nl">Password:</span>
<span class="nl">tlmgr:</span> <span class="n">package</span> <span class="n">repository</span> <span class="n">http</span><span class="o">:</span><span class="c1">//ctan.mirrors.hoobly.com/systems/texlive/tlnet</span>
<span class="nl">tlmgr:</span> <span class="n">saving</span> <span class="n">backups</span> <span class="n">to</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">texlive</span><span class="o">/</span><span class="mi">2014</span><span class="o">/</span><span class="n">tlpkg</span><span class="o">/</span><span class="n">backups</span>
<span class="p">[</span> <span class="mi">1</span><span class="o">/</span><span class="mi">18</span><span class="p">,</span> <span class="o">??:??/??:??</span><span class="p">]</span> <span class="n">update</span><span class="o">:</span> <span class="n">biblatex</span><span class="o">-</span><span class="n">anonymous</span> <span class="p">[</span><span class="mi">53</span><span class="n">k</span><span class="p">]</span> <span class="p">(</span><span class="mi">35451</span> <span class="o">-></span> <span class="mi">35491</span><span class="p">)</span> <span class="p">...</span> <span class="n">done</span>
<span class="p">[</span> <span class="mi">2</span><span class="o">/</span><span class="mi">18</span><span class="p">,</span> <span class="mo">00</span><span class="o">:</span><span class="mo">03</span><span class="o">/</span><span class="mi">16</span><span class="o">:</span><span class="mi">09</span><span class="p">]</span> <span class="n">update</span><span class="o">:</span> <span class="n">biblatex</span><span class="o">-</span><span class="n">realauthor</span> <span class="p">[</span><span class="mi">76</span><span class="n">k</span><span class="p">]</span> <span class="p">(</span><span class="mi">35452</span> <span class="o">-></span> <span class="mi">35499</span><span class="p">)</span> <span class="p">...</span> <span class="n">done</span>
<span class="p">[</span> <span class="mi">3</span><span class="o">/</span><span class="mi">18</span><span class="p">,</span> <span class="mo">00</span><span class="o">:</span><span class="mo">05</span><span class="o">/</span><span class="mi">11</span><span class="o">:</span><span class="mo">00</span><span class="p">]</span> <span class="n">update</span><span class="o">:</span> <span class="n">bibleref</span><span class="o">-</span><span class="n">french</span> <span class="p">[</span><span class="mi">642</span><span class="n">k</span><span class="p">]</span> <span class="p">(</span><span class="mi">27098</span> <span class="o">-></span> <span class="mi">35497</span><span class="p">)</span> <span class="p">...</span> <span class="n">done</span>
<span class="p">...</span>
<span class="nl">tlmgr:</span> <span class="n">package</span> <span class="n">log</span> <span class="n">updated</span><span class="o">:</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">texlive</span><span class="o">/</span><span class="mi">2014</span><span class="o">/</span><span class="n">texmf</span><span class="o">-</span><span class="n">var</span><span class="o">/</span><span class="n">web2c</span><span class="o">/</span><span class="n">tlmgr</span><span class="p">.</span><span class="n">log</span>
<span class="n">running</span> <span class="n">mktexlsr</span> <span class="p">...</span>
<span class="n">done</span> <span class="n">running</span> <span class="n">mktexlsr</span><span class="p">.</span>
<span class="n">running</span> <span class="n">mtxrun</span> <span class="o">--</span><span class="n">generate</span> <span class="p">...</span>
<span class="n">done</span> <span class="n">running</span> <span class="n">mtxrun</span> <span class="o">--</span><span class="n">generate</span><span class="p">.</span>
<span class="n">running</span> <span class="n">updmap</span><span class="o">-</span><span class="n">sys</span> <span class="p">...</span>
<span class="n">done</span> <span class="n">running</span> <span class="n">updmap</span><span class="o">-</span><span class="n">sys</span><span class="p">.</span>
</pre></div>
<h2>6. Trial</h2>
<p>Trial is a Python unit-testing system for use with Twisted. Running</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">trial</span> <span class="o">-</span><span class="n">n</span>
</pre></div>
<p>will iterate through all tests and report them passing, without actually running them. Option <code>-n</code> can be replaced more explicitly with <code>--dry-run</code>.</p>
<hr />
<p>Many other programs — </p>
<ul>
<li><code>groff</code> (using <code>-V</code>)</li>
<li><code>xrandr</code> (using <code>--dryrun</code>)</li>
<li><code>tarsnap</code></li>
<li><code>ssh-copy-id</code> (using <code>-n</code>) </li>
</ul>
<p>— and countless others support dry-run functionality. </p>
<p>Read the docs and do dry runs.</p>
<p>[end]</p>Basic Interaction with Man-pages2014-11-03T23:31:00-05:00David Prager Brannertag:https://dpb.bitbucket.io,2014-11-03:basic-interaction-with-man-pages.html<p>A “man-page” is a piece of on-line documentation for Unix programs. Normally every program available on the command line has one, and it is accessed by typing <code>man</code> followed by the program name. If we want to read the page for the <code>bash</code> shell, we enter:</p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">bash</span>
</pre></div>
<p>Below are five practical topics connected with man-pages.</p>
<h2>1. Navigation and searching within a man-page</h2>
<p>Man-pages are displayed in the terminal by way of a “pager”, usually a program such as <code>less</code> that has search and other navigation functionality. The most immediately useful commands in <code>less</code> are</p>
<p><strong>navigation</strong>:</p>
<ul>
<li><code>q</code> : quit</li>
<li><code>u</code> : page up</li>
<li><code>d</code> : page down</li>
<li><code>g</code> : to top of document</li>
<li><code>G</code> : to bottom of document</li>
</ul>
<p><strong>searching</strong>:</p>
<ul>
<li><code>/</code> : incremental forward-search</li>
<li><code>?</code> : incremental backward-search</li>
<li><code>n</code> : find next in the original direction</li>
<li><code>N</code> : find next in the opposite direction</li>
</ul>
<h2>2. Dealing with multiple pages for the same program</h2>
<p>By default <code>man</code> returns only the first page it finds with a given name; you can open all that are found, in sequence, using the <code>-a</code> option. But I prefer first to get a listing of all pages found, by location in the file-system, and then choose the one or ones I want.</p>
<p>Not all man-pages are found in the same place; the location of a given page can be requested using option <code>-w</code> (mnemonic as “where”; equivalent to <code>--path</code>). Combine <code>-w</code> and <code>-a</code> to return the locations of all pages with a given name:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">man</span> <span class="o">-</span><span class="n">aw</span> <span class="n">groff</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">man</span><span class="o">/</span><span class="n">man1</span><span class="o">/</span><span class="n">groff</span><span class="mf">.1</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">man</span><span class="o">/</span><span class="n">man7</span><span class="o">/</span><span class="n">groff</span><span class="mf">.7</span>
</pre></div>
<p>The numbers at the end of these filenames are the “section” numbers in the overall man-page collection. The manual sections mostly likely to be used by ordinary programmers are 1 (executable shell commands) and 7 (miscellaneous). You can specify which sections you want with the <code>-S</code> option, followed by one or more (colon-separated) section numbers. So on (Ubuntu and Darwin, at least) either of the following</p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">groff</span> <span class="o">-</span><span class="n">S</span> <span class="mi">1</span>
<span class="n">man</span> <span class="o">-</span><span class="n">S</span> <span class="mi">1</span> <span class="n">groff</span>
</pre></div>
<p>will bring up the first of the files listed above, labelled <code>GROFF(1)</code>, while </p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">groff</span> <span class="o">-</span><span class="n">S</span> <span class="mi">7</span>
<span class="n">man</span> <span class="o">-</span><span class="n">S</span> <span class="mi">7</span> <span class="n">groff</span>
</pre></div>
<p>will bring up <code>GROFF(7)</code>. </p>
<h2>3. Searching for relevant man-pages</h2>
<p>Option <code>-k</code> (or <code>--apropos</code>) will search the one-line descriptions in the NAME section of all man-pages for some string. The output is the same as that of the <code>apropos</code> command:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">man</span> <span class="o">-</span><span class="n">k</span> <span class="n">markdown</span>
<span class="n">pandoc_markdown</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="o">-</span> <span class="n">markdown</span> <span class="n">syntax</span> <span class="k">for</span> <span class="n">pandoc</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
<p>Option <code>-K</code> will search the full content of all man-pages for a given string, always giving you the option of opening each page, as found, or quitting before continuing the search. Below is an example of searching for pages containing “markdown” — the letter <code>n</code> at the end of each line is my response to the program’s request as to how to proceed:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">man</span> <span class="o">-</span><span class="n">K</span> <span class="n">markdown</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">man</span><span class="o">/</span><span class="n">man1</span><span class="o">/</span><span class="n">pandoc</span><span class="o">-</span><span class="n">citeproc</span><span class="mf">.1</span><span class="o">?</span> <span class="p">[</span><span class="n">ynq</span><span class="p">]</span> <span class="n">n</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">man</span><span class="o">/</span><span class="n">man1</span><span class="o">/</span><span class="n">pandoc</span><span class="mf">.1</span><span class="o">?</span> <span class="p">[</span><span class="n">ynq</span><span class="p">]</span> <span class="n">n</span>
<span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">man</span><span class="o">/</span><span class="n">man5</span><span class="o">/</span><span class="n">pandoc_markdown</span><span class="mf">.5</span><span class="o">?</span> <span class="p">[</span><span class="n">ynq</span><span class="p">]</span> <span class="n">n</span>
</pre></div>
<p>This can be a long procedure (any pages compressed with <code>gzip</code> are being decompressed and searched) so it is useful to restrict the search domain to some subset of sections, using option <code>-S</code>. Also, be aware that if spacing within a desired phrase varies in different man-pages, or if it is hyphenated or spread over more than one line, not all the desired output may actually be found.</p>
<h2>4. The internal format of a man-page</h2>
<p>Man-pages are natively formatted using <code>roff</code>, a kind of markup dating from the 1960s and modelled on linotype practices. There is a résumé of the history of this protocol in the man-page for <code>roff</code>, whose name is a reduction of the name of an older program, <code>runoff</code>; <code>runoff</code> itself comes from the ordinary English “run off”, to reproduce a document mechanically. </p>
<p>The <code>roff</code> family of programs (mainly <code>troff</code> [“typesetter <code>roff</code>”], <code>nroff</code> [“new <code>roff</code>”] and <code>groff</code> [“GNU <code>roff</code>”]) rely on a pipeline of preprocessor, formatter, post-processor, and an output “device” or “target”. The markup protocol itself is well documented, though it may not be of much interest to the casual user. Its two most distinctive features are</p>
<ul>
<li>“requests”, prefixed by <code>.</code> and occupying a full line; generally having higher-level functionality;</li>
<li>“commands”, prefixed by <code>\</code>; generally producing or affecting sequences of characters.</li>
</ul>
<p>These give it a fairly archaic look by contemporary standards of markup. Here are a few lines from the <code>bash.1</code> man-page:</p>
<div class="highlight"><pre><span class="p">...</span>
<span class="p">.</span><span class="n">SH</span> <span class="n">DESCRIPTION</span>
<span class="p">.</span><span class="n">B</span> <span class="n">Bash</span>
<span class="n">is</span> <span class="n">an</span> <span class="err">\</span><span class="n">fBsh</span><span class="err">\</span><span class="n">fR</span><span class="o">-</span><span class="n">compatible</span> <span class="n">command</span> <span class="n">language</span> <span class="n">interpreter</span> <span class="n">that</span>
<span class="n">executes</span> <span class="n">commands</span> <span class="n">read</span> <span class="n">from</span> <span class="n">the</span> <span class="n">standard</span> <span class="n">input</span> <span class="n">or</span> <span class="n">from</span> <span class="n">a</span> <span class="n">file</span><span class="p">.</span>
<span class="p">.</span><span class="n">B</span> <span class="n">Bash</span>
<span class="n">also</span> <span class="n">incorporates</span> <span class="n">useful</span> <span class="n">features</span> <span class="n">from</span> <span class="n">the</span> <span class="err">\</span><span class="n">fIKorn</span><span class="err">\</span><span class="n">fP</span> <span class="n">and</span> <span class="err">\</span><span class="n">fIC</span><span class="err">\</span><span class="n">fP</span>
<span class="n">shells</span> <span class="p">(</span><span class="err">\</span><span class="n">fBksh</span><span class="err">\</span><span class="n">fP</span> <span class="n">and</span> <span class="err">\</span><span class="n">fBcsh</span><span class="err">\</span><span class="n">fP</span><span class="p">).</span>
<span class="p">.</span><span class="n">PP</span>
<span class="p">...</span>
<span class="p">.</span><span class="n">PD</span> <span class="mi">0</span>
<span class="p">.</span><span class="n">TP</span> <span class="mi">10</span>
<span class="p">.</span><span class="n">BI</span> <span class="err">\</span><span class="o">-</span><span class="n">c</span> <span class="s">"\| string\^"</span>
<span class="n">If</span> <span class="n">the</span>
<span class="p">.</span><span class="n">B</span> <span class="err">\</span><span class="o">-</span><span class="n">c</span>
<span class="n">option</span> <span class="n">is</span> <span class="n">present</span><span class="p">,</span> <span class="n">then</span> <span class="n">commands</span> <span class="n">are</span> <span class="n">read</span> <span class="n">from</span>
<span class="p">.</span><span class="n">IR</span> <span class="n">string</span> <span class="p">.</span>
<span class="n">If</span> <span class="n">there</span> <span class="n">are</span> <span class="n">arguments</span> <span class="n">after</span> <span class="n">the</span>
<span class="p">.</span><span class="n">IR</span> <span class="n">string</span> <span class="p">,</span>
<span class="n">they</span> <span class="n">are</span> <span class="n">assigned</span> <span class="n">to</span> <span class="n">the</span> <span class="n">positional</span> <span class="n">parameters</span><span class="p">,</span> <span class="n">starting</span> <span class="n">with</span>
<span class="p">.</span><span class="n">BR</span> <span class="err">$</span><span class="mi">0</span> <span class="p">.</span>
<span class="p">.</span><span class="n">TP</span>
<span class="p">...</span>
</pre></div>
<p>See the <code>groff_diff</code> man-page for a comprehensive discussion of the rules.</p>
<h2>5. Accessing man-pages outside of the terminal window</h2>
<p>A man-page is normally read within the terminal window where it is displayed by <code>man</code>. But there are other options.</p>
<h3>5a. As text files</h3>
<p>Formatting by <code>man</code> for <code>stdout</code> is hard to read when not processed by a terminal device interface. Exporting directly to a text file, say using the man-page for <code>bash</code> itself, as</p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">bash</span> <span class="o">></span> <span class="n">bash_man_page</span><span class="p">.</span><span class="n">txt</span>
</pre></div>
<p>produces messiness wherever boldface and other character-formatting is in use. Instead, pipe <code>man</code> output through the <code>col</code> or <code>colcrt</code> programs, the former with option <code>-b</code> (“eliminate backspacing”):</p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">bash</span> <span class="o">|</span> <span class="n">col</span> <span class="o">-</span><span class="n">b</span> <span class="o">></span> <span class="n">bash_man_page</span><span class="p">.</span><span class="n">txt</span>
</pre></div>
<p>or</p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">bash</span> <span class="o">|</span> <span class="n">colcrt</span> <span class="o">></span> <span class="n">bash_man_page</span><span class="p">.</span><span class="n">txt</span>
</pre></div>
<p>(The name <code>col</code> appears to derive from “column”, but the program has functionality not limited to columnization and the name perhaps condenses “correct output lines”; its man-page declares its function to be “filter reverse line feeds from input.” The name <code>colcrt</code> is a variety of <code>col</code> originally intended for use with CRT terminals. The two programs produce slightly different output: <code>col</code> uses tabs, while <code>colcrt</code> uses only spaces.)</p>
<h3>5b. As PostScript</h3>
<p>A man-page can also be converted to PostScript and read with any PS-reader — most PDF readers will read PostScript without trouble. Use </p>
<div class="highlight"><pre><span class="n">man</span> <span class="o">-</span><span class="n">t</span> <span class="n">bash</span> <span class="o">></span> <span class="n">bash_man_page</span><span class="p">.</span><span class="n">ps</span>
</pre></div>
<p>Option <code>-t</code> runs <code>groff -Tps -mandoc</code>, meaning take the output “target” to be PostScript and then use a macro package appropriate to whichever man-page format is found. Program <code>man</code> itself outputs to <code>stdout</code> by default; you can pipe that output to your PS-reader. On the current Mac operating system (Darwin v. 13.4) the full command would be</p>
<div class="highlight"><pre><span class="n">man</span> <span class="o">-</span><span class="n">t</span> <span class="n">bash</span> <span class="o">|</span> <span class="n">open</span> <span class="o">-</span><span class="n">fa</span> <span class="o">/</span><span class="n">Applications</span><span class="o">/</span><span class="n">Preview</span><span class="p">.</span><span class="n">app</span>
</pre></div>
<p>although Ghostscript, <code>gv</code>, Acrobat Reader, and many other tools are also available as the direct objects of <code>open</code>. There is another program <code>pdfroff</code> for converting man-pages to PDF, but I have not been able to get the output to look right and simply use PostScript pages, instead.</p>
<h3>5c. As HTML</h3>
<p>There is a program <code>man2html</code> that generates HTML easily from man-pages:</p>
<div class="highlight"><pre><span class="n">man</span> <span class="n">bash</span> <span class="o">|</span> <span class="n">man2html</span> <span class="o">></span> <span class="n">bash_man_page</span><span class="p">.</span><span class="n">html</span>
</pre></div>
<p>[end]</p>