28 comments

[ 3.2 ms ] story [ 75.2 ms ] thread
This is a great primer on iota but the title doesn't make sense to me. I expected talking about an empty struct that uses zero bytes
I'm guessing the title was meant to be a nod toward the meaning of the English word iota, "an extremely small amount".
Also the physically smallest letter of the Greek alphabet.
I was expecting the smallest binary possible from go
Which, mind you, got me interested in go. I remember seeing a docker image of 4mb that ran a pretty well server. Not sure if it's still possible or what article it was.
Still is. I made a basic http responder last week and it was under 4mb static compiled for a scratch docker container. I didn't even have to resort to compression, just stripped debug symbols.
A 3.25inch disk (the one that makes the well known save symbol) held 1.44 megabytes.

These held entire graphical games and now we’re impressed when we can respond to an HTTP request in a binary that size.

Something got lost…

For a lot of newer compiled languages this comes down to static compilation. These aren't linking to any system libraries beyond the OS fundamentals.

That and they have way more debug symbols than Comander Keen, probably.

There was no crypto stuff during the floppy times, and that's a lot of extra code
That's impressive.

But perhaps this thing is even more impressive: https://redbean.dev/

It's a single-file webserver that is also a zip file, and that's also a multi-platform executable (that's right, you can run the same file on Windows, Linux, BSDs, MacOS and more). It even includes a Lua interpreter, SQLiteDB, JSON etc.

And it's so fast it's unbelievable.

Version 2.2 was only 2.2MB , but looks like version 3.0 has grown to 5.5MB, not sure what happened!

This looks like plain old enum in plain c.

Did I miss something that makes it remarkable?

> This looks like plain old enum in plain c.

It very nearly is.

> Did I miss something that makes it remarkable?

Yes. The literal 'iota' keyword. There is no equivalent to this in C.

How is that remarkable?

Does it have some other actual function and this article is only saying how btw it can also be used to make ersatz enums?

> make ersatz enums?

The author is describing 'iota'. You can easily combine this technique with a custom type wrapper which provides the "full enum" if that's actually what you need. In which case this provides a level of capability and convenience above that of C.

In practice, it really is quite remarkable, when you first use it to it's fullest extent.

The basic use of iota is just what C enums do by default.
That's one of potentially unlimited use cases. iota composes with just about any static math expression to generate almost any kind of sequence. The most common is obviously conveniently constructing bit vectors; which is possible in C, but not as an automatically composed sequence. This really is a nice feature in practice and certainly not the only type of convenient sequence you can create.

A contrived example might be:

    const (
        A rune = 'A' + iota
        B
    )

    func main() {
        fmt.Printf("Hello %c", B)
    }
You can, of course, just write it like a C enum if you were so inclined and that willing to go out of your way to show your disinterest in something.
> You can, of course, just write it like a C enum if you were so inclined and that willing to go out of your way to show your disinterest in something.

Oh c'mon, that's a cheap shot. Your example is odd, as it doesn't really show off anything interesting; I can indeed write it as a C enum, and I can do it with less typing:

    enum {
        A = 'A',
        B,
    };
iota doesn't really do anything interesting there. Much more interesting, IMO, was the example in the article where it can be used to easily construct bitfields. That shows off the "just about any static math expression" that you point out.

I think my problem with it overall is that it's weird and unexpected. Even when it can be genuinely useful, it doesn't really fit in the language as a part of syntax. Then again, I feel like that's pretty common for Go.

Does B == 'B' in your example?
Yes, C enums increment by one for each case if no value is specified.
The answer is supposed to be "iota itself is unusual," but imo iota is not really remarkable by itself. I mean it's nice, it's not pointless (though arguably it isn't parsimonious), but you could just type in the numbers. It's not saving you that much.

What I'd really want is something that clearly differentiates enums where the values do matter and the values don't matter, which iota comes so close to being, but then you can do math with it. To use their example, it doesn't really matter if "electron" is 4 or 8 or whatever, but I'm sure as hell not going to assign 5 to January.

The thing that’s remarkable is that, with iota, you can specify an expression that computes the enum value:

For example, this:

  const (
    Foo = 2 * iota // 0
    Bar = 2 * iota // 2
    Baz = 3 * iota // 6
    // ...
  )
It typically is combined with another feature, explicit repetition of the last non-empty expression list (https://go.dev/ref/spec#Constant_declarations) to avoid having to repeat the iota expression.

For a powerful example see https://go.dev/ref/spec#Iota:

By definition, multiple uses of iota in the same ConstSpec all have the same value:

  const (
    bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0  (iota == 0)
    bit1, mask1                           // bit1 == 2, mask1 == 1  (iota == 1)
    _, _                                  // (iota == 2, unused)
    bit3, mask3                           // bit3 == 8, mask3 == 7  (iota == 3)
  )
I think that’s bordering on “too smart for it’s own good”, but it does prevent a very common copy-paste bug in C, where one would write something like

  enum {
    bit0 = 1 << 0,
    bit1 = 1 << 1,
    bit3 = 1 << 3,

    mask0 = bit0 - 1
    mask1 = bit1 - 1,
    mask3 = bit1 - 1 // copy-paste error
  }
(Happens fairly easily in real world code when the Enums are long, and extra Enums get added over time)
Thank you. Arbitrary expression is what I was missing.
It is Go, apparently having plain old enums is too advanced.
It's one of my major pain points with Go. When can we have proper enum support with compile-time checks whether all the enum values are exhausted?
In about 10 years, maybe :)
(comment deleted)
Not sure where I read it, but I think it's useful to have your 0th iota value be a not valid value, or as your empty/zero value for the enum. Maybe in the planet example you have "Space" or "Nothingness" as your 0 value