Comment by hombre_fatal

2 days ago

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?

    • > C has numeric enums and tagged unions

      C has unions, but they're not tagged. You can roll your own tagged unions, of course, but that's moving beyond it being a feature of the language.

      > How would you model this in Go?

      I'm committing the same earlier sin by trying to model it from the solution instead of the problem, so the actual best approach might be totally different, but at least in staying somewhat true to your code:

          type OpComponent interface { op() }
          type Op = []OpComponent
      
          type Skip struct { Value int }
          func (s Skip) op() {}
          type Insert struct { Value string }
          func (i Insert) op() {}
          type Delete struct { Value int }
          func (d Delete) op() {}
      
          op := Op{
              Skip{Value: 5},
              Insert{Value: "hello"},
              Delete{Value: 3},
          }

      4 replies →