Hacker News new | past | comments | ask | show | jobs | submit login

It doesn't have what Rust mistakenly calls enums - what everyone else in the world calls sum types, but it most definitely has enums in the traditional sense. Enum normally refers simply to assigning a number to something. That is what iota does.



Enums in the traditional sense, is what Pascal and C have been doing it for decades.

    (* Pascal in 1970 *)
    Planet = (Unknown, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune);

    // C in 1989
    enum Planet {Unknown, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune};
Plus type system guarantees, and in Pascal's case, run time capabilities to query enum values and ranges.

Go's hack has barely anything to do with that.


Yes, those examples too assign a number to something. Enumeration is not a new concept. In fact, it's an incredibly old concept that emerged in programming langauges as a hack to work around our, a the time, limited understanding of type systems. A modern type system has no reason for enums at all. Of course, Go purposefully tries to be an 'old' language, hence why it copied the antiquated pattern of providing assignment of numbers as a language feature.


You mean it copied how programming used to be before 1970's. Great achievement.


Not really. Enums as a programming language construct are a 1970s invention.

Funnily enough, Algol 68 had sum types, although controversially so due to overhead concerns. If only Go had copied the state of programming before 1970, then we wouldn't have to listen to all the nonsense about enums sucking. Of course they suck – they are, and always will be, a hack to work around a limited type system.


Go does not have any kind of enumerations, what is has are constants and a gigantic hack for pseudo enumerations, they even compile with broken values!

    package main

    import "fmt"

    type planet int

    const (
        unknown planet = iota // invalid
        mercury               // Mercury 0.378,2439.7,3.3e23,57910000,88,0.0000000001,0,false
        venus                 // Venus 0.907,6051.8,4.87e24,108200000,225,92,0,false
        earth                 // Earth 1,6378.1,5.97e24,149600000,365,1,1,false
        mars                  // Mars 0.377,3389.5,6.42e23,227900000,687,0.01,2,false
        jupiter               // Jupiter 2.36,69911,1.90e27,778600000,4333,20,4,true
        saturn                // Saturn 0.916,58232,5.68e26,1433500000,10759,1,7,true
        uranus                // Uranus 0.889,25362,8.68e25,2872500000,30687,1.3,13,true
        neptune               // Neptune 1.12,24622,1.02e26,4495100000,60190,1.5,2,true
    )

    func main() {
        landingOn := venus
        fmt.Printf("Landing on %d\n", landingOn)
        landingOn = 42 // What a hack!
        fmt.Printf("Landing on %d\n", landingOn)
    }

https://go.dev/play/p/9AzJeHB0YbT


> they even compile with broken values!

Of course. Same as C:

    #include <stdio.h>

    enum planet {
        unknown,
        mercury
        /* ... */
    };

    int main() {
        planet landingOn = mercury;
        printf("Landing on %d\n", landingOn);
        landingOn = planet(42); // What a hack!
        printf("Landing on %d\n", landingOn);
    }
Value constraints have nothing to do with enums. Enums are exclusively about numbering – and as your code shows, the numbering works just fine. Value constraints are an independent feature. One that Go (and C) lack completely, not just in the case of enum values. You can compile with broken values throughout. Consider:

    type EmailAddress string
    var email EmailAddress = "Not an email address" // A-OK!
Compare that with a language with a more advanced type system like, say, Typescript:

    type EmailAddress = `${string}@${string}`
    let email: EmailAddress = 'Not an email address' // Compiler error
You can probably make a good case that Go would benefit from value constraints, among other features, but if you're going to start adding such features, why have enums at all? Again, they're a hack to work around a limited type system. If your type system isn't limited...


Now do the same with 1970's Pascal enumerations.


Pascal doesn't really have enums as a language feature, so there is no direct analog. It has enums as an implementation detail, but for all intents and purposes the language could be implemented with something other than enums. The same is not true of C or Go, which make enums a first-class citizen of the language.

That is, with the caveat that Pascal does allow the union to be converted to its underlying enum representation. If we provide such conversion to get at the enum, then sure:

    Program Lander(output);
    type
      planet = (unknown, mercury);
    var
      landingOn: Integer;
    begin
      landingOn := Ord(mercury);
      writeln('Landing on ', landingOn);
      landingOn := 42;
      writeln('Landing on ', landingOn);
    end.
But you're ultimately comparing apples and oranges.


That program isn't correct, you are faking it by using an Integer.


Indeed. Just as I explained, Pascal doesn't really have language support for enums. The pseudo 'sum types' abstraction works to try and hide the fact that enums exist, only presenting the implementation detail enum if you explicitly convert a union element to its enumerated ordinal – which, as it happens, is an integer type.

The program is correct – it complies and runs just fine – but the original ask was faulty. Without any kind of real enum support in Pascal the language, there is no way to perform the same operations as is possible in languages that do have natural enum support. This program is the best you are going to do in the absence of that support. This was all detailed earlier.

Again, you are trying to compare apples and oranges. Rust[1] may try as it might to call sum types enums, but enums and sum types – along with Pascal's pseudo 'sum types' – are different models. I understand where your confusion stems from as there are a lot of similarities, but there is also a difference.

[1] And Swift originally, but its documentation is updated to make clear that, contrary to what the name implies, the language's enum construct is actually sum types and not enums.


And without the explicit cast I'm getting:

GCC: error: invalid conversion from 'int' to 'planet'

clang: error: assigning to 'enum planet' from incompatible type 'int'

Yeah, with casts C let's you reinterpret anything as anything else. Similar to `as any` in TypeScipt.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: