Why can't convert []T to []T2 if T2 is a copy definition of T?

511 views
Skip to first unread message

T L

unread,
Aug 26, 2016, 11:45:40 AM8/26/16
to golang-nuts


package main

type Age int

func main() {
    var ages = []Age{17, 18, 19}
    var ints = ([]int)(ages) // error: cannot convert ages (type []Age) to type []int
    _ = ints
}

Jan Mercl

unread,
Aug 26, 2016, 11:55:26 AM8/26/16
to T L, golang-nuts
Because Go is a type safe language. []T and []T2 have different element types and different underlying types, so in the general case the conversion would not be type safe. Also, again in the general case, the memory layout of the backing arrays of []T and []T2 are not the same.
--

-j

T L

unread,
Aug 26, 2016, 11:58:51 AM8/26/16
to golang-nuts, tapi...@gmail.com

why the underlying types of []Age and []int are not the same.
 

-j

Jan Mercl

unread,
Aug 26, 2016, 12:05:28 PM8/26/16
to T L, golang-nuts


On Fri, Aug 26, 2016, 17:59 T L <tapi...@gmail.com> wrote:


--

why the underlying types of []Age and []int are not the same.

The underlying type of an anonymous type []T is []T.


--

-j

T L

unread,
Aug 26, 2016, 12:09:30 PM8/26/16
to golang-nuts, tapi...@gmail.com

What are differences between memory layouts of []Age and []int?
 
--

-j

Axel Wagner

unread,
Aug 26, 2016, 12:36:58 PM8/26/16
to T L, golang-nuts
There is none. It would be perfectly possible and reasonable to make this possible, but it probably didn't seem worth the effort to introduce this special case into the language which has such a limited use. If you can't live without, you can always use unsafe to do it yourself (though, of course, that's unsafe).

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

T L

unread,
Aug 26, 2016, 1:11:17 PM8/26/16
to golang-nuts, tapi...@gmail.com


On Saturday, August 27, 2016 at 12:36:58 AM UTC+8, Axel Wagner wrote:
There is none. It would be perfectly possible and reasonable to make this possible, but it probably didn't seem worth the effort to introduce this special case into the language which has such a limited use. If you can't live without, you can always use unsafe to do it yourself (though, of course, that's unsafe).

What effort needs to make to convert []Age into []int?
 

On Fri, Aug 26, 2016 at 6:09 PM, T L <tapi...@gmail.com> wrote:


On Saturday, August 27, 2016 at 12:05:28 AM UTC+8, Jan Mercl wrote:


On Fri, Aug 26, 2016, 17:59 T L <tapi...@gmail.com> wrote:


--

why the underlying types of []Age and []int are not the same.

The underlying type of an anonymous type []T is []T.



What are differences between memory layouts of []Age and []int?
 
--

-j

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Michael Jones

unread,
Aug 26, 2016, 1:34:42 PM8/26/16
to T L, golang-nuts

package main

 

import "fmt"

import "unsafe"

 

type Age int

 

func main() {

    var ages = []Age{17, 18, 19}

    var ints = *(*[]int)(unsafe.Pointer(&ages))

   fmt.Println(ints)

Axel Wagner

unread,
Aug 26, 2016, 1:43:03 PM8/26/16
to T L, golang-nuts
The effort is putting a special case into the language for this. 

To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.

T L

unread,
Aug 26, 2016, 1:50:19 PM8/26/16
to golang-nuts, tapi...@gmail.com


On Saturday, August 27, 2016 at 1:34:42 AM UTC+8, Michael Jones wrote:

package main

 

import "fmt"

import "unsafe"

 

type Age int

 

func main() {

    var ages = []Age{17, 18, 19}

    var ints = *(*[]int)(unsafe.Pointer(&ages))

   fmt.Println(ints)

}


Looks effortless for compiler to do this without using the unsafe package.
 

T L

unread,
Aug 26, 2016, 1:51:57 PM8/26/16
to golang-nuts, tapi...@gmail.com


On Saturday, August 27, 2016 at 1:43:03 AM UTC+8, Axel Wagner wrote:
The effort is putting a special case into the language for this. 

I feel the effort is made to forbid converting []Age into []int instead now.
 

Ian Lance Taylor

unread,
Aug 26, 2016, 2:12:55 PM8/26/16
to T L, golang-nuts
On Fri, Aug 26, 2016 at 10:51 AM, T L <tapi...@gmail.com> wrote:
>
> On Saturday, August 27, 2016 at 1:43:03 AM UTC+8, Axel Wagner wrote:
>>
>> The effort is putting a special case into the language for this.
>
>
> I feel the effort is made to forbid converting []Age into []int instead now.


What is your overall goal with all the questions you ask? You seem to
have a certain point of view about the language, one that is not
shared by many other people who work with and on the language. You
ask your questions in a very terse manner, which makes it hard to
understand what kind of answer you are looking for, and why you are
asking.

Can you expand on that?


To answer this specific question of yours, one in a long series, there
is one rule in the language: you can't convert []T1 to []T2. You are
suggesting that there is an extra rule to forbids converting []T1 to
[]T2 when T1 and T2 have the same underlying representation. Your
statement is clearly incorrect; there is no such rule. Perhaps I
misunderstand what you are saying. However, the only way I know to
interpret what appears to be your suggestion is to add a new rule to
the language: despite the overall prohibition on converting []T1 to
[]T2, you are permitted to convert them exactly when T1 and T2 have
the same underlying representation. That rule is much more complex
than the current rule. It means that people reading Go code have to
understand when T1 and T2 have the same representation. It means that
that needs to be defined in the language, which it currently is not.
For example, on a 64-bit system, should we permit converting []int to
[]int64, one on a 32-bit system should we permit converting []int to
[]int32? These questions do not have obvious answers, at least not to
me. The rule saying you can't convert []T1 to []T2 is very simple,
and can be understood by even a beginning Go programmer.

Ian

xiio...@gmail.com

unread,
Aug 26, 2016, 3:13:16 PM8/26/16
to golang-nuts
"I feel the effort is made to forbid converting []Age into []int instead now."

I don't agree that allowing this conversion would be 'easier' than not allowing.

Allowing it requires the additional step of splitting/extracting from the slice the element type and checking that (for assignability)

I am fairly certain that currently that step isn't performed and the slice is treated as a type unto itself, not as some sort of "composite type"

It is/would be an extra step to achieve what is suggested in the original example.

I feel you are asking for extra recursion in the type analysis the compiler does.

I haven't checked the compiler code for this but would bet that currently there is no step disallowing such an assignment.

xiio...@gmail.com

unread,
Aug 26, 2016, 3:38:11 PM8/26/16
to golang-nuts
As an aside - there is a complication to this if this (original post) were allowed/added to the language specification


var (
a  float32   = 1.0
aa []float32 = []float32{1.0, 2.0, 3.0}
)

b := float64(a)       //is ok
bb := ([]float64)(aa) //not ok

If the second conversion bb was allowed it would require a lot of extra magic work underneath -as a new slice would have to be created, large enough to store float64s - not just a case of changing the slice header to point at a new type.

So in reference to the original example - either extra code would have to be added to do this work, or these cases of type conversion would have to be dissallowed for slices.. Either way that's more compiler code, not less. 

Volker Dobler

unread,
Aug 26, 2016, 3:39:16 PM8/26/16
to golang-nuts, xiio...@gmail.com
Am Freitag, 26. August 2016 21:13:16 UTC+2 schrieb xiio...@gmail.com:
[...] I haven't checked the compiler code for this but would bet that currently there is no step disallowing such an assignment.

Well, there is. As you noticed you cannot assign []Age to []int because
the compiler complains. So by matter of fact there is a step which
disallows it.

I'm curiously following your post but I have to admit I cannot
make much sense of them. There is a language specification
which describes what is allowed and what not. That is not really
uncommon, there are specifications for most other languages
starting from what a Turing machine is and which transitions
are allowed to Brainfuck, various assembly languages, the whole
C-family with various dialect of C, C++, Java, the Lisp-family,
Haskell, you name it. All are governed by a specification and
none allows everything which might be technically feasible. Like
everything in life there are tradeoffs and different people make
different tradeoffs. The Go creators decided on a set of tradeoffs.
I think it is okay to ask _why_ it was decided this or that way, this
helps understanding the language and it's intentions. Several
people with deep understanding of the language itself and how it
is implemented explained to you the rationale behind various
decisions taken during the design of the language specification
and I'm feeling uncomfortable with your harsh rejections of any
explanation given. Especially if rejected based on guessing or
betting.

V.

Volker Dobler

unread,
Aug 26, 2016, 3:43:34 PM8/26/16
to golang-nuts
Ahhrg, sorry, sorry, sorry!
My reply to this message should have gone to the last one of user T L
not yours.

I'd like to blame the Web UI, but it was just me being lazy. Sorry.

V.

Am Freitag, 26. August 2016 21:13:16 UTC+2 schrieb xiio...@gmail.com:

mura

unread,
Aug 26, 2016, 9:06:00 PM8/26/16
to golang-nuts
Hi,

Generally speaking, you may find it a bit of struggling if you are trying to write Go code in an attempt to emulate *how* other languages can do, or to argue with the compiler about how a fresh learner would come to think in the first place. A tip for making the learning/adaption process smoother is to focus on *what* you want to achieve in the problem domain (instead of language domain, like fighting the compiler).

Veteran gophers would be most helpful if you ask about the specific functionalities or features you are trying to build. It's very likely that the language problems you encountered don't exist at all in other well-explored approaches.

T L

unread,
Aug 26, 2016, 11:09:49 PM8/26/16
to golang-nuts, tapi...@gmail.com

int64 and int (int32 and int) surely have different underlying types. I wouldn't deny this.
 

Ian

T L

unread,
Aug 26, 2016, 11:11:43 PM8/26/16
to golang-nuts, xiio...@gmail.com


On Saturday, August 27, 2016 at 3:38:11 AM UTC+8, xiio...@gmail.com wrote:
As an aside - there is a complication to this if this (original post) were allowed/added to the language specification


var (
a  float32   = 1.0
aa []float32 = []float32{1.0, 2.0, 3.0}
)

b := float64(a)       //is ok
bb := ([]float64)(aa) //not ok

If the second conversion bb was allowed it would require a lot of extra magic work underneath -as a new slice would have to be created, large enough to store float64s - not just a case of changing the slice header to point at a new type.

I don't think so. I think changing the slice header is enough. Doing more is strange.
 

T L

unread,
Aug 26, 2016, 11:14:09 PM8/26/16
to golang-nuts, xiio...@gmail.com

I don't deny the rules. I am just curious about the reason behind the rules.

I really don't like your attitude.
 

V.

T L

unread,
Aug 26, 2016, 11:15:46 PM8/26/16
to golang-nuts


On Saturday, August 27, 2016 at 9:06:00 AM UTC+8, mura wrote:
Hi,

Generally speaking, you may find it a bit of struggling if you are trying to write Go code in an attempt to emulate *how* other languages can do, or to argue with the compiler about how a fresh learner would come to think in the first place. A tip for making the learning/adaption process smoother is to focus on *what* you want to achieve in the problem domain (instead of language domain, like fighting the compiler).

Veteran gophers would be most helpful if you ask about the specific functionalities or features you are trying to build. It's very likely that the language problems you encountered don't exist at all in other well-explored approaches.


I'm not a new gopher.
In fact, I would be more a veteran gopher than you.
Sorry for saying this.
 

T L

unread,
Aug 26, 2016, 11:17:49 PM8/26/16
to golang-nuts


On Saturday, August 27, 2016 at 9:06:00 AM UTC+8, mura wrote:
Hi,

Generally speaking, you may find it a bit of struggling if you are trying to write Go code in an attempt to emulate *how* other languages can do, or to argue with the compiler about how a fresh learner would come to think in the first place. A tip for making the learning/adaption process smoother is to focus on *what* you want to achieve in the problem domain (instead of language domain, like fighting the compiler).

Veteran gophers would be most helpful if you ask about the specific functionalities or features you are trying to build. It's very likely that the language problems you encountered don't exist at all in other well-explored approaches.


And it is very appreciated if you can show the behind reason for "why can't []Age be converted into []int".
 

Ian Lance Taylor

unread,
Aug 26, 2016, 11:40:20 PM8/26/16
to T L, golang-nuts
On Fri, Aug 26, 2016 at 8:17 PM, T L <tapi...@gmail.com> wrote:
>
> On Saturday, August 27, 2016 at 9:06:00 AM UTC+8, mura wrote:
>>
>> Hi,
>>
>> Generally speaking, you may find it a bit of struggling if you are trying
>> to write Go code in an attempt to emulate *how* other languages can do, or
>> to argue with the compiler about how a fresh learner would come to think in
>> the first place. A tip for making the learning/adaption process smoother is
>> to focus on *what* you want to achieve in the problem domain (instead of
>> language domain, like fighting the compiler).
>>
>> Veteran gophers would be most helpful if you ask about the specific
>> functionalities or features you are trying to build. It's very likely that
>> the language problems you encountered don't exist at all in other
>> well-explored approaches.
>>
>
> And it is very appreciated if you can show the behind reason for "why can't
> []Age be converted into []int".

You have gotten several different answers to that question.

What kind of answer would you find satisfactory?

Ian

T L

unread,
Aug 26, 2016, 11:52:17 PM8/26/16
to golang-nuts, tapi...@gmail.com


No one have answered what is the behind reason for "why can't []Age be converted into []int" yet.

I don't think "rules disallow it, so it can't" is a good answer.
 

Ian Lance Taylor

unread,
Aug 27, 2016, 12:28:16 AM8/27/16
to T L, golang-nuts
> No one have answered what is the behind reason for "why can't []Age be
> converted into []int" yet.
>
> I don't think "rules disallow it, so it can't" is a good answer.

Many people have answered it, including me. Perhaps you missed my
answer; it is here:
https://groups.google.com/d/msg/golang-nuts/jDcUu4gUIRc/fX5pI66zFQAJ .

So, I'm sorry, but I have to ask again: what kind of answer would you
find satisfactory?

Ian

T L

unread,
Aug 27, 2016, 12:46:14 AM8/27/16
to golang-nuts, tapi...@gmail.com

I have read and replied your answer above.

And sorry I didn't convert all aspects in that reply.


> "..., which makes it hard to
understand what kind of answer you are looking for, and why you are
asking. Can you expand on that? "

Sorry, secret now. :)
Alternative answer: I'm curious on the details of Golang rules.


> "You are suggesting that there is an extra rule to forbids converting []T1 to
[]T2 when T1 and T2 have the same underlying representation."

No. I understand []T1 can't be converted to []T2 when T1 and T2 have different underlying representation.

Ok, the alternative of my question is: why []T2 and []T1 have different underlying representations when T2 and T1 have the same underlying representation?


> "despite the overall prohibition on converting []T1 to
[]T2, you are permitted to convert them exactly when T1 and T2 have
the same underlying representation.  That rule is much more complex
than the current rule.  It means that people reading Go code have to
understand when T1 and T2 have the same representation."

So you mean there is no implementation obstacles to allow converting []Age to []int?
The prohibition is just to make people less confused.

But the current prohibition make me confused, may I am not a typical gopher.





 

Ian Lance Taylor

unread,
Aug 27, 2016, 1:36:53 AM8/27/16
to T L, golang-nuts
On Fri, Aug 26, 2016 at 9:46 PM, T L <tapi...@gmail.com> wrote:
>
>> "You are suggesting that there is an extra rule to forbids converting []T1
>> to
> []T2 when T1 and T2 have the same underlying representation."
>
> No. I understand []T1 can't be converted to []T2 when T1 and T2 have
> different underlying representation.
>
> Ok, the alternative of my question is: why []T2 and []T1 have different
> underlying representations when T2 and T1 have the same underlying
> representation?

They don't.

If T2 and T1 have the same underlying representation, then []T2 and
[]T1 have the same underlying representation.


>> "despite the overall prohibition on converting []T1 to
> []T2, you are permitted to convert them exactly when T1 and T2 have
> the same underlying representation. That rule is much more complex
> than the current rule. It means that people reading Go code have to
> understand when T1 and T2 have the same representation."
>
> So you mean there is no implementation obstacles to allow converting []Age
> to []int?

That is correct.


> The prohibition is just to make people less confused.

I would say that it is to make the language simpler. There are fewer
things that people learning the language need to understand.


> But the current prohibition make me confused, may I am not a typical gopher.

Why does it make you confused?

On a 64-bit system, the types "int" and "int64" have the same
representation. They are both 64-bit signed integers. Does it
confuse you that Go rejects

var v int = int64(1)

?

If that does not confuse you, then the fact Go does not permit
assigning from []Age to []int should not confuse you. It is the same
kind of thing: in Go, different types are different.

Ian

xiio...@gmail.com

unread,
Aug 27, 2016, 2:21:38 AM8/27/16
to golang-nuts, tapi...@gmail.com

Ok, the alternative of my question is: why []T2 and []T1 have different underlying representations when T2 and T1 have the same underlying representation?


There is a difference - the compiler does not split slices and find the underlying representation of the non-slice part (example https://play.golang.org/p/hnjNkM77h7)

package main

type T1 string
type T2 T1
type T3 []T1
type T4 T3

type S1 T1
type S2 S1
type S3 []S1
type S4 S3

func main() {
var (
t3 T3
t4 T4
s3 S3
s4 S4
r  T1
)

a := T3(t3)
b := T4(t4)
c := T3(t4)
d := T4(t3)

e := T3(s3) //not allowed
f := T3(s4) //not allowed
z := S4(t4) //not allowed
//etc

r2 := S2(r)

v := S3(s3)
w := S4(s4)
x := S3(s4)
y := S4(s3)

The slice is treated as a type unto itself - that is why, in the examples cross conversion between slice types involving S and T fail. 

In the spec ( https://golang.org/ref/spec#TypeName ) types are defined. The relevant text on underlying types is "Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal"

Type      = TypeName | TypeLit | "(" Type ")" .
TypeName  = identifier | QualifiedIdent .
TypeLit   = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType . 

In the non slice type (eg String) this corresponds to TypeName, whereas in the slice (eg []String) example this corresponds to TypeLit (SliceType). The language specification does not state that type literals are further analysed for sub-type matches - so it does not happen.

I get that a common expectation is that a full recursive analysis of a TypeLiteral might happen, reducing each sub-element of the TypeLiteral to its lowest form - but it doesn't happen.


xiio...@gmail.com

unread,
Aug 27, 2016, 2:28:07 AM8/27/16
to golang-nuts
In the above 

"the compiler does not split slices and find the underlying representation"

should say

"the compiler does not split slices and find the underlying types"

There's a difference - I'm not referring to the way the data is stored, but the language specification. Hope that doesn't confused further

xiio...@gmail.com

unread,
Aug 27, 2016, 2:33:26 AM8/27/16
to golang-nuts
.. Maybe part of the confusion here is the difference between the representation of these slice types (ie in memory) and the definition of these slice types (in the language definition) - ?

They don't exactly align - it's the language specification that is 'the barrier' to conversion in simple cases such as slices made of elements with the same underlying types. The compiler is just matching the defined behaviour of the specification, whether or not going further would be easy to do.

xiio...@gmail.com

unread,
Aug 27, 2016, 2:46:05 AM8/27/16
to golang-nuts
Just an example to show that the compiler is not performing any sort of sub-type analysis, even on the simplest cases

T L

unread,
Aug 27, 2016, 3:41:34 AM8/27/16
to golang-nuts, tapi...@gmail.com

I don't think an int64 value can be converted to an int value is for they have the same underlying type.
In fact, an int8 value can also be converted to an int value.
"Number values can be converted to values of other number types" is totally an exception for the conversion rule.
This has nothing related to the underlying types.
 

T L

unread,
Aug 27, 2016, 3:45:23 AM8/27/16
to golang-nuts, tapi...@gmail.com

And another exception for the conversion rule is:
1. string values can be converted []byte values and vice versa.
2: string values can be converted []rune values and vice versa.

For almost every basic rule in goalng, there are some exceptions.
This is my impression for golang syntax rules.
 

amk...@gmail.com

unread,
Aug 27, 2016, 10:33:45 AM8/27/16
to golang-nuts, tapi...@gmail.com
Look at this example code from https://talks.golang.org/2012/goforc/celsius.go and you'll know why.

Although the underlying type of Celsius and Fahrenheit are the same - float32. There will be no meaning if the language allow you to convert these type to the underlying type float32. What's it mean for 0 = 273.15? (273.15K = 0°C).

Also, even for the Age type, I may use it for a person's age, you may use it for a virus' age.  
The person may live 100 years, but some virus may live only several hours. Although the 
underlying type is int, what does it mean when you compare a person's age with a virus' age? 

"A type determines the set of values and operations specific to values of that type." 
type Age is not the same as type int.

Andrew

T L

unread,
Aug 27, 2016, 11:28:39 AM8/27/16
to golang-nuts, tapi...@gmail.com, amk...@gmail.com

In this example, in fact, values of Celsius and Fahrenheit (including float32) can be converted to other types.
 

Andrew

T L

unread,
Aug 27, 2016, 12:04:32 PM8/27/16
to golang-nuts, tapi...@gmail.com, amk...@gmail.com
Up to now, the most convincing reason is "it is to make the language simpler" mentioned by Ian.

Maybe Ian is right. I have seen the following code in golang src:

type hmap struct {
    *[2]*[]*bmap
}

Maybe sometimes, it is really hard to judge if two types have a same underlying representation.

Michael Jones

unread,
Aug 27, 2016, 12:56:37 PM8/27/16
to T L, golang-nuts, amk...@gmail.com

TL, I have been confused by this thread, your similar questions, and in fact, most of your emails—until now.

 

When you write ‘Why can’t X’ as you often do, I have presumed that this was a casual and imprecise form of expressing the question “what is the reason why a different path was chosen.” Now, based on this, I see it differently. I think you mean it literally. I imagine myself walking beside you and you saying, “Why can’t trees be blue? Why can’t dogs have square heads? Why can’t cars have windows in the tires? Why don’t cats and pigs swim?” Which is to say, it seems that you are writing email as a way to share a stream of consciousness that every aspect of reality—every choice, decision, evolutionary outcome, taste, desire—could in fact be different in some other place or time or circumstance.

 

Now that the question unfolds as “Why is it not possible that X” (as you wrote from the start) then the answer to your emails is, “It is possible,” possible as in, “in a different language, with a different goal, on a hypothetical computer, if the most common programmer errors were not as they are, etc.” In engineering, nearly everything is possible. Not all of the possibilities are good, wise, or desirable though, so I think many here thought these other attributes were implied as part of your question. I did before but now do not.

 

In your spirit of “Why can’t” as in “prove that it is impossible” (of course such proofs are impossible), I offer examples of the uncommon but possible.

 

          

 

A different question, “Why is X disallowed in Go,” is actually much more educational. The example below, that was given you by amkguo, is the example that I thought of right at first—not about “why can’t bytes be interchangeable” but “why are Types treated as separate species.” This is a great topic. Because of huge human experience that mixing types by concept (adding two kinds of temperature or mass) results in unfortunate outcomes (many!) and similar experience in debugging as the result of many languages, C and C++ among them, doing natural-seeming invisible coercion between types. Type coercion in specific and invisible actions generally are a trouble area in large-scale software development. This is why the Go team (superstars with UNIX, C, major Gnu C/C++ implementation, Plan 9, Inferno, and maybe more importantly, careful study of common software development problems by 10,000+ programmers Google) disallowed it during the design of Go and instead require explicit casts (as in “var a int = 3; b := float64(a)”), why they treat Types as non-mixing species, and why the affordances around this are very limited.

 

I gave a talk in Madrid about Go as a software engineering approach assisted by a computer language. This seems a nice educational way to avoid many of the “but C allows …” or “it should be technically possible to…” confusions.

 

Michael

parais...@gmail.com

unread,
Aug 27, 2016, 1:25:16 PM8/27/16
to golang-nuts, xiio...@gmail.com
There are no subtypes in go, so no covariance or contravariance, which explained a lot of limitations of Go type system. The problem is that some level of covariance is hardcoded in the compiler (string to []byte ...)  which makes me think that go designers understand the value of it and know that there are cases where it is needed. It just the same problem as generics vs append. append is a generic function  of type append([]T,T...)[]T which behavior is hardcoded in the compiler instead of being generalized. Go designers understand the value of generics in that specific case without letting the user define their own functions with the exact same behavior.


All languages are opinionated, I think that adjective doesn't match Go features. Go is a language that is "restricted" but bear with me. 

The problem with being fine with that fact is that, while Go has these restrictions, Go allows a lot of dynamic behavior at runtime through reflection (with a speed cost, though caching definitely helps) which is a paradox for a statically typed language. The temptation of using reflection to work around language restrictions becomes huge every time one is confronted to these limitations.

It would be interesting to know if allowing(or not) reflection in userland was debated among Go designers at some point.

Regards.

T L

unread,
Aug 27, 2016, 1:41:14 PM8/27/16
to golang-nuts, tapi...@gmail.com, amk...@gmail.com


On Sunday, August 28, 2016 at 12:56:37 AM UTC+8, Michael Jones wrote:

TL, I have been confused by this thread, your similar questions, and in fact, most of your emails—until now.

 

When you write ‘Why can’t X’ as you often do, I have presumed that this was a casual and imprecise form of expressing the question “what is the reason why a different path was chosen.” Now, based on this, I see it differently. I think you mean it literally. I imagine myself walking beside you and you saying, “Why can’t trees be blue? Why can’t dogs have square heads? Why can’t cars have windows in the tires? Why don’t cats and pigs swim?” Which is to say, it seems that you are writing email as a way to share a stream of consciousness that every aspect of reality—every choice, decision, evolutionary outcome, taste, desire—could in fact be different in some other place or time or circumstance.

 

Now that the question unfolds as “Why is it not possible that X” (as you wrote from the start) then the answer to your emails is, “It is possible,” possible as in, “in a different language, with a different goal, on a hypothetical computer, if the most common programmer errors were not as they are, etc.” In engineering, nearly everything is possible. Not all of the possibilities are good, wise, or desirable though, so I think many here thought these other attributes were implied as part of your question. I did before but now do not.

 

In your spirit of “Why can’t” as in “prove that it is impossible” (of course such proofs are impossible), I offer examples of the uncommon but possible.

 

          

 

A different question, “Why is X disallowed in Go,” is actually much more educational. The example below, that was given you by amkguo, is the example that I thought of right at first—not about “why can’t bytes be interchangeable” but “why are Types treated as separate species.” This is a great topic. Because of huge human experience that mixing types by concept (adding two kinds of temperature or mass) results in unfortunate outcomes (many!) and similar experience in debugging as the result of many languages, C and C++ among them, doing natural-seeming invisible coercion between types. Type coercion in specific and invisible actions generally are a trouble area in large-scale software development. This is why the Go team (superstars with UNIX, C, major Gnu C/C++ implementation, Plan 9, Inferno, and maybe more importantly, careful study of common software development problems by 10,000+ programmers Google) disallowed it during the design of Go and instead require explicit casts (as in “var a int = 3; b := float64(a)”), why they treat Types as non-mixing species, and why the affordances around this are very limited.

 

I gave a talk in Madrid about Go as a software engineering approach assisted by a computer language. This seems a nice educational way to avoid many of the “but C allows …” or “it should be technically possible to…” confusions.

 

Michael


I never deny the great work made by golang team. In fact, I'm a go lover.
I just want to understand the reason for some golang syntax rules. :)
 

T L

unread,
Aug 27, 2016, 2:12:45 PM8/27/16
to golang-nuts, xiio...@gmail.com, parais...@gmail.com

I'm a performance guy. I never used the reflection feature. I also try to avoid using the zero method set interface{}.

Lacking generic is really a restriction for building high performance std libs.
But supporting genetic will make some std libs obsolete.
For user programs, it is acceptable for me to use third-party generic tools.

What I want most is the JIT feature, which will make golang enter the big data area.
 

Ian Lance Taylor

unread,
Aug 27, 2016, 11:00:53 PM8/27/16
to T L, golang-nuts
On Sat, Aug 27, 2016 at 12:41 AM, T L <tapi...@gmail.com> wrote:
>
> I don't think an int64 value can be converted to an int value is for they
> have the same underlying type.
> In fact, an int8 value can also be converted to an int value.
> "Number values can be converted to values of other number types" is totally
> an exception for the conversion rule.
> This has nothing related to the underlying types.

I'm sorry, I don't understand the point you are making.

Ian

T L

unread,
Aug 27, 2016, 11:26:09 PM8/27/16
to golang-nuts, tapi...@gmail.com

isn't the basic conversion rule is two values with a same underlying type can be converted to each other' type?
(another basic conversion rule is, if T implements interface I, the values of T can be converted to values of I)

The underlying types of different numeric types are different.
Golang just makes an exception/convenience to make it is possible to convert the values of these types to any of these types.

And there is another exception, integer values can be converted to string, this is one-direction conversion.


 

Dan Kortschak

unread,
Aug 28, 2016, 3:42:12 AM8/28/16
to Michael Jones, T L, golang-nuts
I think that your original interpretation of TL's questions is the
correct one, and the one that I read when I read all of this posts. I
don't think that it's a fair characterisation that he is asking about
possibility rather that design, even in the post that this was a reply
to.

I can understand his position entirely, and his frustration that might
lead to the epic threads that we see here. When I was starting to use
Go, I often asked questions about the motivation/reason behind
prohibitions or approaches in Go to be answered, extremely frustrating,
by references to the spec (I find understanding things unless I know why
they are the way they are - see Katrina Owen's great discussion about
knowledge construction and its graphical basis in "Mind the Gap" for why
rationale facilitates knowledge graph growth). This has improved here,
in that people now more often answer with design justifications, though
still there is a cultural habit or responding with essentially that it
is "because".

This would have been a significantly shorter thread if there had been a
clear explanation of the motivation behind slice conversion restrictions
early. This could have been after about the second (certainly by fourth)
post from TL where it became clear that he was asking about motivation
rather than mechanics (the initial post was ambiguous).

Dan
> A different question, “Why is X disallowed in Go,” is actually much
> more educational. The example below, that was given you by amkguo, is
> the example that I thought of right at first—not about “why can’t
> bytes be interchangeable” but “why are Types treated as separate
> species.” This is a great topic. Because of huge human experience that
> mixing types by concept (adding two kinds of temperature or mass)
> results in unfortunate outcomes (many!) and similar experience in
> debugging as the result of many languages, C and C++ among them, doing
> natural-seeming invisible coercion between types. Type coercion in
> specific and invisible actions generally are a trouble area in
> large-scale software development. This is why the Go team (superstars
> with UNIX, C, major Gnu C/C++ implementation, Plan 9, Inferno, and
> maybe more importantly, careful study of common software development
> problems by 10,000+ programmers Google) disallowed it during the
> design of Go and instead require explicit casts (as in “var a int = 3;
> b := float64(a)”), why they treat Types as non-mixing species, and why
> the affordances around this are very limited.
>
>
>
> I gave a talk in Madrid about Go as a software engineering approach
> assisted by a computer language. This seems a nice educational way to
> avoid many of the “but C allows …” or “it should be technically
> possible to…” confusions.
>
>
>
> Michael

--
Omnes mundum facimus.

Dan Kortschak <dan.ko...@adelaide.edu.au>
F9B3 3810 C4DD E214 347C B8DA D879 B7A7 EECC 5A40
10C7 EEF4 A467 89C9 CA00 70DF C18F 3421 A744 607C

xiio...@gmail.com

unread,
Aug 28, 2016, 6:37:08 AM8/28/16
to golang-nuts
agree with Korshak above

In fact T L's experience reminds me very much of probably my first experience with go .. I had read the specification completely, and I thought 'thoroughly' - then immediately tried this : https://play.golang.org/p/or1Ikhr4en

package main

import (
"fmt"
)

func main() {
var (
x, y, z *string = new(string), new(string), new(string)
b       []*string
)

str := "please parse this"

b = make([](*string), 3)

fmt.Sscan(str, x, y, z)
fmt.Sscan(str, b...) //doesn't work
fmt.Println("x", *x, "y", *y, "z", *z)

fmt.Println("b", b)
}

 the compile error is of course "cannot use b (type []*string) as type []interface {} in argument to fmt.Sscan" - 

variadics are clear example of why allowing the suggested type conversion on slices of convertible types would actually be useful..

I've been tempted to request this before, but in the end just moved on.

(maybe there's an obvious way to accomplish the above I've missed ?)

[aide] Doing/allowing type conversions on other type literals is probably a BAD idea - structs for example coul/would rapidly become difficult - the beginnings of the types of problems possible is easily represented with this simple 'program' https://play.golang.org/p/dmDty3iTk0 - would A and B be considered convertable - trivial on inspection by a human, but difficult to program for - even more so with additional layers of redirection, with definition loops - looks like a difficult thing to parse, with little, no, or negative benefits -mostly massive opportunities for confusion.

Ian Lance Taylor

unread,
Aug 29, 2016, 1:19:46 AM8/29/16
to T L, golang-nuts
On Sat, Aug 27, 2016 at 8:26 PM, T L <tapi...@gmail.com> wrote:
>
> On Sunday, August 28, 2016 at 11:00:53 AM UTC+8, Ian Lance Taylor wrote:
>>
>> On Sat, Aug 27, 2016 at 12:41 AM, T L <tapi...@gmail.com> wrote:
>> >
>> > I don't think an int64 value can be converted to an int value is for
>> > they
>> > have the same underlying type.
>> > In fact, an int8 value can also be converted to an int value.
>> > "Number values can be converted to values of other number types" is
>> > totally
>> > an exception for the conversion rule.
>> > This has nothing related to the underlying types.
>>
>> I'm sorry, I don't understand the point you are making.
>>
>> Ian
>
>
> isn't the basic conversion rule is two values with a same underlying type
> can be converted to each other' type?

Yes, if by "same underlying type" you mean "identical underlying type".

In the original question of why you can't convert []Age to []int,
[]Age and []int are not identical underlying types.


> (another basic conversion rule is, if T implements interface I, the values
> of T can be converted to values of I)

Yes, that is true.

> The underlying types of different numeric types are different.
> Golang just makes an exception/convenience to make it is possible to convert
> the values of these types to any of these types.
>
> And there is another exception, integer values can be converted to string,
> this is one-direction conversion.

Yes, there are two different kinds of conversions: ones that do not
change the value, and ones that change the value. It is perhaps
unfortunate that they use the same syntax.


I asked a question earlier, but I don't think you ever answered it.
It's an important question. The question is: what kind of answer
would you find satisfactory?

Right now you seem to repeat the question in different ways, and none
of the answers seem to get anywhere. So I feel that we need to step
back and understand what kind of answer you are looking for.

Ian

Ian Lance Taylor

unread,
Aug 29, 2016, 1:40:51 AM8/29/16
to Dan Kortschak, Michael Jones, T L, golang-nuts
On Sun, Aug 28, 2016 at 12:41 AM, Dan Kortschak
<dan.ko...@adelaide.edu.au> wrote:
>
> This would have been a significantly shorter thread if there had been a
> clear explanation of the motivation behind slice conversion restrictions
> early. This could have been after about the second (certainly by fourth)
> post from TL where it became clear that he was asking about motivation
> rather than mechanics (the initial post was ambiguous).

I apologize for a pedantic response, but there are no slice conversion
restrictions. I agree that it's a little confusing, because
conversions are permitted among numeric types (and there are a couple
of other value-changing conversions, like between string and []byte).
As soon as you get into composite types (slices, arrays, structs,
maps, channels, functions) the rule is fairly simple: conversions are
permitted if the types have identical underlying types.

So I think the question you are asking (I honestly don't know what
question TL is asking) is: if T1 and T2 are both defined to have
identical underlying types, then why not permit conversions between
composites involving T1 and T2? Why not permit converting []T1 to
[]T2? Why not permit converting func(T1) T2 to func(T2) T1? Why not
permit converting struct { f1 T1; f2 T2 } to struct { f1 T2; f2 T1}?

In Go, types are closely tied to methods. Every type has a method
set. Another way of stating the rule for conversions between
composite types is that you can change the method set of the type
being converted (by converting to a different type, with different
methods, that has the same underlying type) but you can't change the
method set of elements of the composite.

As to why Go has that restriction, I would say that it is simply
because 1) it is conservative--people are unlikely to get into
accidental trouble; 2) real programs rarely seem to need to do this
kind of conversion.

I want to be clear here: real program do often want to do a different
kind of conversion: between interfaces with methods with different
result types, to support covariant and contravariant types. That is
not what we are talking about here. That would be difficult to
implement for reasons that have been discussed elsewhere. The
question I am addressing is why Go doesn't permit conversions between
composite types built out of non-identical types with the same
underlying type. I am asserting that that is not common in real
programs.

Ian

Ian Lance Taylor

unread,
Aug 29, 2016, 1:44:15 AM8/29/16
to Xio Fen, golang-nuts
On Sun, Aug 28, 2016 at 3:36 AM, <xiio...@gmail.com> wrote:
>
> In fact T L's experience reminds me very much of probably my first
> experience with go .. I had read the specification completely, and I thought
> 'thoroughly' - then immediately tried this :
> https://play.golang.org/p/or1Ikhr4en
>
> package main
>
> import (
> "fmt"
> )
>
> func main() {
> var (
> x, y, z *string = new(string), new(string), new(string)
> b []*string
> )
>
> str := "please parse this"
>
> b = make([](*string), 3)
>
> fmt.Sscan(str, x, y, z)
> fmt.Sscan(str, b...) //doesn't work
> fmt.Println("x", *x, "y", *y, "z", *z)
>
> fmt.Println("b", b)
> }
>
>
> the compile error is of course "cannot use b (type []*string) as type
> []interface {} in argument to fmt.Sscan" -
>
> variadics are clear example of why allowing the suggested type conversion on
> slices of convertible types would actually be useful..

I want to make clear that I do not think this is what TL was
discussing. I think TL was asking about conversions of slices where
the element types have the same underlying type, not where the
elements types are convertible.

I completely agree that allowing type conversions between slices of
convertible types would be useful. This is not currently permitted
because it requires an implicit loop at run-time. It means that a
conversion from []T1 to []T2, although it looks like a simple change
of representation, actually requires a loop over all the elements in
the slice.

Ian

Dan Kortschak

unread,
Aug 29, 2016, 1:50:36 AM8/29/16
to Ian Lance Taylor, Xio Fen, golang-nuts
It seems to me that this comes up often enough that it satisfies the
definition of a FAQ. I know that
https://golang.org/doc/faq#convert_slice_of_interface is commonly
pointed to as an explanation, but it is not entirely satisfactory since
it is talking about the specific case of []T to []interface{} while
commonly people want to know about []T1 to []T2 where T1 and T2 are
derived from T, so another answer is probably warranted.

Dan Kortschak

unread,
Aug 29, 2016, 1:54:07 AM8/29/16
to Ian Lance Taylor, Michael Jones, T L, golang-nuts
Clarifying: I'm not asking a question. However, the explanation is a
good one. It could form the basis for a FAQ answer.
Message has been deleted

Dan Kortschak

unread,
Sep 4, 2016, 9:52:31 PM9/4/16
to nicolas riesch, golang-nuts
On Fri, 2016-09-02 at 13:47 -0700, nicolas riesch wrote:
> In your original example, if you don't cast, it works.
>
> https://play.golang.org/p/g-GScYkA5S

That is not doing what the OP wanted though; they wanted a []int.

https://play.golang.org/p/YpyYXIu9D2


> The explanation is here:
>
> https://groups.google.com/forum/#!topic/golang-nuts/x3nOMDCLv5M

This is a differnt thing.

https://play.golang.org/p/JKgJCeXRQM

Reply all
Reply to author
Forward
0 new messages