Comment by 9rx

2 days ago

> it was annoying to program (due to a lack of enums)

Typescript also lacks enums. Why wasn't it considered annoying?

I mean, technically it does have an enum keyword that offers what most would consider to be enums, but that keyword behaves exactly the same as what Go offers, which you don't consider to be enums.

In typescript I typed my text editing operations like this:

    type Operation = {type: “insert”, …} | {type: “delete”, …} | …;

It’s trivial to switch based on the type field. And when you do, typescript gives you full type checking for that specific variant. It’s not as efficient at runtime as C, but it’s very clean code.

Go doesn’t have any equivalent to this. Nor does go support tagged unions - which is what I used in C. The most idiomatic approach I could think of in Go was to use interface {} and polymorphism. But that was more verbose (~50% more lines of code) and more error prone. And it’s much harder to read - instead of simply branching based on the operation type, I implemented a virtual method for all my different variants and called it. But that spread my logic all over the place.

If I did it again I’d consider just making a struct in go with the superset of all the fields across all my variants. Still ugly, but maybe it would be better than dynamic dispatch? I dunno.

I wish I still had the go code I wrote. The C, rust, swift and typescript variants are kicking around on my github somewhere. If you want a poke at the code, I can find them when I’m at my desk.

They presumably mean tagged unions like `User = Guest | LoggedIn(id, username)`.

  • That wouldn't explain C, then, which does not have sum types either.

    All three languages do have enums (as it is normally defined), though. Go is only the odd one out by using a different keyword. As these programs were told to be written as carbon copies of each other, not to the idioms of each language, it is likely the author didn't take time to understand what features are available. No enum keyword was assumed to mean it doesn't exist at all, I guess.

    • C has numeric enums and tagged unions, which are sum types without any compile time safety. That’s idiomatic C.

      Go doesn’t have any equivalent. How do you do stuff like this in Go, at all?

      I’ve been programming for 30+ years. Long enough to know direct translations between languages are rarely beautiful. But I’m not an expert in Go. Maybe there’s some tricks I’m missing?

      Here’s the problem, if you want to have a stab at it. The code in question defines a text editing operation as a list of editing components: Insert, Delete and Skip. When applying an editing operation, we start at the start of the document. Skip moves the cursor forward by some specified length. Insert inserts at the current position and delete deletes some number of characters at the position.

      Eg:

          enum OpComponent {
              Skip(int),
              Insert(String),
              Delete(int),
          }
      
          type Op = List<OpComponent>
      

      Then there’s a whole bunch of functions with use operations - eg to apply them to a document, to compose them together and to do operational transform.

      How would you model this in Go?

      5 replies →