

Constants - jweir
http://blog.golang.org/constants

======
millstone
> In summary, a typed constant obeys all the rules of typed values in Go.

I think this is too optimistic. For example, you can divide by a 0 value but
not by a 0 constant:

    
    
        1.0 / 0.0 // compile error
    

but

    
    
        zero := 0.0
        1.0 / zero // infinity
    

Or try:

    
    
            foo := 0.0
    	fmt.Printf("%f", -foo) // outputs -0.0
            fmt.Printf("%f", -0.0) // outputs 0.0
    

So negating a zero value is different than negating a zero constant. Rather
confusing.

~~~
Tloewald
Seems like they've eliminated a class of subtle bugs and introduced a new
class of subtle bugs. I can understand why mixing signed and unsigned types
leads to subtle bugs, but not being able to mix floating types and integer
types is, in practice, a big pain in the butt and I'm not convinced it's
preventing anything bad from happening -- it just wraps bugs in casts.

~~~
jerf
To really do this right, a cast probably should have been able to fail, but
this really complexifies code. On the other hand, only a certain restricted
class of casts can truly not fail and I wish Go could tell the difference.

To be honest, this seems like one of those places where Go suffers from having
paid a little less attention to the mainstream of type theory than I'd like.
One of the things I think we can learn from our various experiments and years
of experience with code is that any sharp bit of the code _will_ eventually
come out and bite your program. No matter how inconvenient it is to have to
deal with errors on truncation, if you make it "easy" and just silently eat
the extra bits, it will eventually cause bugs, pretty much every time. I mean
that fairly literally... it boggles my mind that damn near every time I set to
use a number I encounter this problem incredibly regularly. I'd really like to
be able to use uints more often, but it's too easy for them to blow up in your
face instead of helpfully restricting the range of things you have to think
about, as a type should.

You can tell the Go authors over the years have independently rediscovered a
lot of the same principles, because Go is a lot more careful than C or a
number of other extant languages in a lot of places, but there's the
occasional blind spot like the numeric type hierarchy. I've come to like Go in
a lot of ways, but I find dealing with the numeric types a bit of a
throwback... I wish I could flip a flag or something and get panics on
overflows or underflows instead of silent truncation. It's an annoyingly
difficult bug to track down sometimes.

~~~
JoeAltmaier
Funny, I haven't had but a few truncation bugs in 20 years. And only when
doing math on rates etc. Where I know they can occur, and do a diligent job of
testing, so no issue.

I think this is overblown. Should every i++ have to deal with truncation
issues? This would overburden code pointlessly.

~~~
jerf
From my training in other languages, I _really_ want to use uint on values
that have no meaning when negative. If you look at that statement with C eyes,
that probably sounds insane, but if you look at it from a modern type system
perspective, it sounds eminently sensible and if anything not paranoid enough
(where's your _upper_ bound?).

Unfortunately it's too darned easy to casually subtract something and bam, Big
Numbers due to underflow. What I _want_ is to be _told_ I have bug... what I
get is just the bug.

I've also encountered it in some network code where the numbers in question
were bitpacked. I mean, sure, it's my bug, but philosophically I no longer
think that's the end of the story. Anything a compiler or runtime can do to
help me avoid bugs, it should, and noticing a truncation is definitely in that
class. Again, that statement may sound crazy in a C world, but it's perfectly
sensible in a modern one.

You don't get truncation bugs because you're so used to not getting any help
that you just do bad things like not correctly specify your type, because
you've thoroughly internalized how bad and wrong the compiler and runtime are
here. You shouldn't have to lie about your types to make your code work.

~~~
TheLoneWolfling
Personally, I really wish numeric types supported more than just
unsigned/signed <minimum bit length>. Generic range types at a minimum,
perhaps even "a type is defined by a pure function that returns true/false for
if the value is a valid instance of that type" \- want to specify that the
input must be a Gaussian prime at compile time? Sure! (Or, for a saner
example, want to specify that the input must be a normalized quaternion?
Sure!)

For generic range types, you can just specify "this stores a number in this
range" (with negative infinity/infinity being valid values for the bounds) and
let the compiler figure out the best way to store it (with overrides, of
course. Just because you have sane defaults doesn't mean you should make
people fight the language). Especially if you could specify wrapping rules.
Exception on under/overflow / wrapping / saturation / "won't happen" (read:
compile-time error if the compiler can show that it can overflow/underflow) -
exception being the default.

------
zak_mc_kracken
> When designing Go, we decided to avoid this minefield by mandating that
> there is no mixing of numeric types

Except when these values are constant, in which case you can mix at will.

Quite a weird design decision.

------
kornakiewicz
When I was playing around one of most irritating thing in Go was that I need
to write a lot of type conversions, especially since there's eight "normal"
integer types. In my opinion, for sake of simplicity it could be reduced.

~~~
enneff
To be fair, it's rare to use anything but int and float64 in most programs,
and it's exceedingly rare to use anything more than a couple of different
precision integer types (unless you're writing a binary codec or something).

I don't think you mean "simplicity" here. What's simpler than forcing the
programmer to say what they mean? Perhaps you mean "convenience".

~~~
k__
But it's those problems that keep me away from static typed languages.

When I had to use Java for a project, most of the time I was casting objects
around, because libA didn't use stuff libB needed etc.

~~~
enneff
The Java ecosystem is pretty painful like that. Go's ecosystem is a lot more
consistent, in my experience.

Honestly, the difficulty expressed by the GP here is way oversold. I spent a
decade using dynamically typed languages and I slid into Go with little
difficulty. I really appreciate static typing now.

------
twotwotwo
Kind of fun that, say, uint(0+0i) works, not that I'm going to use that
tomorrow.

------
pilif
This brings back memories of times long since past as this is pretty much how
Delphi deals with constants.

------
eru
It's strange that they only have numeric and string constants. What about,
say, constant arrays?

~~~
Laremere
Go doesn't have them. There is no large need for any special consideration of
values other than those discussed in the blog post. The programmer can declare
the global variable easy enough, and even use Go's Init method to populate the
values. As the blog outlined, variables all have type, and it's only constants
which don't have a specific type in Go. It's true it's possible to theorize up
a special case where you'd want a slice of these broadly typed values, but
that would add a lot of complexity to the language for doing some work which
isn't very hard to do without the language feature. As for wanting a constant
variable, Go doesn't have that because in the opinion of the designers it
makes the type system much more complicated for a gain that isn't worth the
effort and language complication.

~~~
alecbenzer
I don't understand. Why is

    
    
      const str = "Hello, world!"
    

important to have and easy to implement, but

    
    
      const strs = []string{"Hello", "world!"}
    

is not?

~~~
tjgq
What happens when you write

    
    
      var x []string = strs ?
    

If you make a copy of the slice's underlying array and point x to the copy,
then you are hiding a potentially expensive allocation behind an apparently
innocuous initialization (something that Go tries very hard not to do).

If, instead, you make x point to the same underlying array as strs, then you
would have to have immutable slices, which is something that currently does
not exist in Go.

I'm not saying neither of the two options is acceptable, but they surely raise
issues that go against the grain of the language.

~~~
alecbenzer
I'd expect it to do the exact same thing as

    
    
      var x []string = []string{"Hello", "world!"}
    

which I guess does a "copy" of the temporary? (Or at least requires O(slice's
size) work).

But so

    
    
      const s string = "Hello, world!"
      var x string = s
    

Doesn't do a copy of the data?

That's somewhat satisfying of an explanation, though I guess I still don't see
the huge trouble in having it do the copy for a slice. (I mean, really, how
large is a slice embedded into the source code going to be?)

~~~
Laremere
The second example doesn't do a copy of the data. The underlying data storage
of a string is immutable. In your example x would point to the memory location
of the constant string s. If you do for example:

    
    
        x += "\n"  
      

Then new memory would be allocated, and the current contents of x would be
copied in, and the "\n" would be copied in after it. Since the string's type
can't modify the underlying data, it's safe. However a slice has the ability
to do so, the data must be copied. As the article link elaborates on, one of
the main design features of constants in Go is their ambiguous type. Since
slices or arrays require their components to have a specific type, the only
remaining feature is that they do the copy as you talk about. (Unless you want
to really complicate slice logic.)

It's a rare request that you're talking about. If you have a slice which code
references but doesn't edit, make it a package level var and be done with it.
If you need to be able to get the same starting slice which you can then edit,
make a function to return and initialize it. These solutions fit well within
the language's design, and mean that everyone learning the language doesn't
have to learn a specific feature that they could easily do without.

------
kristianp
This is the permanent link for the constants article, currently the link
points to the blog front page:

[http://blog.golang.org/constants](http://blog.golang.org/constants)

edit: it has been updated now.

~~~
dang
Thanks!

