Posted on :: min read :: Tags: :: listen via tts

I had a recent situation where I needed to populate an existing struct with values, similar to the way json.Unmarshal works. These values would come from various sources, like URL query parameters, form data, path variables, or something along those lines.

To give an example, I needed to map a URL like /newStudent?name=Albert&age=16&city=Zurich onto a Golang struct like this:

type Student struct {
  Name       string
  AgeInYears int `json:"age"`
  City       string
}

Initially, my thought was to use what we already have in the standard library: gather all the input values into a basic map[string]string, serialize this map into JSON using json.Marshal, and then deserialize it back into the target struct.

I soon realized this approach wasn't going to work. In the example above, all the input values are string, but AgeInYears needs to be a different type. And the problems don't stop there: I also want to map path parameters from an http.Request, but there's no way to retrieve all the existing values. You can only extract path values if you already know their names.

I needed a different solution. Essentially, I had to create my own version of json.Unmarshal1. My goal was to continue using the familiar json struct tags, so fields could be renamed or skipped in a way that users already expect. Additionally, the unmarshal function needed to work independently of the data source. The primary distinction of our Unmarshal function from json.Unmarshal is that it is driven by the target struct, rather than the incoming data (i.e., JSON).

To represent the source data, we'll introduce an interface SourceValue. It will provide access to and conversion of the actual values. To support nested mapping and to treat the root value the same as any other value, everything will be considered a SourceValue. Initially, we focus on handling int and string types, along with a mechanism to retrieve child values. The interface also needs to account for scenarios where a child value doesn't exist for a given name or when the SourceValue can't be converted to the desired type, so the methods will return an error. Here's what the interface might look like:

type SourceValue interface {
  // Int returns the current value as an int64.
  // Returns error ErrInvalidType if the value can not be represented as such.
  Int() (int64, error)

  // String returns the current value as a string.
  // Returns error ErrInvalidType if the value can not be represented as such.
  String() (string, error)

  // Get returns a child value of this SourceValue if it exists.
  // Returns error ErrInvalidType if the current SourceValue does not support
  // child values. If the SourceValue does support children but is missing the
  // requested child, ErrNoValue must be returned.
  Get(key string) (SourceValue, error)
}

Given some SourceValue that accesses URL query parameters, we can now access the values from the previous example:

// get the name "Albert"
nameSource, _ := mySource.Get("name")
name, _ := nameSource.String()

// get his age
ageSource, _ := mySource.Get("age")
age, _ := ageSource.Int()

We are 80% done now, I guess. We just need to drive this by some function that walks the Student struct via reflection and performs the steps above for each field. It should also do that recursively. This is left as an exercise to the … no, let's do it!

Starting small

In Go, we can use reflection to interact with types or values at runtime. We can determine the type of a variable or access struct fields dynamically by leveraging the reflect package, the reflect.Type and the reflect.Value types.

Given a SourceValue and a value of a primitive type like string represented as target reflect.Value, we can create a function to extract the string from the SourceValue and assign it to the target value using the Value.SetString method.

func setString(source SourceValue, target reflect.Value) error {
  stringValue, err := source.String()
  if err != nil { return err }

  target.SetString(stringValue)
  return nil
}

With a bit of copy-and-paste, we can also create a setInt method that functions in much the same way. Both of those methods have the same type, let's call it setter.

// A setter sets the target to the value
// extracted from the given SourceValue
type setter func(SourceValue, reflect.Value) error

When we encounter an unknown target value's type, we can determine the appropriate setter by switching on the value's reflect.Kind. The Kind represents the underlying type of a value. For instance, in type Name string, Name is a defined type with string as its underlying type.

Let's write a setterOf method that returns either the setString or the setInt method depending on an input type ty.

func setterOf(ty reflect.Type) (setter, error) {
  switch ty.Kind() {
    case reflect.String:
      return setString, nil

    case reflect.Int, reflect.Int8, reflect.Int16, /* ... */:
      return setInt, nil

  default:
    return nil, NotSupportedError{Type: ty}
  }
}

With this we can now create a setter for string, pick the name SourceValue out of our student and call the setter with a value holding the target string.

// get a string setter
nameSetter, _ := setterOf(reflect.TypeFor[string]())

// get the SourceValue for the name of our student
nameSource, _ := studentSource.Get("name")

var name string
var nameValue = reflect.ValueOf(name)
_ = nameSetter(nameSource, nameValue)
fmt.Println(name)

A wild panic appears!

panic: reflect: reflect.Value.SetString using unaddressable value

goroutine 18 [running]:
testing.tRunner.func1.2({0x13e640, 0x400011c2b0})
  /go/src/testing/testing.go:1632 +0x1bc
testing.tRunner.func1()
  /go/src/testing/testing.go:1635 +0x334
panic({0x13e640?, 0x400011c2b0?})
  /go/src/runtime/panic.go:785 +0x124
reflect.flag.mustBeAssignableSlow(0x13e640?)
  /go/src/reflect/value.go:257 +0x74
reflect.flag.mustBeAssignable(...)
  /go/src/reflect/value.go:244
reflect.Value.SetString({0x13e640?, 0x2b5880?, 0x400011a210?}, {0x169cff, 0x6})

Nothing too bad, we just put the string directly into the value, but a reflect.Value constructed like this is not addressable, doh. Easy to fix, we just create the reflection value using a pointer to the name variable and then directly dereference it: reflect.ValueOf(&name).Elem(). That way we end up with a reflect.Value that is addressable and can be updated. This also makes a lot more sense, as we actually want the setter to update name somehow. We run again and are greeted with the expected name. Perfect!

=== RUN   TestSetter
Albert
--- PASS: TestSetter (0.00s)
PASS

Structs

I like to start at the bottom and work my way up: A simple sub problem of this is walk the Student struct. Let's start with that. Go recently introduced iterators and walking over all fields in a struct sounds a lot like a good use case for that. We start with a function that gets a reflect.Type holding the struct type we want to inspect and returns an iterator over reflect.StructFields.

func fieldsOf(ty reflect.Type) iter.Seq[reflect.StructField] {
  return func(yield func(reflect.StructField) bool) {
    // TODO

The reflect.Type gives us access to the number of fields via the NumField() int method. Looping over all field indices and calling Field(index) returns all the StructField instances in the struct, including some for private fields. Those can then be filtered out by checking IsExported(). For now, we also filter out embedded fields - that's a fun topic for later. This gives us the following loop:

for idx := range ty.NumField() {
  fi := ty.Field(idx)
  if !fi.IsExported() {
    // skip not exported field
    continue
  }

  if fi.Anonymous {
    panic("not supported")
  }

  yield(fi)
}

We can now use the fieldsOf function to iterate over all fields we want to serialize.

for fi := range fieldsOf(ty) {
  // do some magic with reflect.StructType fi
}

To proceed, we need to identify the name we'll use for lookups in the SourceValue interface for the field in question. To achieve this, let's define a nameOf function. This function takes the current fi and returns the name of the struct field, such as Name or AgeInYears.

func nameOf(fi reflect.StructField) string {
  return fi.Name
}

This approach works, but we'd like it to also respect any existing json struct tags. A json struct tag can take the form (name)?(,omitempty)?2 or - to indicate the field should be skipped. (Edgecase: a field can be named - by adding a comma behind the name -,.)

To extract the name, we simply take the portion of the tag string before the first comma.

name := fi.Name

if tag := fi.Tag.Get("json"); tag != "" {
  if tag == "-" {
    // skip this field by returning an empty name
    return ""
  }

  idx := strings.IndexByte(tag, ',')
  switch {
    case idx == -1:
      // no comma, take the full tag as name
      name = tag

    case idx > 0:
      // non empty name, take up to comma
      name = tag[:idx]
  }
}

return name

Now that this is settled, we can gather some information for each field.

We'll start by defining a field type that combines Name and Type for later use. Additionally, we'll include an Index field to identify each field within a struct, making it easier to reference later. To bring it all together, we'll implement a collectStructFields method to handle the collection process.

func collectStructFields(ty reflect.Type) []field {
  var fields []field

  for fi := range fieldsOf(ty) {
    name := nameOf(fi)
    if name == "" {
      continue
    }

    fields = append(fields, field{
      Name: name, Type: fi.Type, Index: fi.Index,
    })
  }

  return fields
}

Putting the pieces together

Let's move on to writing a function to populate each field of our Student struct.

First, we'll start by listing the assignable fields in the struct using the previously defined collectStructFields function. For each field, we'll retrieve its SourceValue using the Get(string) method. If no value is found, we simply skip that field — just like json.Marshal does. After adding some error handling, the function looks like this:

func setStudentStruct(source SourceValue, target reflect.Value) error {
  ty := reflect.TypeFor[Student]()
  fields := collectStructFields(ty)

  for _, field := range fields {
    fieldSource, err := source.Get(field.Name)
    switch {
    case errors.Is(err, ErrNoValue):
      // no value in source, skip this field
      continue
    case err != nil:
      return fmt.Errorf("lookup source field %q: %w", field.Name, err)
    }

    // TODO
  }

  return nil
}

Next, we use our setterOf function to look up a setter for the current field. The field's type is easily accessible through field.Type. To call the field's setter, we also need the fields reflect.Value, which we can find using the index stored in field.Index. We'll pass that one as the target parameter to the fields setter.

With this information, we're ready to set the value for a struct field:

fieldSetter, err := setterOf(field.Type)
if err != nil {
  return fmt.Errorf("lookup setter for %q: %w", field, err)
}

fieldValue := target.FieldByIndex(field.Index)
if err := fieldSetter(fieldSource, fieldValue); err != nil {
  return fmt.Errorf("set field %q: %w", field.Name, err)
}

Finally, writing a quick test and running it confirms the expected result:

=== RUN   TestSetStudentStruct
Student{Name:"Albert", AgeInYears:16, City:"Zurich"}`
--- PASS: TestSetStudentStruct (0.00s)

Streamlining

You might have noticed that the setStudentStruct function isn't as generic (or reflective?) as it should be. It's currently limited to working with Student structs, which isn't ideal. On top of that, it only handles string and int fields via setterOf, so if we added a nested struct like an Address field — containing city and zip code — the current implementation will fail. Let's update our Student struct to unmarshal while we're at this:

type Student struct {
  Name    string
  Age     int64
  Address struct {
    City    string `json:"city"`
    ZipCode int32  `json:"zip"`
  }
}

We can enhance setStudentStruct by allowing the struct type to be passed as a reflect.Type parameter. This change enables the function to work with other structs, not just Student.

The function could derive the struct type directly from the target value. While this would be a reasonable solution, I prefer the type to be passed in explicitly. This approach lets us separate the setter creation phase from the setter execution phase, making it easier to test each part independently.

func setStruct(ty reflect.Type, source SourceValue, target reflect.Value) error {
  fields := collectStructFields(ty)
  // as before
}

With this change, the function doesn't meet the requirements for a setter anymore. To address that, we can splice it up a little. By creating a function that constructs and returns a setter for any struct type ty, we open the door for unmarshalling any struct type.

func makeSetStruct(ty reflect.Type) setter {
  return func(source SourceValue, target reflect.Value) error {
    fields := collectStructFields(ty)
    // as before
  }
}

With this setup, we can now improve the setterOf function to support struct types too. When it encounters a type of kind Struct, it can dynamically create a new setter for exactly this type using makeSetStruct.

switch ty.Kind() {
  case reflect.Struct:
    return makeSetStruct(ty), nil
  // ...
}

Make it nice

Now we can create a setter capable of handling any struct type, including nested structs, as well as int and string fields. To utilize the setter, we'll need a target value to apply it to. As shown earlier, we can obtain one for any pointer target:

targetValue := reflect.ValueOf(target).Elem()

Let's wrap the reflection logic in a more user-friendly interface, much like how json.Unmarshal operates:

func Unmarshal(source SourceValue, target any) error {
  targetValue := reflect.ValueOf(target).Elem()

  setter, err := setterOf(targetValue.Type())
  if err != nil { return err }

  return setter(source, targetValue)
}

Calling it now correctly fills all nested values:

var student Student
_ = Unmarshal(studentSource, &student)

Student is now filled correctly:

=== RUN   TestSetStruct
Student{Name:Albert AgeInYears:16 Address:{City:Zurich ZipCode:8044}}
--- PASS: TestSetStruct (0.01s)

`

We now have the flexibility to implement different versions of the SourceValue interface and unmarshal it to any struct. For example, one implementation could fetch values from a url.Values instance, while another might extract path parameters from an http.Request. We could even back it with a map[string]any. For testing purposes, a FakeSourceValue could be created to return random strings and integers. The possibilities are limitless!

Some types know better

Skimming through the documentation of encoding/json we can find a reference to encoding.TextUnmarshaler. The documentation of json.Unmarshal tells us:

If the value implements encoding.TextUnmarshaler and the input is a JSON quoted string, Unmarshal calls encoding.TextUnmarshaler.UnmarshalText with the unquoted form of the string.

If encoding/json supports this, there's no reason we shouldn't as well. A quick look at the standard library reveals that this interface is implemented by types like net.IP, and we might want to unmarshal IPs. Fortunately, adding support for this is straightforward given our current setup.

All we need is a new setTextUnmarshaler function that retrieves the value using String() from the source and passes it to the target's UnmarshalText() method. Once implemented, we can update setterOf to return this function as a setter whenever the target type implements the TextUnmarshaler interface.

var tyTextUnmarshaler = reflect.TypeFor[encoding.TextUnmarshaler]()

func setterOf(ty reflect.Type) (setter, error) {
  if ty.Implements(tyTextUnmarshaler) {
    return setTextUnmarshaler, nil
  }
  // ...
}

The implementation of setTextUnmarshaler is straightforward.

func setTextUnmarshaler(source SourceValue, target reflect.Value) error {
  text, err := source.String()
  if err != nil {
    return fmt.Errorf("get string value: %w", err)
  }

  m := target.Interface().(encoding.TextUnmarshaler)
  return m.UnmarshalText([]byte(text))
}

Let's unmarshal this struct now. It contains the IP address of a host and optional port:

type Address struct {
  Host net.IP
  Port *int
}
=== RUN   TestUnmarshalIP
    de_test.go:160: setter for field "Host": type "net.IP" is not supported
--- FAIL: TestUnmarshalIP (0.00s)

The test failure makes sense because net.IP itself doesn't implement TextUnmarshaler; instead, *net.IP does, because UnmarshalText is defined with a pointer receiver. To handle this, we need to update our setterOf function to check if the type implements TextUnmarshaler on a pointer to the current type.

Here's how you we adjust the code:

if reflect.PointerTo(ty).Implements(tyTextUnmarshaler) {
  return setTextUnmarshaler, nil
}

Additionally, when working with a pointer, we need to extract the interface from the pointer value using Addr():

m := target.Addr().Interface().(encoding.TextUnmarshaler)

Run the tests again:

=== RUN   TestUnmarshalIP
    de_test.go:160: setter for field "Port": type "*int" is not supported
--- FAIL: TestUnmarshalIP (0.00s)

Ah, crap — our code doesn't yet handle pointer values. Changing *int back to int allows the Address struct to unmarshal correctly, but that's not the behavior we're aiming for. Thankfully, adding support for pointer values is straightforward. We can introduce a new setter implementation and extend the setterOf method to handle cases where ty.Kind() == reflect.Pointer.

There's an important distinction to keep in mind compared to the setTextUnmarshaler function we just implemented. When a target parameter is passed to the setter, it will be a pointer, but it won't point to anything yet. This means our setter needs to allocate a new instance of the target type (the pointee), and then apply the pointee's setter to it.

To address this, we can follow a similar approach to makeSetStruct and create a makeSetPointer method. This method will generate the appropriate setter for the type:

func makeSetPointer(ty reflect.Type) (setter, error) {
  pointeeType := ty.Elem()

  pointeeSetter, err := setterOf(pointeeType)
  if err != nil { return nil, err }

  setter := func(source SourceValue, target reflect.Value) error {
    // newValue is a pointer to a new instance of the pointeeType
    newValue := reflect.New(pointeeType)
    err := pointeeSetter(source, newValue.Elem())
    if err != nil { return err }

    // set target pointer to the new value
    target.Set(newValue)
    return nil
  }

  return setter, err
}

With this change, we finally achieve the desired result:

=== RUN   TestUnmarshalIP
Host: {Host:127.0.0.1 Port:*8080}
--- PASS: TestUnmarshalIP (0.00s)

Caching

I've already mentioned the idea of separating the setter creation phase from the setter execution phase, and the makeSetPointer method is a great example of this in action. When makeSetPointer is called, it prepares a setter for the pointee type and returns a setter for the pointer type. Once this returned setter is invoked, it doesn't need to inspect any types again — it can directly set the values as needed, even if called multiple times.

In contrast, our makeSetStruct method doesn't yet follow this pattern. During setter execution, it loops over all the struct fields, constructs a new setter by calling setterOf(field.Type) for each, and applies it to the target value. If the struct setter is invoked multiple times, this work is repeated unnecessarily.

To make this more efficient, we can move the construction of setters for each struct field into the setter creation phase of makeSetStruct. The returned setter can then close over this slice and simply invoke each setter in turn during execution.

func makeSetStruct(ty reflect.Type) (setter, error) {
  fields := collectStructFields(ty)

  // Added: prepare setters once during creation
  var fieldSetters []setter
  for _, field := range fields {
    fieldSetter, err := setterOf(field.Type)
    if err != nil { return nil, err }
    fieldSetters = append(fieldSetters, fieldSetter)
  }

  setter := func(source SourceValue, target reflect.Value) error {
    for idx, field := range fields {
      // ... get fieldSource and fieldValue, same as before

      // reference prepared setter during execution
      fieldSetter := fieldSetters[idx]

      // ... call fieldSetter, same as before
    }
    return nil
  }
  return setter, nil
}

This approach also improves testability, as it allows us to separate the process of creating a setter for a struct from the act of invoking it.

But that's actually not quite what I mean by caching. Consider a long-running process. Every time the Unmarshal method is called with a Student reference, setterOf is invoked to create a new setter instance for the Student type. setter creation and setter execution, as described earlier.

Calling setterOf with the Student type will always produce the same (or equivalent) result. We can cache the generated setter based on its reflect.Type, because setterOf is pure (the function return values are identical for identical arguments).

To make things thread-safe and avoid the complexity of locks, we'll skip using a sync.Mutex and instead use a sync.Map. It's unfortunate that Go still does not have a generic sync.Map[K, V], but that's a rant for another time.

So, we'll begin by renaming our setterOf method to makeSetterOf, and then implement a new setterOf method that:

  • Checks the cache for an existing setter for the reflect type ty and returns it if found.
  • Delegates to makeSetterOf to create a new setter if no cached version exists.
  • Caches the new setter if no errors occur.

Easy:

var cachedSetters sync.Map

func setterOf(ty reflect.Type) (setter, error) {
  cached, ok := cachedSetters.Load(ty)
  if ok { return cached.(setter), nil }

  setter, err := makeSetterOf(ty)
  if err != nil { return nil, err }

  cachedSetters.Store(ty, setter)
  return setter, nil
}

One more issue

I was ready to call it quits here, but something kept nagging at me. Let's take a closer look at this struct:

type GitCommit struct {
  Sha1   string
  Parent *GitCommit
}

While this looks harmless, it breaks everything we have:

=== RUN   TestUnmarshalGitCommit
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0x4020160370 stack=[0x4020160000, 0x4040160000]
fatal error: stack overflow
...

narf/zone.deser.setterOf({0x1bc6b8, 0x162900})
narf/zone.deser.makeSetPointer({0x1bc6b8?, 0x14a540?})
narf/zone.deser.makeSetterOf({0x1bc6b8, 0x14a540})
narf/zone.deser.setterOf({0x1bc6b8, 0x14a540})
narf/zone.deser.makeSetStruct({0x1bc6b8?, 0x162900?})
narf/zone.deser.makeSetterOf({0x1bc6b8, 0x162900})
narf/zone.deser.setterOf({0x1bc6b8, 0x162900})
narf/zone.deser.makeSetPointer({0x1bc6b8?, 0x14a540?})
narf/zone.deser.makeSetterOf({0x1bc6b8, 0x14a540})
narf/zone.deser.setterOf({0x1bc6b8, 0x14a540})
narf/zone.deser.makeSetStruct({0x1bc6b8?, 0x162900?})
narf/zone.deser.makeSetterOf({0x1bc6b8, 0x162900})
narf/zone.deser.setterOf({0x1bc6b8, 0x162900})
narf/zone.deser.makeSetPointer({0x1bc6b8?, 0x14a540?})
narf/zone.deser.makeSetterOf({0x1bc6b8, 0x14a540})

This is starting to get tricky. Our code runs into an infinite recursion. While building the setter for GitCommit, we inspect the parent field, which requires us to get a setter for *GitCommit. But to do that, we need to build a setter for GitCommit first, which leads us right back to the same problem. Essentially, we're stuck in an endless loop.

Why isn't this fixed by our setter cache? The issue with the current approach is that we only cache the setter for GitCommit once we've finished constructing it. Since we're constantly trying to construct it again while constructing it, the cache doesn't help us break the cycle.

To handle this, we need a way to detect such cycles. A simple solution is to maintain a global variable that tracks the types we're currently building setter instances for. If we detect a cycle, we can return a placeholder setter that acts as a lazy proxy — it fetches the actual setter implementation from the cache when invoked (during setter execution).

Think of it as a lazy setter. Here's how the flow would work, with stack depths indicated for clarity:

setterOf(1): Mark GitCommit as being constructed.

setterOf(1): Call makeSetStruct(GitCommit).

makeSetStruct(2): Encounter the parent field and call setterOf(GitCommit).

setterOf(3): Detect that GitCommit is already being constructed. Return a lazy setter for GitCommit.

makeSetStruct(2): Return the struct setter for GitCommit.

setterOf(1): Insert the completed setter into the cache.

To prototype this, we can use a map with a zero sized value type as a set to track types under construction. We'll probably want to exchange this with some thread safe type later. Lets do some minor adjustments to the setterOf method:

type inConstructionTypes map[reflect.Type]struct{}

// global cache
var inConstruction = inConstructionTypes{}

func setterOf(ty reflect.Type) (setter, error) {
  // ... do cache lookup as before

   if _, ok := inConstruction[ty]; ok {
    lazySetter := func(source SourceValue, target reflect.Value) error {
      cached, _ := cachedSetters.Load(ty)
      return cached.(setter)(source, target)
    }
    return lazySetter, nil
  }

  // mark in construction
  inConstruction[ty] = struct{}{}
  defer delete(inConstruction, ty)

  // rest as before
}

As promising as this approach sounds, there's a significant issue to consider: concurrency. Imagine two goroutines calling setterOf at the same time. The first goroutine begins constructing a setter for type A. While it's still working, the second goroutine also requests a setter for A. It sees that the setter is under construction and gets a lazy setter as a placeholder.

Now, let's say the first goroutine realizes it cannot complete the setter for A because A has a field of an unsupported type. It returns an error and doesn't add the setter to the cache.

Meanwhile, the second goroutine is left with a lazy setter. When it eventually tries to use this placeholder, it will panic because it attempts to fetch the actual setter from the cache — only to find nothing there.

The root of the problem isn't really concurrency; it's the reliance on global state, specifically inConstruction. By using a shared global variable, we open the door to conflicts and unpredictable behavior.

A better solution is to make the setterOf function reentrant. Instead of depending on a global inConstruction variable, we can pass this state explicitly through the call stack. Each invocation of Unmarshal would create its own tracking set, isolating the construction process. This way, the issue disappears entirely.

// in Unmarshal
setter, err := setterOf(inConstructionTypes{}, targetValue.Type())

// in setterOf
setter, err := makeSetterOf(inConstruction, ty)

// similar changes in makeSetterOf, makeSetStruct, makeSetPointer
// ...

With everything in place, we can now unmarshal our git history!

=== RUN   TestUnmarshalGitCommit
History: {"Sha1":"aaaa","Parent":{"Sha1":"bbbb","Parent":{"Sha1":"cccc","Parent":null}}}
--- PASS: TestUnmarshalGitCommit (0.00s)

Next steps

We've made significant progress, and I think this is a good place to wrap up. Here's a quick outlook on what remains:

  • More Types This one is straightforward. Extending support to types like float64 and bool should be trivial given the current setup.

  • Slices Adding support for slices is another key improvement. This could be achieved by introducing a method At(idx int) (SourceValue, error) within the SourceValue interface.

  • Arrays Similar to slices. Here is an interesting quote from the encoding/json documentation:

    To unmarshal a JSON array into a Go array, Unmarshal decodes JSON array elements into corresponding Go array elements. If the Go array is smaller than the JSON array, the additional JSON array elements are discarded. If the JSON array is smaller than the Go array, the additional Go array elements are set to zero values.

    Who needs errors, am I right?

There's plenty of potential for further refinement, but for now, we've built a solid foundation.

Thank you for making it this far — now go build something!

Discuss this article on reddit.



1

With blackjack and hookers, dah.

2

Technically there is also ,string, but we disregard this for now.