Poema Papi

From the shadow of struggling with cancer, a poem from my dad.



SONRIENTE
Renace la esperanza y con ella la vida
El futuro abre sus puertas
Y el ensombrecido día ahora es brillante
Sus colores dilatan mis pupilas y al horizonte veo más grande
Brillante luz del día que me acoge
Luego de salir de esta agonía

A vivir me invita y como canto de sirena me seduce
Los sueños renacen y con ellos la vida
Soy el mismo pero reformado a positivo

Y aun cuando la vida como compañero a la muerte tiene, las dos son al camino
Por hoy he variado la ruta y no me alcanzaste
Vivo consciente de la vida y de la muerte y ninguna me detiene
Las he visto de cerca y me apresto a vivir
Vivir con su magia me sostiene
Mejor un día de vida que mil esperando por ella.

Cerca la hoz de mi cuello estuvo y por ella la progresión del camino he visto
Salgo a la calle y vivo como sólo el otro lado la observa
La fantasía de la vida es el camino y sé que un día tocará a su fin
Pero a cada amanecer una sonrisa le trae
Y a cada atardecer en sus colores se solaza
Los días por si solos no son buenos, es la alegría interna la que la delata

Muerte, sé que estás ahí y te he visto
Y me has mirado fijamente
Pero, para cuando me toque,
Me encontrarás sonriente.
                                      
Israel Ginez
2025-05-08

Quantum Circuits

One of the nicest properties of quantum computing circuits is the fact that you can achieve the same goal with a fewer number of steps compared to classical computer, and it has been a lot of fun for me to discover how to implement such algorithms.

I wanted to write about an algorithm I spent some time thinking about and wrestling with. This particular quantum circuit does not provide an improvement over a classical one (there are algorithms tacking similar problems that ac tually do provide speed-ups), but it was really nice to see how to solve a problem using quantum thinking as opposed to classical thinking.

The problem consist of coming up with an algorithm to learn the bits of a hidden string s. For this problem we restrict the string s to be a string of 0 and 1, e.g.: 100110

The classical algorithm is quite simple. It can be summarized as follows: test every bit of the string with the and operation and a 1, if the result is 1 then the bit is a 1 otherwise the bit is a 0.

To solve this problem using quantum computing I decided to break the algorithm into two parts. The first part will encode a unitary function whose main purpouse is some information from any secret string. The second part of the algorithm consists in preparing a state that represents all the possible states of a binary string s of size n. The first part of the algorith is called an oracle.

The oracle

As mentioned before, the first part of the problems boils down to finding a quantum circuit that can be used to extract information from any string s. By doing some exploration and due to previous experinece I had on similar problems I settled on the oracle that is would basically calculate the sum mod 2 of $x_i$ * $s_i$ where $x_i$ is the ith bit of an arbitrary string x and $s_i$ is the ith bit of the hidden string s. Or in other words:

$$ (\sum_{i=0}^{n}s_i * x_i)\ mod\ 2 $$

The above is equivalent to calculating the parity of s when x equals to 111...1. Next, then is the problem of coming up with an algorithm that encodes the above unitary, here I did testing of different circuits looking for patterns, starting with smaller strings allowed me to find patters in the circuits. For example the circuit for the string 101 looks like this:

sc2

The pattern I found was basically CNOTing all the 1 bits of the secret string. Thus, I coded up a function whose input is an arbitrary string s and the output is a quantum circuit that encodes the above unitary for the input string s. The width of the circuit varies grows linearly with the length of s(which is not great), and the number of gates grows linearly with the number of 1 in s, they are all CNOT gates which is implemented in most quantum hardware. Further there are no operations between the input qubits, only between the inputs and output qubit.

sc3

The search circuit

The world of quantum computing revolves around designing a circuit that creates an interesting superposition state, that can later be exploited to process a particular computation. One common technique to do is to create the super position where all possible states in a quantum register have equal measuring probability, this state is called the uniform superposition. For example in a 2 qubit register the uniform super position would be the state:

$$ \psi = \frac{1}{4}(|00> + |01> + |10> + |11>) $$

More generally the uniform super position of an n-qubit register is:

$$ \psi = \frac{1}{\sqrt{2^n}}\sum_{0}^{2^n-1}|x> $$

Such a circuit can be created via hadamard gates applied to each of the input qubits for a quantum register set to 0

The final circuit

By combining both parts we get the final circuit.

At the end of the circuit we apply hadamards to finalize the search circuit and read the measurement to classical bits.

sc4

The circuit is initialized with the state |0> plus an ancilla qubit set to |1> which helps us encode the oracle unitary and the uniform superposition. Notice the circuit labelled search circ is actually built for the hidden string s and it varies depending on s.

Finally when running the circuit we should expect to read back the hidden string s in the classical bits. Interestingly we only need to run this circuit one time to properly discover the string s. Recall the classical algorithm needs to iterate through each of the bits in the string s in order to discover s.

sc5

For the complete code, feel free to look at this repository which contains a runnable notebook you can play with.

On change

In a short couple of days I will be starting graduate school in the Netherlands and as with every big move I have done in my life, there are always uncertainties, anxieties but also expectations.

I decided to trade a well compensated position in technology for university life and even though I have spent time evaluating, thinking and preparing for this, ultimately one can never know how something will turn out for the best, all we can do is try our hardest.

I love thinking about sailing and life. Anyone who has sailed will recognize the skipper nor the crew have full control of the ship. All they can do is adjust the rudder, tighten the sails point in the desired direction, after that, it is impossible to tell which way the wind will blow. All a sailor can do is be in tune to the changes in the weather and adjust the vessel accordingly. Life, I believe, is much like sailing, one chooses a worthy goal, and then works with the winds of life to take you there, hopefully enjoying the detours along the way.

I started thinking about a change in my life a number of years ago while I noticed a certain level of dissatisfaction in different jobs I held. Though most of the time it was due to the typical characteristics of a corporate job, many times my responsibilities at work never aligned with what I perceive are the needs of our current society. That bothered me the most because I believe my skills and my time are my main contributions to society. Ultimately, society compensates human beings based on demand and not on what is actually net good for society. Expecting to have a job that completely aligns with my values and is also profitable is a bit of an illusion, nor am I wealthy enough to completely disregard the need for a job that provides for me and my family. I am, however, curious enough to keep exploring alternatives that will balance these forces in my life.

Lately I have thoroughly enjoyed discovering and reading about the field of quantum computing, and more importantly I have been inspired to be a participant in the field because I believe there is an opportunity to improve human society. I believe in this space I can have a greater probability for meaningful impact to society (of course there is a real chance the field stalls or even fails, but exploring dead ends still brings value to society). Moreover, if the field is going to see progress, it needs to build on the lessons of scaling classical computing and attract people from diverse backgrounds and experiences; people willing to learn about this field but that can also leverage their experience to move it forward.

My personality, I have come to learn, draws a lot of satisfaction from learning. Probably why moving and living in different parts of the world has been part of my life, and is currently one of the big motivators in pursuing this opportunity outside of my current community. I find living in a different culture very rewarding as it gives me the chance to witness how other people solve problems, how other societies organize themselves (for the benefit or detriment of its members), how other communities enjoy and celebrate life. These are the experiences that have enriched my life in the past, that have inspired me to be a better human being.

Everything in life has trade offs and pursuing this goal comes with a fair share of them. The biggest trade off being the separation from my community. I often think that the roots are to a tree what a community is to a person. The roots keep a tree nourished and grounded. And find that losing contact with one’s community (if only temporarily) is painful.

Another difficult part of this change has been the delay of other goals my wife and I have been planning and working towards. Indeed this change is different from the others I have done in the past because now I have someone to share this new season with, but also there is another life making sacrifices and going through the ups and downs of being a foreigner. I count myself lucky to have someone by my side who shares my values and is willing to step into the unknown with me.

And isn’t this one of the ways we are called to live life? To point our boat towards a new port and enjoy as much as one can of the journey there.

Building the Q# compiler in mac os

Earlier this year Microsoft open sourced a number of their quantum programming tools including the compiler for the qsharp(q#) quantum programming language. I really enjoy reading and learning from open source software, so the news were really exciting for me since it allowed to look at the internals of qsharp.

The following post summarizes some of my experiences working and building the qsharp compiler code base as member of the open source comunity.

My main dev environment is macOS so lots of the instructions here will be targeted for it, however if your are running a *nix environment is pretty much same.

Prerequisites

Here is the list of things you are going to need to build the qsharp compiler.

  • Dotnet

    $> dotnet --version
    3.0.101
    
  • Power shell

    $> brew cask install powershell
    ...
    $> pwsh --version
    PowerShell 6.2.3
    
  • Qsharp’s source code

    $> git clone https://github.com/microsoft/qsharp-compiler.git
    
  • bsondump and jq To visualize the compiler output. I found it surprinsing that there was no easy way to install a bson->json converter so I decided to build a mongodb tool from the source above (FYI you’ll need the go tool chain for that)

  • A text editor of your choice. Here life starts getting a little complicated for macOS users. Vim, usually my editor of choice, sadly struggled to support symbolic navigation, specially cross-project. Visual Studio Code, fine choice for most projects, and an excellent choice for C# projects, did not have a good F# plugin. I settled for Visual Studio for macOS, even though it lacks some pretty key text editor plugins (vim style emulation, for example). On the plus side I found that Visual Studio offered the best experience when navigating a mix C#, F# code base.

Building

  • Move to your the qsharpcompiler repository and execute the boostraping script
$> cd qsharp-compiler
$> pwsh bootstrap.ps1
...
Enable telemetry: false
Adding Newtonsoft.Json.Bson
Adding Microsoft.VisualStudio.LanguageServer.Protocol
Adding FSharp.Core
Adding System.ValueTuple
Adding Newtonsoft.Json
Adding System.Collections.Immutable
Adding Markdig
Adding YamlDotNet
Adding FParsec
Adding Microsoft.CodeAnalysis.CSharp

dependency
----------
{dependency, dependency, dependency, dependency…}
  • Build the compiler project
$> dotnet build QsCompiler.sln
Microsoft (R) Build Engine version 16.3.2+e481bbf88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
....

Make sure you have sync’d your repo with the lastest qsharp repository. I fixed a few minor issues with the build script in macOS and they relatively new commits.

If everything worked fine, you now should be able to call the qsharp compiler from its command line tool.

$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc
Microsoft Q# compiler command line tool. 1.0.0
© Microsoft Corporation. All rights reserved.

ERROR(S):
  No verb selected.

  build       Builds a compilation unit to run on the Q# quantum simulation framework.

  diagnose    Generates intermediate representations of the code to help diagnose issues.

  format      Generates formatted Q# code.

  help        Display more information on a specific command.

  version     Display version information.

$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc version
Microsoft Q# compiler command line tool. 1.0.0

Running it

With a built compiler we are ready to take for a spin. The command line tool of the qsharp compiler, provides a few options to specify input. For example we can pass a snippet of q# code like so:

$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc build -s "var uf = 2;"

Error QS3034:
File: /Users/eginez/repos/qsc/__CODE_SNIPPET__.qs
Position: [ln 1, cn 5]
Unexpected code fragment.

Error QS3035:
File: /Users/eginez/repos/qsc/__CODE_SNIPPET__.qs
Position: [ln 1, cn 1]
An expression used as a statement must be a call expression.

____________________________________________

Q# compilation failed: 2 errors, 0 warnings


$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc build -s "mutable uf = 2;"
____________________________________________

Q#: Success! (0 errors, 0 warnings)

Of course you probably want to save the source code to a file and pass that file to the compiler, for that you can do

$> cat sample.qs
namespace blank {
        operation OneQ () : Unit {
        using(q = Qubit()) {
        }
    }
}
$> src/QsCompiler/CommandLineTool/bin/Debug/netcoreapp3.0/qsc build -i sample.qs -o out/
____________________________________________

Q#: Success! (0 errors, 0 warnings)

$>ls out
twnlm5ty.bson twnlm5ty.dll

The output of the compiler is both a bson file and dll with the bson in it. Finally you can look at the output of the compiler with the bsondump tools

$> $GOPATH/mongodb/mongo-tools/bin/bsondump twnlm5ty.bson|jq
...
"Statements": [
                          {
                            "Statement": {
                              "Case": "QsQubitScope",
                              "Fields": [
                                {
                                  "Kind": {
                                    "Case": "Allocate"
                                  },
                                  "Binding": {
                                    "Kind": {
                                      "Case": "ImmutableBinding"
                                    },
                                    "Lhs": {
                                      "Case": "VariableName",
                                      "Fields": [
                                        "q"
                                      ]
                                    },
                                    "Rhs": {
                                      "Case": "SingleQubitAllocation"
                                    }
                                  },
                                  "Body": {
                                    "Statements": [],
                                    "KnownSymbols": {
                                      "Variables": [
                                        {
                                          "VariableName": "q",
                                          "Type": {
                                            "Case": "Qubit"
                                          },
                                          "InferredInformation": {
                                            "IsMutable": false,
                                            "HasLocalQuantumDependency": false
                                          },
                                          "Position": {
                                            "Case": "Value",
                                            "Fields": [
                                              {
                                                "Item1": {
                                                  "$numberInt": "1"
                                                },
                                                "Item2": {
                                                  "$numberInt": "8"
                                                }
                                              }
                                            ]
                                          },
                                          "Range": {
                                            "Item1": {
                                              "Line": {
                                                "$numberInt": "1"
                                              },
                                              "Column": {
                                                "$numberInt": "7"
                                              }
                                            },
                                            "Item2": {
                                              "Line": {
                                                "$numberInt": "1"
                                              },
                                              "Column": {
                                                "$numberInt": "8"
                                              }
                                            }
                                          }
                                        }
                                      ],
....

As you can see the compiler outputs the whole AST and metadata in json format.

The compiler code itself is split into a number of packages, some interesting packages to look at are: Optimizations, SyntaxProcessor, Compilation Manager. In addition the compiler project has a number of targets, for example: CommandLineTool, LanguageServer and the Tests targets. The CommandLineTool and the Test targets are the most relevent and as we saw built with no problems, the Test target still has a build problem on macOS I haven’t tracked down yet.

Poemientos

I am many years old, I am trying to figure out this thing He calls man.

I dream to much and I don’t hustle enough. They tell me work to work for towers don’t build themselves and all gardens now grow arulladas by the glow of monitors and clicking of keyboards.

I dream to much and I don’t bike enough. Just pedal down and up, and down and up. I look behind making sure the trees I ride past every day are not tired of me yet. I look upwards hoping my tires were were filled with day-dreams and not air, and for a moment they are. I look in where the weather is unpredictable, my private maze of wires and poets. I look around, and it is all there, an encyclopedia bookmarked at busy-mess. I look to my feet … and down and up and down and up. Sin subidas, sin bajadas, just pedal down and pedal up. I look forward…When do I get there?… When do I get where?…

I am trying to figure out this thing that He calls “man”.


On my grandpa passing away

Hola abue subiendo las escaleras….

Jaque mate
no te fijaste en mi caballo

Anda nada no mas no te va a pasar nada … no abue tengo miedo del lado profundo de la piscina

No te acerques tanto a la chimenea, que puse nueva lena pero me gusta ver el fuego abue,

Ven a oir esta musica bonita como se llama abue … Tchaikovsky

Quieres mas higos? bueno abue

Quiero que sepas que yo te aprecio mucho por que me dice eso abue?, yo siempre he sabido que ud me aprecia

Abres en 1,2,3 …. Cierras … 1,2,3 no puedo ver mis dedos, no se que tecla estoy aplastando abue

Has leeido tu biblia?

Alma, mente y espiritu tiene el ser humano, no te olvides de alimentar a las 3 que?, no le entiendo abue…

Alma, mente y espiritu tiene el ser humano es verdad abue

‘Ciertamente el bien y la misericordia me seguiran todos los dias de mi vida y en la casa del Seno morare por largos dias’ Descansa en paz abue


Entre suenos te pense, y dos veces dude mientras la gente ocupada murmura quien es tal criatura

Some calculus fun

On one of my commutes home a couple of days ago I had for whatever reason the desire to calculate to the circumference of a circle using calculus. The idea was to calcute the lenght of the base of a triagle whose sides are the radius, summing all those distances as they wrap a circle. As the angle between the two sides of the triangle of lenght $r$ tends to 0, the sum of the bases should equal the circumference of the circle . If we know that the radius of a cirlce is $r$. By the law of cosines we know that the side $x$ is equal to $\sqrt{r^2+r^2-2r^2\cos(\theta)}$. Simplifying we get $$ x = r\sqrt{2-2\cos(\theta)}$$ The equation above as is is still a bit hard to work with so after some searching and remembering trigonometric identities. $$ \sqrt{\frac{1 - \cos(\theta)}{2}} = \sin(\theta/2) $$ Then $$ \frac{x}{2} = r \sqrt{\frac{2 - 2\cos(\theta)}{4}} $$ $$ x = 2r \sqrt{\frac{1 - \cos(\theta)}{2}} $$ $$ x = 2r\sin(\frac{\theta}{2}) $$

The above expression is way easier to reason about and work with. Also noticed I already have some of the terms that I am looking for, namely $2 r$. Now with the above function we can imagine that as the angle $\theta$ approaches 0 the value of the sum of all x(arounde the circle) approaches the circumference $C$ for a circle or radius $r$. Since all $x$ are the same size we can multiply by $2\pi/\theta$. Then $$ C = \lim_{\theta\to0}\frac{2\pi}{\theta} 2r\sin(\theta/2) $$ $$ C = \lim_{\theta\to0}4\pi r \frac{\sin(\theta/2)}{\theta} $$ $$ C = 4\pi r \lim_{\theta\to0}\frac{\sin(\theta/2)}{\theta} $$

So the problem now boils down to calculating $\lim_{\theta\to0}\frac{\sin(\theta/2)}{\theta}$. Given that we have a division by 0, it is not super straighfoward to calculate the limit, but easy enough using other rules. Such $$ \lim_{x \rightarrow a} \frac{f(x)}{g(x)} = \lim_{x \rightarrow a} \frac{f’(x)}{g’(x)} $$ $$ \lim_{\theta\to0} \frac{\sin(\theta/2)}{\theta} =\lim_{\theta\to0} \frac{1}{2}\frac{\cos(\theta/2)}{1} $$ $$ \lim_{\theta\to0} \frac{\sin(\theta/2)}{\theta} = \frac{1}{2} \cos(0) = \frac{1}{2} $$

Finally: $$ C = 4 \pi r \frac{1}{2}$$ $$ C = 2 \pi r $$

On culture and human relationships

This is a recollection of some of my experiences as I started living in the western part of Canada. I especially want to write down my thoughts on how people relate to each other in the different places I have lived.

Sometimes people ask me what I miss the most about my birth place, and without a doubt it is the way humans interact. In fact human interactions here still feel foreign to me.

One of the most surprising things to me when I first rode Calgary’s transit system was the silence, and to this day I still think it is remarkable that a group of human beings manage to stay quite for a good period of time. In some parts of the world, the sounds of chatter and the blasting radio would fill the bus. Being from a different culture, I tried many times to break the norm and start conversations with fellow passengers but more often than not the response was apathetic at best. Eventually I gave up and did as I observed, that is, immersed myself in some reading, podcast, or whatever else would distract my attention. Though I did manage to strike a few spontaneous conversations that made my commute more enjoyable. I still find it strange that two people who routinely find themselves in a common place would choose not to interact with each other. Or, even worse, choose not to acknowledge each other. That is exactly what made transit very foreign to me- people actively choosing to avoid interactions.

Many months ago I read of a study that had crawled the “miss connections” section of craiglist.com for different cities in the United States and catalogued the most common locations for such events. Buses and trains made the list. I guess it makes sense especially for transit heavy cities (Seattle, San Francisco, NYC for example). Could it be that people want to connect to each other but they feel is not appropriate?

In Calgary, I once went to a house party that I was mildly interested in. I found myself bored after I had exhausted talking to everyone I knew at the party, and I decided to leave. On my drive home I started to wonder why it felt strange for me to drive home early from a party, it isn’t like I never attended boring parties before back home, so what was it? Well one of the things I quickly realized is that when I was in Quito I rarely drove to parties, not only that, if I did it was generally in a carpool with friends. Thus very frequently, when I felt bored at parties I had no alternative but to wait until everyone whom I came with felt ready to go. Sometimes this meant that I was stuck in a place I did not want to be. This however had the positive side effect that it pushed me to talk to people I did not know. But not only that, there was a good chance that other people were in the same situation making a chunk of the attendees pretty receptive to these type of encounters, many times turning a dull night into a memorable one.

I realized that night, as I drove alone, that resource limitations can lead to practices that strengthen communities. Further I believe the opposite is also true, that an abundance of resources makes it harder for people to connect and erodes our opportunities to create new relationships. I am not suggesting we should give up individual possessions and live in communes, but we should be suspicious of world views that preach society betterment through self-sufficiency and accumulation.

Finally I would like to describe a behavior, that has been hard for me to adapt to and to this day it still feels foreign. Many times in the past I have been introduced to new people in a social gathering, and after a meaningful interaction we both part ways. After a short period of time goes by and I encounter the same person somewhere else, it would be very likely that he or she will make no effort to acknowledge me, or worse actively avoid me. What is even more surprising is that this behavior will happen even with people that I have interacted with on multiple occasions. The first times I encountered this behavior I wondered if the person did not see or remember me. Many times I assumed he or she was intentionally avoiding a friendship with me, but I quickly realized that this was not necessarily the case. If I found them in a setting similar to the one in which we had met, most people behaved friendly towards me.

It took me several years to realize that people regulate their receptiveness to a social interaction based on the physical place they find themselves in. Incidentally this “regulation” is highly dependent on their mother culture. For example, back home, failing to approach a person that was introduced to me recently, regardless of where I found him or her, would be considered rude, as would arriving at a small gathering and not acknowledging everyone individually.

Why does it feel more out of place to start a conversation while waiting for the bus than at a conference? There is no single answer to that, as it depends on many things. What I keep wondering is if our reliance on self-reliance robs us of opportunities to develop meaningful connections.

Error handling in golang, an experience report

In the spirit of contributing to the golang community, I would like to document my experience while trying to make error handling a little more palatable.

Error handling sits high among the things that I would like to do better in go, thus while working on a recent project I decided to invest some time looking into how to improve.

I’ll start by showing code snippets of what I thought could have been improved:

//Loads the data structures
func Load(root string, keyRing string, p pgp.PromptFunction) (index *MeerkatsIndex, key *MeerkatsKeys, e error) {

	//Load keys
	index = &MeerkatsIndex{}
	key = &MeerkatsKeys{}
	fr, e := os.OpenFile(filepath.Join(root, ".keys"), os.O_RDWR, os.FileMode(0700))
	e = key.Read(fr)
	if e != nil {
		return
	}

	//Load index
	fr, e = os.OpenFile(filepath.Join(root, ".index"), os.O_RDWR, os.FileMode(0700))
	if e != nil {
		return
	}
	ent, entList, e := LoadKeysFromDisk(keyRing, p, key)
	if e != nil {
		return
	}

	e = index.Read(fr, ent, entList)
	return
}

That is a short of example showcasing something pretty obvious: there is a lot repetitive error handling pretty much doing the same thing. My first intuition was to replace all the error checking statements with a function that would check for the status of an error variable and then just panic.

//check for errors
func logAndExitIfError(e error) {
	if e != nil {
		panic(e)
	}
}

func EncryptPipeline(to pgp.EntityList, from *pgp.Entity, secret []byte) (encbytes []byte, e error) {
	e = nil
	plain := bytes.NewBuffer(nil)
	zipped := gzip.NewWriter(plain)
	armored, e := armor.Encode(zipped, "PGP MESSAGE", nil)
	logAndExitIfError(e)
	encrypted, e := pgp.Encrypt(armored, to, from, nil, nil)
	logAndExitIfError(e)

	_, e = encrypted.Write(secret)
	logAndExitIfError(e)
	//...
}

That works pretty well if all I want to do is exit the program, but for the cases where I needed more than just exiting, this technique does not work.

Still unsatisfied with the state of affairs I went looking for answers in the internet. I started by looking at other people’s code too see how they have been solving the same problem. Surprisingly, I found that the vast majority of projects I looked into were basically if-checking on every error.

That seems less than ideal to me. And as far as I can tell it is a source of complaint amongst gophers. So much so that Rob Pike himself wrote a [post] (https://blog.golang.org/errors-are-values) on this specific topic a couple of years ago. In it, he describes a clever technique to deal with errors. He makes the point that errors should be treated as values (which they should) and goes on to provide an example on how to program around errors. I won’t describe his whole solution however I’d like to highlight a key part of his example. Consider the following interface and function:

type errWriter struct {
    w   io.Writer
    err error
}

func (ew *errWriter) write(buf []byte) {
    if ew.err != nil {
        return
    }
    _, ew.err = ew.w.Write(buf)
}

Give the above, and as explained in Rob’s post, you could write a function to use the above solution, roughly looking like so:

...
ew := &errWriter{w: fd}
ew.write(..)
ew.write(..)

// and so on
if ew.err != nil {
    return ew.err
}

At a first glance this is great solution for the problem. The error checking logic is localized to a single function and the consumer only has to worry about checking the error when the function is about to return. However, when I tried to extend this solution to work on more than just one use case, I started running into some problems.

The first thing I noticed is that one might want to do more than just call ew.write. In fact, ideally, we should be able to handle arbitrary error throwing functions.

Closures seem like the right tool for that. Our new error check structure would like so:

type ErrorCatcher struct {
	err error
}

func (ec *ErrorCatcher) TryFile(fn func() (*os.File, error)) (ret *os.File) {
	if ec.err != nil {
		return nil
	}

	ret, ec.err = fn()
	return ret
}

Great, we now have a function called TryFile. It will execute an error throwing closure if there are no prior errors. Thus we can now can do something like this:

func possibleErrorThrowingFunction() (error) {
	erc := ErrorCatcher{}
	file1 := erc.TryFile(func() (*os.File, error) {
		return os.Open("/some/fine/file.txt")
	})

	file2 := erc.TryFile(func() (*os.File, error) {
		return os.Open("/some/fine/file.txt")
	})
    
    return erc.err
}

In the spirit of contributing to the golang community, I would like to document my experience while trying to make error handling a little more palatable.

Error handling sits high among the things that I would like to do better in go, thus while working on a recent project I decided to invest some time looking into how to optimize error checking.

I’ll start by showing code snippets of what I thought could have been improved.

//Loads the data structures
func Load(root string, keyRing string, p pgp.PromptFunction) (index *MeerkatsIndex, key *MeerkatsKeys, e error) {

	//Load keys
	index = &MeerkatsIndex{}
	key = &MeerkatsKeys{}
	fr, e := os.OpenFile(filepath.Join(root, ".keys"), os.O_RDWR, os.FileMode(0700))
	e = key.Read(fr)
	if e != nil {
		return
	}

	//Load index
	fr, e = os.OpenFile(filepath.Join(root, ".index"), os.O_RDWR, os.FileMode(0700))
	if e != nil {
		return
	}
	ent, entList, e := LoadKeysFromDisk(keyRing, p, key)
	if e != nil {
		return
	}

	e = index.Read(fr, ent, entList)
	return
}

That is a short example showcasing something obvious: there is a lot repetitive error handling doing the same thing. My first intuition was to replace all the error checking statements with a function that would check for the status of an error variable and then panic.

//check for errors
func logAndExitIfError(e error) {
	if e != nil {
		panic(e)
	}
}

func EncryptPipeline(to pgp.EntityList, from *pgp.Entity, secret []byte) (encbytes []byte, e error) {
	e = nil
	plain := bytes.NewBuffer(nil)
	zipped := gzip.NewWriter(plain)
	armored, e := armor.Encode(zipped, "PGP MESSAGE", nil)
	logAndExitIfError(e)
	encrypted, e := pgp.Encrypt(armored, to, from, nil, nil)
	logAndExitIfError(e)

	_, e = encrypted.Write(secret)
	logAndExitIfError(e)
	//...
}

That works pretty well if all I want to do is exit the program. Still unsatisfied with the state of affairs I went searching for answers in the internet. I started by looking at other people’s code too see how they have been solving the same problem. Surprisingly, I found that the vast majority of projects I looked into were basically if-checking on every error. That seems less than ideal to me.

As far as I can tell it is a source of complaint amongst gophers. So much so that Rob Pike himself wrote a [post] (https://blog.golang.org/errors-are-values) on this specific topic a couple of years ago. In it he describes a clever technique to deal with errors. He makes the point that errors should be treated as values and goes on to provide an example on how to program around errors. I won’t describe his whole solution however I’d like to highlight a key part of his example. Consider the following interface and function:

type errWriter struct {
    w   io.Writer
    err error
}

func (ew *errWriter) write(buf []byte) {
    if ew.err != nil {
        return
    }
    _, ew.err = ew.w.Write(buf)
}

As Rob’s post explains, you could write a function using the above solution, which would look something like this:

...
ew := &errWriter{w: fd}
ew.write(..)
ew.write(..)

// and so on
if ew.err != nil {
    return ew.err
}

At a first glance this is great solution for the problem. The error checking logic is localized to a single function and the consumer only has to worry about checking the error when the function is about to return. However, when I tried to extend this solution to work on more than just one use case, I started running into some problems.

The first thing I noticed is that one might want to do more than just call ew.write. In fact, ideally, we should be able to handle arbitrary error throwing functions.

Closures seem like the right tool for that. Our new error check structure would like

type ErrorCatcher struct {
	err error
}

func (ec *ErrorCatcher) TryFile(fn func() (*os.File, error)) (ret *os.File) {
	if ec.err != nil {
		return nil
	}

	ret, ec.err = fn()
	return ret
}

Great, we now have a function called TryFile. It will execute an error throwing closure if there are no prior errors. Thus we can now can do something like this:

func possibleErrorThrowingFunction() (error) {
	erc := ErrorCatcher{}
	file1 := erc.TryFile(func() (*os.File, error) {
		return os.Open("/some/fine/file.txt")
	})

	file2 := erc.TryFile(func() (*os.File, error) {
		return os.Open("/some/fine/file.txt")
	})
    
    return erc.err
}

Other than the verbosity of the closure declaration, this accomplishes what we need if all we needed to return was of type File.A common technique to generlize for a type is to use the interface{} type. Replacing the concrete type with go’s interface{} would look like this:

func (ec *ErrorCatcher) TryAny(fn func() (interface{}, error)) interface{} {
	if ec.err != nil {
		return nil
	}

	var ret interface{}
	ret, ec.err = fn()
	return ret
}

We can now utilize our error checking structure much more freely, like so:

func GetFleInfo() (info os.FileInfo, err error) {
	erc := ErrorCatcher{}
	file := erc.TryAny(func() (interface{}, error) {
		return os.Open("/some/fine/file.txt")
	}).(*os.File)

	fileInfo := erc.TryAny(func() (interface{}, error) {
		return file.Stat()
	}).(os.FileInfo)

	return fileInfo, erc.err
}

A few observations:

  • We now have to type assert the return value. This seems silly since the return type is well known in all cases (just not the same). Why can’t go let me express that!? Falling back to a type that expresses no information hardly seems like the right solution.
  • The above fragment is marginally better than the manual error checking fragment, mostly due to the typing of the closure argument but Go could infer the types of a function after all, go’s compiler can already infer variable’s types, why not function’s type? It will cut down on a lot of typing.

In my opinion, the above experience highlights the importance of generics. Having some way to express an arbitrary type is very useful when trying to express solutions to problems like the one above.

func (ec *ErrorCatcher) TryAny(fn func() (`T`, error) `generic: T` {
...
...
    return fn()
}