News for hackers. Stuff that matters.
Re:Go 2, here we come by joppy on Thursday November 29, 2018 @12:29PM (#18561910)
I’m hoping that https://github.com/golang/go/issues/19623 will come through, and we’ll get a native “true integer” type (and hopefully a rational one as well, though maybe this is pushing it a bit). This is really something that should be implemented at the language level, so that “int” can become a true integer, yet still remain efficient in many cases.

It is bizarre to me that languages boasting built-in language-level data structures like lists, hashtables, etc are content to just leave us with the bare minimum support of numbers, being basically whatever the hardware thinks a number is. The semantics of integers and fractions are perfect, and everybody already knows them. On the other hand, overflows in int32’s are weird, and if your idea of a fraction is a floating-point number, then you can never have something like (5/3)*6 evaluate to 10 exactly.

To be clear, I think fixed-width integers and floating-point numbers have their place, I just see no reason why they should be the default.

Re:Go 2, here we come by jolmg on Thursday November 29, 2018 @06:37PM (#18565234)
I like how Haskell does it. When you simply write a number like "3" it will infer the type to be "Num a => a" which means it could be any type you have loaded that defines the functions in the typeclass Num:

    class Num a where
      (+) :: a -> a -> a
      (-) :: a -> a -> a
      (*) :: a -> a -> a
      negate :: a -> a
      abs :: a -> a
      signum :: a -> a
      fromInteger :: Integer -> a
"3.0" would be "Fractional a => a" which means it defines the functions in the typeclass Fractional (in addition to being a Num):

    class Num a => Fractional a where
      (/) :: a -> a -> a
      recip :: a -> a
      fromRational :: Rational -> a
Depending on how you use the value, the type would be further refined in compile-time. For example, if you did `recip 3`, 3 couldn't be any Num anymore, it would have to be some Fractional.

Regarding (5/3)*6, it does equal 10 using floating point. A better example would be how 0.1 + 0.2 is not equal to 0.3. We can see this:

    ghci> 0.1 + 0.2 == (0.3 :: Float)
    False
If we specified that we're working with Rational values, which are also Fractional a => a, and which are defined as a pair of integers, one representing a numerator and the other a denominator, roughly like so:

    type Rational = Ratio Integer
    data Ratio a = a :% a
then we can see that 0.1 + 0.2 does equal to 0.3:

    ghci> 0.1 + 0.2 == (0.3 :: Rational)
    True
It's pretty cool that Haskell lets you define new types of numbers and use them like any other. While you can transparently support hardware type numbers, represented by types like Int, Float, Double, Word, Word8, Word16, Word32, Word64, you also have transparent support for arbitrary precision Integer and Rational. Writing your functions to work with the typeclasses like Num and Fractional lets your functions work with any of these types and future types defined.
Re:Go 2, here we come by joppy on Thursday November 29, 2018 @10:09PM (#18566319)
This is a great system for tying in new number types with existing ones, but the lack of explicitness about casting exact types (Integer, Rational) to inexact types (Int, Float) has led to many bugs and confusions for me. Coupled with the fact that so many standard functions (like length, for example) want to return an Int rather than an Integer, it just leads to me spewing ((fromIntegral ___)::Integer) all over my code.

I love all of the automatic casting between exact types, but happily implicitly casting to inexact types is (in my opinion) a big mistake.

Re:Go 2, here we come by runeks on Sunday December 02, 2018 @11:34AM (#18582982)
> [...] but the lack of explicitness about casting exact types (Integer, Rational) to inexact types (Int, Float) has led to many bugs and confusions for me.

What do you mean? As far as I'm aware, you always have to explicitly convert exact types to inexact types in Haskell (using "fromIntegral" and "realToFrac").

> Coupled with the fact that so many standard functions (like length, for example) want to return an Int rather than an Integer, it just leads to me spewing ((fromIntegral ___)::Integer) all over my code.

Indeed this is rather annoying. It's this way because of legacy reasons (see https://www.reddit.com/r/haskell/comments/60u10b/do_function...).

Re:Go 2, here we come by trobertson on Thursday November 29, 2018 @10:23PM (#18566372)
If you don't like the automatic cast, you can always manually cast inline by doing (3 :: Int). I've used this a number of times when doing numeric stuff in Haskell.
Re:Go 2, here we come by joppy on Thursday November 29, 2018 @10:37PM (#18566450)
I do know how to manually cast, although in my case I'm usually casting to Integer. I was arguing that a cast from Num to Float, Double, Int etc is a lossy operation, and breaks the semantics of arithmetic, and so should not be done implicitly.
Re:Go 2, here we come by jolmg on Thursday November 29, 2018 @11:04PM (#18566568)
> but the lack of explicitness about casting exact types (Integer, Rational) to inexact types (Int, Float) has led to many bugs and confusions for me.

> I love all of the automatic casting between exact types, but happily implicitly casting to inexact types is (in my opinion) a big mistake.

> I was arguing that a cast from Num to Float, Double, Int etc is a lossy operation, and breaks the semantics of arithmetic, and so should not be done implicitly

It's not really casting; it's just type inference. You can't have a Num and use it as a Rational in one place and a Float in another (unless you lift the monomorphism restriction), and you can't add a Rational and a Float without explicitly casting one to the other by the use of a function like fromRational. Like so, real casting is very much explicit. I feel like you're technically arguing against representing Floats with decimal numbers in code, but I don't think you really mean that.

EDIT: At the risk of stating something that you might already know, (x :: Int) in Haskell is not a cast like (int)x in C. (x :: Int) simply further restricts the list of possible concrete types that x could be. If the code context implies that x is a Num a => a, that means it could one of an Int, a Float, etc. Doing (x :: Int) simply says to restrict those possibilities to only Int. If x were a Float, and you did x :: Int, that'd be a type error because it was never possible for it to be an Int, only a Float. You'd need to cast by using a function like floor, ceiling, or round.

EDIT 2: To further explain this, C's (int)x is a run-time operation that converts whatever x is to an int, while Haskell's x :: Int is a compile-time operation that states that x can only ever be an Int and never something else. At the end of compiling, Haskell needs everything to be concrete types. Num a => a is not concrete because it can be many types and if Haskell can't resolve it to a single concrete type implicitly by context or explicitly by signatures like x :: Int, then it has to resort to defaulting rules or raise a compile-time error informing the programmer of the type ambiguity.

EDIT 3: On:

> Coupled with the fact that so many standard functions (like length, for example) want to return an Int rather than an Integer, it just leads to me spewing ((fromIntegral ___)::Integer) all over my code.

I agree it would be nice for length to return a Num a => a instead of an Int, but it's nice that the reason is to maintain stability and limit code breakage from the times before Num existed. The Haskell community seems to really care about that. They did add genericLength which does return a Num a => a, though. There's other generic functions added to Data.List.

Re:Go 2, here we come by 13415 on Thursday November 29, 2018 @01:26PM (#18562467)
Makes no sense to me to redefine existing integer types. Why not introduce a primitive type "num" for arbitrary precision rational numbers instead?

As a long-time Racket and Scheme user, I'd say that arbitrary precision numbers as default bring more disadvantages than advantages. As an option with syntax support Yes, but not as a default. it just makes it harder to port all kinds of code that relies on modulo arithmetics.

Re:Go 2, here we come by coder543 on Thursday November 29, 2018 @03:57PM (#18563935)
> it just makes it harder to port all kinds of code that relies on modulo arithmetics.

If you're relying on modulo arithmetic, you should be using a fixed size integer anyways, not one that varies based on the architecture. Go has fixed size integer types available, and modulo arithmetic should be using those, not "int".

Re:Go 2, here we come by viraptor on Thursday November 29, 2018 @04:14PM (#18564085)
I'm not sure how these two are related. Why would you mix modulo operations and fixed size? Modulo on an arbitrary bigint is perfectly valid and useful.
Re:Go 2, here we come by coder543 on Thursday November 29, 2018 @04:23PM (#18564151)
Modulo arithmetic refers to the property of fixed-size integers where they will predictably wraparound in expected ways if you overflow or underflow them. This wraparound is "free", so it used to be commonly used for cyclic high performance code. An arbitrary bigint is computationally more expensive, and it will never experience this effect, so it's a double whammy of irrelevance for bigints. You can manually do a modulo operation on a bigint, but that just makes them even more computationally expensive than a fixed size int, requires more code, and would be considered an unnecessary inconvenience by most people who care about modulo arithmetic.
Re:Go 2, here we come by Beldin on Thursday November 29, 2018 @06:51PM (#18565323)
Except cryptographers. They like modulo arithmetic, and 64 bits really doesn't cut it.
Re:Go 2, here we come by dmurray on Thursday November 29, 2018 @04:21PM (#18564132)
> Why not introduce a primitive type "num" for arbitrary precision rational numbers instead?

Rationals aren't supported natively by processors, so there's no real need to handle this as a primitive instead of letting people to use a library for it. Adding them to the base language just because some people would find it convenient would clash with Go's explicit minimalist philosophy.

Re:Go 2, here we come by CydeWeys on Thursday November 29, 2018 @07:12PM (#18565434)
This argument falls flat for me. Classes aren't supported natively by processors either, yet any number of OOP languages use them.

It's generally nice when you can do simple things with the language's built-in standard library. I tend to prefer languages with more powerful standard libraries because it means that you can more easily move across codebases since they'll all be the same. If commonly used data types like rationals, hashes, maps, strings, etc., aren't defined in the stdlib, then there'll be any number of different libraries to use them, and you'll have to potentially re-learn a lot of different unnecessary things when working on different codebases.

Re:Go 2, here we come by passwd on Friday November 30, 2018 @08:06AM (#18568759)
Yes, standard library. I understood the poster above you to suggest they shouldn't be a part of language by that's used by default, for sure though it would be convenient to have centralized implementation.
Re:Go 2, here we come by makapuf on Friday November 30, 2018 @10:43AM (#18569862)
Exactly. Having a rational datatype as easily usable as float would make it easier to use as a default when you don't really need floats but just non integers. Which is often the case if you think about it. Automatic simplifications, literals (12.345122 is a rational, as well as 22/7)
Re:Go 2, here we come by usrusr on Thursday November 29, 2018 @04:46PM (#18564376)
It's like building in special handling for a string type, exactly one instead of a catalog of library options.

I'd say that would fit in quite well with the brand of minimalism that Go is representing, keep the language simple and provide builtins where more convenience is needed. The opposite kind of "minimalism" would be providing tools to allow libraries to define what other languages can only support as special builtins. C++ and Scala went down that road, they minimize builtins by empowering libraries to replace them. That's also a form of minimalism, but not the one chosen by Go.

Tangent: now I wonder wether Scala has inerited special handling for the (not special, but specially handled) string type it inherited from Java or if just reimplements those syntax extras in the standard library using implicits.

Re:Go 2, here we come by dtech on Friday November 30, 2018 @06:51AM (#18568418)
> I wonder wether Scala has inerited special handling for the (not special, but specially handled) string type

Scala uses Java's String exactly, but does define a few extra methods using its extension method functionality (called implicit class in Scala)

Templates like s"This is a string with a $variable", are part of the language, but `s` is a stdlib feature.

   xxx"First $a $b Second"
will be translated by the compiler to

   new StringContext(Array("First ", " ", " Second")).xxx(a, b)
The standard library defines `StringContext.s`, but there's no restriction. Several SQL Libraries for example define `StringContext.sql`, to allow you to safely and type-checked embed SQL queries directly inside the code.
Re:Go 2, here we come by aoeusnth1 on Thursday November 29, 2018 @07:30PM (#18565559)
"X isn't supported natively by processors, so there's no real need to handle this as a primitive instead of letting people to use a library for it" is a general-purpose argument to cherry pick which primitives you support and which ones you don't. Surely this isn't your actual reason you choose to oppose Rationals / BigIntegers as primitives while accepting hashmaps and arrays?
Re:Go 2, here we come by joppy on Thursday November 29, 2018 @06:45PM (#18565286)
Arrays, slices, hashtables, and channels are not supported natively by the processor, but Go still has them as primitives. Why not also add a number type which behaves in a sane, easy-to-understand, useful way?
Re:Go 2, here we come by shakna on Thursday November 29, 2018 @11:22PM (#18566643)
Scheme has an explicit minimalist philosophy, so much so that when R6RS was released with too many conveniences it fractured the language and community. Now there's two specs, R7RS-small and R7RS-big, and they're far less popular than R5RS.

Rationals are also the default number type.

Lists are the base type used throughout Scheme, and can be used to implement arrays and hashmaps and whatnot, so Scheme doesn't really need them, you can just use a library.

... That didn't stop the committee adding types to the spec. Like records, promises and other complex types.

What is useful and necessary to a language isn't defined by what the processor can natively do, or we'd only use registers, not arrays. And it isn't defined by a overbearing attitude towards one or more philosophies.

Re:Go 2, here we come by outworlder on Thursday November 29, 2018 @03:51PM (#18563870)
This is reminiscent of 'numeric tower' discussions from years ago.
Re:Go 2, here we come by tigershark on Thursday November 29, 2018 @01:27PM (#18562475)
I am misunderstanding or really go is using the ‘int’ type that can be 32 or 64 bit depending on the system that it runs on??? If this is the case I think that is crazy and I can’t think of any useful use case for it. If it’s not the case then please explain me what that proposal is really about...
Re:Go 2, here we come by jerf on Thursday November 29, 2018 @03:02PM (#18563423)
"int" in Go the native index type for arrays. I consider it an error to use it for anything else, and since I've adopted that policy, I've had no particular problem with ints.

Probably a good linter idea in there somewhere.

Re:Go 2, here we come by kbirkeland on Thursday November 29, 2018 @06:17PM (#18565104)
I'm curious what the motivation was to use int instead of uint considering indexes cannot be negative in Go.
Re:Go 2, here we come by jerf on Thursday November 29, 2018 @09:23PM (#18566091)
Despite most of my professional programming being in Go nowadays, I am extremely sympathetic to the Haskell/FP way of thinking about things, and trying to make invalid state unrepresentable.

However, having made the mistake a few times now of trying to use "unsigned ints" for things that I want to assert are never negative, I've learned the hard way not to do that. The problem is, there's always some bug you have in the program that will drive the uint "negative", wrapping over to a huge number. Unfortunately, since you get no warning when that happens, it tends to take longer to show up, and without a clear cutoff to say "ah, this is clearly invalid" it can be hard to even program detection code, whereas checking for "less than 0" can be unambiguous.

I'd loooove it if I could easily, cheaply, and universally (i.e., not just in Go, but across all my programming languages) turn on a behavior that says "if this int or uint under or overflows, throw an exception instead of trying to do whatever stupid thing you're going to do". I get the sense this is heading down the road where in 20 or 30 years, this is just going to be common sense. However, we are very early on the road yet from what I can see. Whenever I bring it up, even today, even in this sort of context, it still is generally negatively received. (But not uniformly. A few other people agree. I think momentum is with me. I'm not sure my programming career will live long enough to see it, though.)

Re:Go 2, here we come by johncolanduoni on Friday November 30, 2018 @12:23AM (#18566920)
Rust does this in debug builds by default, and you can switch it on in production if you'd like.
Re:Go 2, here we come by monocularvision on Friday November 30, 2018 @06:13PM (#18573612)
Swift does this with the default operators. There are alternative operators if you want to get the more classical C-style treatment.
Re:Go 2, here we come by greenleafjacob on Thursday November 29, 2018 @09:59PM (#18566260)
> if this int or uint under or overflows, throw an exception

Overflow flags are supported on some architectures, so it would really just be a matter of checking that flag.

Re:Go 2, here we come by 4ad on Friday November 30, 2018 @06:43AM (#18568388)
Except in Go, types are defined using modular 2s complement. Overflow is not considered a problem, it's a feature that code depends on.
Re:Go 2, here we come by LukeShu on Friday November 30, 2018 @11:34AM (#18570267)
The spec says:

> For signed integers, the operations +, -, , /, and << may legally overflow and the resulting value exists and is deterministically defined by …*

It does not go on to define the overflow values; that gets to be implementation defined.

This is in contrast to unsigned integers, which the spec does precisely define overflow for.

Re:Go 2, here we come by joppy on Friday November 30, 2018 @02:37AM (#18567427)
Using unsigned indexes would be fine if the program automatically throws an error on wrapping. Otherwise, it’s an accident waiting to happen, since you have to code all of your arithmetic keeping in mind the fact that the numbers are trying to blow up in your face.

If x is unsigned, then you can’t rearrange an inequality like x >= 4 into x - 4 >= 0, since the first inequality is only true sometimes, whereas the second is true always. This looks obvious, but bury it a little way into some nontrivial index arithmetic and boom.

Another more aesthetic reason is that indices can represent offsets into a structure relative to some other index, and in this case you really need negative numbers.

Re:Go 2, here we come by IshKebab on Thursday November 29, 2018 @09:27PM (#18566104)
In general it is nicer to use signed numbers for indices. The actual index can't be negative, true, but differences between them can, and it means you don't have so many dubious sign conversions.
Re:Go 2, here we come by pxia on Thursday November 29, 2018 @06:24PM (#18565153)
Because you want to represent errors. For example a find() function that returns the index of some element: you want to return -1 when the element doesn't exist.
Re:Go 2, here we come by growse on Thursday November 29, 2018 @07:12PM (#18565433)
Shouldn't idiomatic go return an error instead? Magic number ranges for errors always seemed a bit old-fashioned.
Re:Go 2, here we come by pxia on Thursday November 29, 2018 @07:23PM (#18565510)
It's just an example... Another example would be you want to iterate your array in reverse. The normal `for (uint i=size-1; i >= 0; i--)` won't work.
Re:Go 2, here we come by growse on Friday November 30, 2018 @06:34AM (#18568350)
That example doesn't work precisely because you're conflating the concept of the loop counter (which type represents an integer that needs to be able to go <0) with the array index accessor. There's no reason for these two things to be the same type, it's just a pattern that accidentally works because we allow arrays to be accessed using a type that represents negative numbers.

What would be a more compelling argument is to use int in the same way that python does - a negative accessor means offset from the end of the array, not the start. I'm not sure golang lets you do this though...?

Re:Go 2, here we come by xyproto on Thursday November 29, 2018 @07:29PM (#18565549)
Returning -1 instead of an error is abusing the type system. In C, there is no error type, so it might be excusable there, but it is inexcusable in Go, IMO.
Re:Go 2, here we come by nordsieck on Thursday November 29, 2018 @07:47PM (#18565638)
> I'm curious what the motivation was to use int instead of uint considering indexes cannot be negative in Go.

I want to emphasize that I do not know the true answer to this question.

I think that indexes are int to play nicely with a decrementing loop counter. Doing:

    for i := len(n) - 1; i >= 0; i-- { fmt.Println(n[i]) }
requires i to be signed due to the last iteration.
Re:Go 2, here we come by a1369209993 on Thursday November 29, 2018 @10:56PM (#18566535)
I'm not sure about go, but in C this could be:

  for(size_t i = zn; i-- > 0 ;) printf("%s\n",n[i]);
(This is a large part of why unsigned over/underflow is well-defined behavior in C.)
Re:Go 2, here we come by nordsieck on Thursday November 29, 2018 @11:28PM (#18566665)
In Go, i++/i-- is a statement, not an expression, so that doesn't work.

More generally, assignment is always a statement, and never an expression (e.g. you can't say a = b = c)

Re:Go 2, here we come by Too on Friday November 30, 2018 @01:44AM (#18567244)
Crazy indeed. This was like lessons learned #2 from C, which later introduced the stdint types int32_t et. al.

A modern language with this type of confusing and platform dependent behavior is inexcusable. By all means, include a native data type as big as the processor can handle (size_t), but don't call it int which is the default data type most people will use out of pure laziness.

Re:Go 2, here we come by throwaway34241 on Thursday November 29, 2018 @03:42PM (#18563797)
Which would you choose instead? To default to 32 bits (even on 64 bit systems) or to default to 64 bits (even on 32 bit systems).

Defaulting to 64 bit math on 32 bit systems will have a huge performance penalty on generally the slowest/oldest systems where this penalty is least desirable. It's not clear to me what the benefit to this would be for most programs.

Running 32 bit ints on 64 bit systems will cause problems handling large arrays on systems with a lot of memory. I think it also complicates generating efficient loop code, although C++ gets around this with signed integer overflow being "undefined behavior".

Of course Go has int64 and int32 types if you want to use them (and all conversions require explicit casting), but the default type for array lengths etc is the platform native type. But what is the better alternative?

Re:Go 2, here we come by tigershark on Friday November 30, 2018 @03:22AM (#18567581)
I would use int and long like in C# for example, with no magic int that can be 32 or 64 bit depending on the platform to avoid any confusion.
Re:Go 2, here we come by throwaway34241 on Friday November 30, 2018 @07:09PM (#18573993)
And as a result of this, you can't have a 3GB byte array in C#. I think there needs to be a big benefit to make hard-coding a restriction like that into the language worth it.

Unfortunately I've read every comment in this HN thread (so far) and I haven't found any specific one mentioned, just people calling it "crazy" and "confusing" over and over.

Go is a language that has explicit pointers! And of course those can be 32 or 64 bits and change struct sizes, field offsets etc. There are certainly things about Go that are confusing but I've never thought this was one of them.

Just FYI Go has int8, int16, int32, int64, and int types. Only the 'int' type is the machine-native one. It's always been obvious to me that 'int' is the one without a fixed size, but I think this would be less obvious if the naming convention was different using short, int, long etc.

Re:Go 2, here we come by toyg on Thursday November 29, 2018 @03:55PM (#18563915)
The subset of Go users who deploy on 32bit hardware in 2018 and care about performance at that level, is likely to be vanishingly small.
Re:Go 2, here we come by LukeShu on Thursday November 29, 2018 @05:32PM (#18564762)
32 bit ARM is still very common.
Re:Go 2, here we come by coldtea on Friday November 30, 2018 @07:36AM (#18568627)
What about Go in 32 bit ARM?
Re:Go 2, here we come by throwaway34241 on Thursday November 29, 2018 @04:16PM (#18564093)
Even if it's OK to degrade the performance of a small minority of users, is there a big benefit to emulating 64 bit ints everywhere on 32 bit hardware? (I'm not saying there isn't a benefit, just that it's not clear to me what it is).

I don't know how many users are still on 32bit. Maybe low power network devices? Older mobile phones (Go isn't usually run on mobile, but it's possible...).

If at some point in the future 32 bit systems become totally irrelevant for Go users, maybe a release of Go could drop support for it altogether and make int an alias for int64, and save people some type casts. 32 bit systems probably aren't at that point yet though.

Re:Go 2, here we come by coldtea on Friday November 30, 2018 @07:37AM (#18568630)
>I don't know how many users are still on 32bit. Maybe low power network devices? Older mobile phones (Go isn't usually run on mobile, but it's possible...).

Well, 16 bit would also be possible if someone took the effort. Perhaps it just shouldn't be encouraged.

Re:Go 2, here we come by throwaway34241 on Friday November 30, 2018 @06:37PM (#18573807)
By 'possible' I meant that it's currently supported by the Go toolchain.
Re:Go 2, here we come by nwmcsween on Thursday November 29, 2018 @02:32PM (#18563152)
Its not crazy, its defined by the system ABI, C, C++ has this too in that can be whatever depending on the ABI, hell char can be 32 bits.
Re:Go 2, here we come by Sharlin on Thursday November 29, 2018 @02:57PM (#18563382)
It may be crazy but it's not exactly without precedent. Neither C nor C++ fix the sizes of the fundamental integer types, although for backward-compatibility reasons popular 64-bit platforms still have 32-bit `int` and even `long`. But yeah, there's a reason eg. Rust has no `int` and friends but `i32` etc. instead.
Re:Go 2, here we come by WakiMiko on Thursday November 29, 2018 @03:25PM (#18563628)
Rust has a `usize` which is 32 or 64 bits depending on the platform and also serves as the native index type for arrays and such.
Re:Go 2, here we come by friday99 on Thursday November 29, 2018 @05:17PM (#18564657)
Yeah, that makes sense because you need some type to span the address space and that depends on the size of the address space. That is what int is used for in go, though why they chose signed rather than unsigned is confusing. unsigned you would never have to do negative bounds checks and you can prove a lot of other useful things if you know your index is always positive.
Re:Go 2, here we come by earenndil on Thursday November 29, 2018 @05:50PM (#18564902)
I don't know how go does it, but in some languages negative indices count backwards from the rear end. E.G. myarr[-1] == myarr[myarr.length-1].
Re:Go 2, here we come by lemoncucumber on Thursday November 29, 2018 @03:42PM (#18563794)
Right, 64-bit Windows has 32-bit int and long and 64-bit long long (LLP64) while 64-bit unixes generally have 32-bit int and 64-bit long/long long (LP64).
Re:Go 2, here we come by user5994461 on Thursday November 29, 2018 @03:13PM (#18563513)
C only defines char, short, int has having a minimum size of 8, 16 and 32 bits.
Re:Go 2, here we come by mrb on Thursday November 29, 2018 @03:17PM (#18563550)
Actually C defines the minimum size of "int" as 16 bits, because it defines the minimum range it should support as [-32768 .. 32767]

See https://en.wikipedia.org/wiki/C_data_types

Re:Go 2, here we come by shric on Thursday November 29, 2018 @04:52PM (#18564439)
Nit: [-32767 .. 32767] C permits ones' complement and sign-and-magnitude as well as two's complement.
Re:Go 2, here we come by jstimpfle on Thursday November 29, 2018 @03:21PM (#18563591)
no, int is 16 bits minimum
Re:Go 2, here we come by pkulak on Thursday November 29, 2018 @01:59PM (#18562799)
You are not crazy, and it's what makes this proposal even more appropriate than other languages. "int" is already a magic type.
Re:Go 2, here we come by icedchai on Thursday November 29, 2018 @04:45PM (#18564364)
Yeah, sounds crazy. It only worked for C for 40+ years...
Re:Go 2, here we come by usrusr on Thursday November 29, 2018 @05:26PM (#18564720)
Ignoring the basic int type and using a zoo of preprocessor defines instead is what has worked for C all that time.

But I still think that native types have their place. It can often be quite reasonable to accept serious limitations on narrow machines where the performance gains won by the trade-off are desperately needed, lift those limitations on wider machines and grant an enormous safety margin on the widest architectures. When you dive deeper, the values where this makes sense still tend to be "index-like", as GP stated, but they don't have to strictly be indexes (e.g. IDs, a wider machine will be capable of working on bigger datasets and therefore be more likely to exhaust a given width of IDs, all indexes are identifiers but not all identifiers are indexes)

Re:Go 2, here we come by geezerjay on Friday November 30, 2018 @02:02PM (#18571631)
> Ignoring the basic int type and using a zoo of preprocessor defines

My C is a bit rusty but why should #defines be used in this scenario? A typedef set in a config.h.in is more than enough to meet the requirements of this usecase.

Re:Go 2, here we come by icedchai on Friday November 30, 2018 @05:30PM (#18573343)
Why do you need your own typedef? stdint.h is available, if you're using a compiler from the past couple of decades at least.
Re:Go 2, here we come by johncolanduoni on Friday November 30, 2018 @12:28AM (#18566942)
And what percentage of programs written in those 40 years are actually able to run on systems with more than one or two different memory layouts?
Re:Go 2, here we come by AsyncAwait on Thursday November 29, 2018 @05:36PM (#18564795)
Why is that a problem? There's int8/16/32/64 for when you need to be specific.
Re:Go 2, here we come by LanceH on Friday November 30, 2018 @12:31AM (#18566952)
I don't know how many times I've been writing a program using int, then suddenly I have to do some math on the index of a range (for example), and the math.* functions require int64. I start casting to int64, but things get infected and it spreads. Eventually I refactor everything to use int64 and wonder why int can't just be an alias for one of the others. Personally I would make it int64, since that is what the standard library thinks math should be done with.
Re:Go 2, here we come by benhoyt on Friday November 30, 2018 @08:31AM (#18568914)
Odd, I've rarely had this issue, and almost never need to do complicated math on the index of a range (maybe "multiply by two and add one" kind of stuff, but nothing from the "math" pkg). Also, note that the math.* functions all use float64, not in64.
Re:Go 2, here we come by LanceH on Friday November 30, 2018 @11:02AM (#18569997)
Yes, you're right float64 in the math package. So I've definitely run into this with float vs float64.

As for the int vs int64, I definitely run into what I describe on Project Euler. Probably using a self referential map[int]int when I need to suddenly pull an int64 and everything gets infected.

I realize it's just a matter of convenience for me, but I personally have no downside to int == int64.

Re:Go 2, here we come by quickthrower2 on Thursday November 29, 2018 @03:08PM (#18563469)
Meh I use C# and I rarely need an int bigger than 2147483647, and if I do I use a long which gets me up to 9223372036854775807, and if I need more than THAT then I'll use a math library of some sort.
Re:Go 2, here we come by joppy on Thursday November 29, 2018 @07:01PM (#18565378)
I think the question though is that if “int” were an actual integer, would you still default to using int32/int64, and for what reason? There are valid uses for fixed-width types, but beyond domain-specific number crunching (crypto, image processing, etc) I would argue that the use of these types is technically incorrect, and not what people expect. Even experienced programmers will see “x > x + 1” and mentally replace that with “true”, even though if x is fixed-width, the value of that expression actually depends on x.
Re:Go 2, here we come by adtac on Thursday November 29, 2018 @03:17PM (#18563547)
The problem with overflow isn't just needing to store numbers larger than 2 billion. Sometimes, intermediate values are larger than that even if the final result isn't.

Take averaging as a very simple example. Doing (a + b) / 2 will overflow if a and b are sufficiently large, even if the average will always fit in 32 bits. Things like this go unseen for years.

Re:Go 2, here we come by dekhn on Thursday November 29, 2018 @03:27PM (#18563646)
don't most people compute the mean iteratively when they need to do this? Sure, it goes unseen, but programmers on systems like this are expected to understand the math model and write tests.
Re:Go 2, here we come by xapata on Thursday November 29, 2018 @08:01PM (#18565701)
Systems like what? My expectation is no, most people make mistakes.
Re:Go 2, here we come by dekhn on Thursday November 29, 2018 @08:42PM (#18565885)
I mean, in C and other low-level languages unlike python, it's generally assumed you have a basic understanding of the machine model and the consequences of arithmetic in limited types.

If most people make mistakes, they should self-select to languages which have properties that protect them from their ignorance. for example, I mostly program in Python using longs so I don't have to worry about overflow.

Re:Go 2, here we come by xapata on Friday November 30, 2018 @03:43AM (#18567661)
What kind of "long" are you referring to? Most programmers would think of a C long, int64, not a Python long, bigint.

Maybe people ought to self-select, but that would mean they'd need the training or experience to recognize what they don't know. It's often the most ignorant people that believe they have the most expertise.

Re:Go 2, here we come by quickthrower2 on Thursday November 29, 2018 @04:14PM (#18564084)
I get you point. I'd probably go float/double precision for that task.
Re:Go 2, here we come by pvg on Thursday November 29, 2018 @05:25PM (#18564718)
Then you can lose precision that you might actually need - a bug that's even more annoying to track down than straight overflow.
Re:Go 2, here we come by quickthrower2 on Thursday November 29, 2018 @07:09PM (#18565420)
Yes indeed! But what is the alternative, especially if you are using approximations to transcendental constants?
Re:Go 2, here we come by paulddraper on Thursday November 29, 2018 @05:32PM (#18564761)
There have been 1,543,530,695,158 milliseconds since epoch.
Re:Go 2, here we come by quickthrower2 on Thursday November 29, 2018 @07:12PM (#18565430)
That would fit into a spacious Int64.

I typically wouldn't be passing around milliseconds since epoch as an raw number, but then that's C#, I guess you might do that in other languages for performance or out of necessity.

Re:Go 2, here we come by the_clarence on Thursday November 29, 2018 @01:47PM (#18562661)
Why oh why do people want a value to have different bounds depending on which system it is used? This is a source of huge confusion and why people stick to uint8 and other precise types
Re:Go 2, here we come by adrianmonk on Thursday November 29, 2018 @02:32PM (#18563154)
It's a perfectly reasonable niche use case for achieving maximum performance.

My main issues with it are:

1. Like many other performance optimizations, it is a trade-off. You may be sacrificing easy maintenance or even introducing breakage (if the person using it doesn't understand the limitations and implications). So IMHO you should only do it if you can show through profiling, etc. that the gain is real and worth it.

2. As a matter of language ergonomics, it should never be something that anyone does unknowingly. You should have to explicitly ask for it. The type name should be something blindingly obviously like "native_int" or "word_int".

Re:Go 2, here we come by dcow on Thursday November 29, 2018 @03:06PM (#18563459)
Even Swift who’s mantra is do nothing unexpected or implicit has a machine dependent (word sized) Int type.
Re:Go 2, here we come by the_clarence on Thursday November 29, 2018 @04:19PM (#18564115)
You’re trading off security here. Users are going to shoot themselves in the foot assuming that int is this size or this size.
Re:Go 2, here we come by drb91 on Thursday November 29, 2018 @02:00PM (#18562810)
People have traditionally wanted to use the maximum sized type that can fit in a register.
Re:Go 2, here we come by Someone on Thursday November 29, 2018 @03:57PM (#18563937)
More precisely: they wanted the integer type that was large enough and ran their code fastest.

On CPUs with 64-bit and 32-bit registers, that typically is the register-sized integer type. Machines with 16-bit registers are a bit of an edge case, as 16-bit integers may both be a lot faster on them then 32-bit integers and, in many cases, too small)

If go chose to use 32-bit integers as default, some users on 64-bit systems would complain that they couldn’t create, say, an array of 6 billion ints. If they chose 64-bit, some users on 32-bit systems would complain their loops were needlessly slow, and code bloated (why waste 4 bytes of almost every integer in a program?)

Not having generics makes this more of a problem. If go had generics, switching between integer sizes could be a matter of recompilation using a different compiler flag)

A sufficiently advanced compiler would help here, but go doesn’t have one (not exceptional), and doesn’t even aim to have one (compilation speed seems more of a goal than run-time speed)

Re:Go 2, here we come by TheDong on Thursday November 29, 2018 @08:03PM (#18565712)
> Not having generics makes this more of a problem. If go had generics, switching between integer sizes could be a matter of recompilation using a different compiler flag)

Isn't it already the case that you can switch between int sizes with compiler flags?

    var i int
That will be 32 bits if I compile it with GOOS=linux GOARCH=386 and will be 32 bits if I swap in amd64 instead of 386 there.

Is there any language where generics are useful for switching between int sizes? None come to mind offhand, so I don't quite understand what you mean.

Re:Go 2, here we come by user5994461 on Thursday November 29, 2018 @03:17PM (#18563545)
Traditionally the register size was too small, it's very common to have numbers above 256 or 65536. It's not true anymore with 32 bits numbers and a limit of 2 billion.
Re:Go 2, here we come by throwaway34241 on Thursday November 29, 2018 @04:29PM (#18564210)
On 64 bit systems you can have large arrays that are bigger than a 32 bit int. For example, it's nice to be able to load a >2GB file into a byte array.

For comparison, Java's int type is 32 bits on 64 bit systems, but then this limits the array size. It seems like a lesser evil to have a platform-native int type than to limit the size of arrays (especially since servers can be expected to increase their max memory going forward).

Of course, standardizing on 64 bit ints instead would require emulating them on 32 bit systems, when they can't support that much memory anyway (you could argue that 32 bit systems don't matter much anymore, but if you really don't care about ever running on them, then you can just treat 'int' as 64 bits and not variable size).

Re:Go 2, here we come by Too on Friday November 30, 2018 @01:52AM (#18567269)
C# is the same, int is merely an alias for Int32 and the default Array type only holds 32bit.

If you really need to, it's easy to wrap this into your own BigArray-class holding a 32bit-array-of-32bit-arrays and overriding the []-operator with Int64 as argument.

Re:Go 2, here we come by scott_s on Thursday November 29, 2018 @04:35PM (#18564268)
It's a rational practice when your language allows casting pointers to integers. Since the size of the pointer itself will vary based on the underlying architecture, you need an integer type which will also vary based on the underlying architecture.
Re:Go 2, here we come by Vendan on Thursday November 29, 2018 @04:51PM (#18564423)
I feel you, but, that's uintptr. int is more useful as the "native type" for array/slice length/cap/indexing
Re:Go 2, here we come by friday99 on Thursday November 29, 2018 @05:20PM (#18564677)
Except length/cap/index are always positive, so I think int was a mistake here.
Re:Go 2, here we come by joppy on Thursday November 29, 2018 @10:32PM (#18566413)
I think that the rationale for using int for array indices and lengths and so on is to avoid shooting yourself in the foot with wrap-around arithmetic (again, my thesis being that when 99% of people use integers, they expect them to behave like integers and not wrap)

Take for example code which finds consecutive differences in a list, something like

  for i := 0; i < len(list) - 1; i++ {
    print(list[i+1] - list[i])
  }
This code looks fine and reasonable, and we even avoided the off-by-one error at the end. However, if len(list) is a uint and we run this on an empty list, len(list) - 1 is then 2^32 or something, and the program explodes.

So this is the rationale for using signed integers rather than unsigned integers. I think the language semantics should go further, and use true integers pretty much everywhere. Note that the compiler could still easily see that the index variable in the loop above is bounded, and use a machine word under-the-hood. But the programmer only ever has to think about well-behaved integers.

Re:Go 2, here we come by scott_s on Friday November 30, 2018 @11:44AM (#18570329)
I actually agree. I was responding to someone who dismissed the entire concept.
Re:Go 2, here we come by Vendan on Friday November 30, 2018 @07:33PM (#18574126)
no, I get that, but int is not for pointer<->integer conversions. That is very specifically a separate type:

    uintptr  an unsigned integer large enough to store the uninterpreted bits of a pointer value
https://golang.org/ref/spec#Numeric_types
Re:Go 2, here we come by scott_s on Friday November 30, 2018 @08:44PM (#18574462)
Sure, but did I imply it was? I’m genuinely confused.
Re:Go 2, here we come by Vendan on Monday December 03, 2018 @12:46AM (#18586615)
> language allows casting pointers to integers

The original thread was about converting int to be an arbitrary precision type: "so that 'int' can become a true integer". One would imagine that, to preserve the ability to do pointer <-> non-pointer number, they would just leave uintptr alone, and so basically ignore your concerns, whereas int as the "native type" for slice indexes and the like is a more likely reason to prevent messing with "int" itself

Re:Go 2, here we come by scott_s on Tuesday December 04, 2018 @10:46AM (#18600408)
Okay, that's the source of the confusion. I was not replying to that sentiment, which is a nuanced discussion on what an int should be. I was replying to the_clarence's categorical dismissal of variable width integer types.
Re:Go 2, here we come by a_c_s on Thursday November 29, 2018 @12:37PM (#18561979)
This was one thing COBOL got right: built in support for a DECIMAL data type.
Re:Go 2, here we come by vvern on Thursday November 29, 2018 @10:24PM (#18566381)
Fixed – Fixed-place decimal math library for Go (github.com) https://news.ycombinator.com/item?id=18559625
[dead]
Re:Go 2, here we come by christophilus on Thursday November 29, 2018 @01:14PM (#18562352)
It’s been a while since I COBOLed, but if I recall, the COBOL decimal is similar to Currency types in languages like C#. (Maybe I’m misremembering.) If I’m right, though, it’s not a floating point number. It’s currency properly handled via integer math under the hood.
Re:Go 2, here we come by int_19h on Thursday November 29, 2018 @09:53PM (#18566231)
In C#, there's a "decimal" type. Which is exactly that - decimal floating-point. However, one catch about it is that it doesn't allow for the exponent that would place the decimal point somewhere outside of the representable digits of the number (i.e. unlike floats, the difference between any two decimals is never more than 1).

But it's still plenty useful, because it allows to accurately represent decimal fractional numbers, which is exactly what's needed in many domains, since humans work with decimal fractional numbers. Representing money would be one particular example.

Re:Go 2, here we come by Symmetry on Thursday November 29, 2018 @01:19PM (#18562401)
Decimal floating point is actually an established thing and part of the current IEEE 754 spec. I'm not too familiar with COBOL but pretty much any modern language will offer it through a library or compiler extension. Recent IBM Power processors even have hardware support.

https://en.wikipedia.org/wiki/Decimal_floating_point

Re:Go 2, here we come by ekimekim on Thursday November 29, 2018 @01:49PM (#18562695)
Both you and the parent are correct. Decimal floating point is a long-established thing, but the vast majority of "Currency" or "Decimal" data types in modern languages are arbitrary or fixed precision (to some configurable precision) which uses integer math under the hood.
Re:Go 2, here we come by vanderZwan on Thursday November 29, 2018 @01:48PM (#18562673)
Given the age of COBOL and the age of IEEE floating points, it would be very unlikely if it used a floating point number.

(And yes, I know that Conrad Zuse invented floating point over a century ago ;))

Re:Go 2, here we come by michaelcampbell on Thursday November 29, 2018 @03:18PM (#18563563)
Probably implementation dependent, but the COBOL I used that put me through college used some variation of BCD (binary coded decimal).
Re:Go 2, here we come by coldtea on Thursday November 29, 2018 @06:37PM (#18565231)
Cobol uses fixed point decimal
Re:Go 2, here we come by igravious on Thursday November 29, 2018 @12:45PM (#18562041)
That would be quite a fundamental change. At the moment _int_ and _uint_ have certain semantics that, if changed, would surely break many applications and libraries that rely on the current semantics. I am finding it hard to think of a more sweeping and drastic change to the core of a language.

Having said that, I'm by no means a Golang expert – this is the comment of an outsider looking in. I get that the proposer is Rob Pike and obviously Mr. Pike is god-like so what is it I am missing? Is Go 2 meant to break everything? That's like, wow.

Any low-level hardware bit-banging code is going to have to be audited or break in subtle ways, will it not? Is Golang different from C and C++ and languages of that ilk that this sort of change is not that much of a problem? Help me out here folks, I'm genuinely perplexed.

Re:Go 2, here we come by HALtheWise on Thursday November 29, 2018 @01:27PM (#18562472)
If the change as originally proposed went through, it probably wouldn't affect most uses of bitbanging low level code because they are already using int32/int64 rather than int (which has different size on different platforms). You are correct that it could definitely break some programs though, and so with recent sensibilities veering away from making any non- backwards-compatible changes, an amended proposal would probably just introduce a new "vint" type (maybe removing the old int type at the same time if it is really ambitious)
Re:Go 2, here we come by pstuart on Thursday November 29, 2018 @01:14PM (#18562358)
If these are new datatypes then they would break nothing (ignoring the "int" default part).

> so what is it I am missing?

The Go team has been adamant about avoiding any changes that break existing code. The whole point of Go 2 is that at some point that might have to happen and they're trying to minimize that pain.

Re:Go 2, here we come by copperx on Thursday November 29, 2018 @01:31PM (#18562516)
I've been thinking about this, and even though it's indeed a breaking change, it's one of those changes that can be easily toggled through a compiler flag. I cannot picture many libraries relying on the edge cases that Pike enumerated.
Re:Go 2, here we come by losvedir on Friday November 30, 2018 @08:34AM (#18568928)
My (admittedly unsophisticated) mental model is that int32 and the like are simple primitives that can be stored in registers and use the processor's native ADD/MUL codes, while BigInt is going to be some boxed structure with its own implementation of arithmetic operations. For as common as number munging is (especially in somewhat lower level code that Go shoots for), it would carry a huge performance penalty, wouldn't it? Or are there more sophisticated ways of offering a "true integer" type that I'm not aware of?
Re:Go 2, here we come by Insanity on Thursday November 29, 2018 @03:21PM (#18563602)
I'd like this because it'd make certain classes of programming problems simpler.

Admittedly, not for things I build in my day-job but mostly for the kind of things you'd get when doing 'project euler' or 'leetcode'. Or more seasonal, the coming "Advent of Code".