Golang not able to detect implicitly typed const when assigning to a variable - go

When I try to assign an implicitly typed constant to a variable, the assigned variable doesn't detect the custom type and instead gets assigned as the underlying primitive type. i.e;
For:
type Custom string
const (
First Custom = "10"
Second = "20"
)
If I have a function:
func SomeFunc( x Custom) {
fmt.Printf("Inside func %v %v", x, reflect.TypeOf(x))
}
Then when I:
out := Second
SomeFunc(out)
it errors with:
cannot use out (type string) as type Custom in argument to SomeFunc
However SomeFunc(Second) works fine.
Also
fmt.Printf("%v %v\n",reflect.TypeOf(second),reflect.TypeOf(out)) //prints string string
Here is the reproducer: https://play.golang.org/p/Iv-C1ee992
Can someone help me understand what is happening here?

Second is an untyped const and has this property (https://blog.golang.org/constants):
An untyped constant is just a value, one not yet given a defined type
that would force it to obey the strict rules that prevent combining
differently typed values.
...
Assigning them to a variable of any type compatible with strings works
without error.
On the contrary out is a variable of type string. Again from the blog post:
and by now you might be asking, "if the constant is untyped, how does
str get a type in this variable declaration?" The answer is that an
untyped constant has a default type, an implicit type that it
transfers to a value if a type is needed where none is provided. For
untyped string constants, that default type is obviously string

Related

GoLang: why doesn't address-of operator work without a variable declaration

In Go, suppose I have a []byte of UTF-8 that I want to return as a string.
func example() *string {
byteArray := someFunction()
text := string(byteArray)
return &text
}
I would like to eliminate the text variable, but Go doesn't support the following:
func example() *string {
byteArray := someFunction()
return &string(byteArray)
}
Is this second example syntax correct? And if so, why doesn't Go support it?
Because the spec defines is that way:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
Notice that type conversions (what you are trying to do with string(byteArray)) are not included in this list.
See Marc's answer for an official citation, but here's an intuitive reason for why Go doesn't support this.
Suppose the following code
var myString string
stringPointer := &myString
*stringPointer = "some new value"
Hopefully you know, this code will write some new value into myString. This is a basic use of pointers. Now consider the modified example (pretending that it is valid code):
var myBytes []byte
// modify myBytes...
stringPointer := &string(myString)
*stringPointer = "some new value"
The question is, where in the world (or computer) are we writing to?? Where is some new value going?
In order for the language to handle this correctly, the compiler would need some internal process to "promote" the temporary value to an invisible variable, and then take the address of that. This would be adding needless complexity to make some code slightly shorter, but create this confusing situation where we have pointers with no well defined location in the program. Instead of creating these confusing ghost-variables, the language delegates to the programmer to use their own variable as usual.

Is it possible to have interface composite literals in Go?

I just want to confirm if my understanding is correct about interface{}{}
Does interface{}{} mean a composite literal of interface type?
So, if I wanted to pass a composite type, lets say []byte as a interface{}, I should assign it to a variable of type interface{}{} and pass in that variable, whereas if I wanted to pass a non composite type, such as a int as a interface{}, I should assign it to a variable of type interface{} and pass in that variable.
Is my understanding correct on this?
interface{}{} is invalid syntax.
It is not an empty interface composite literal — there's no such thing. The following don't compile:
var a interface{}{} = "foo" // not a type
b := interface{}{} // not a value
From the specs Composite Literals:
Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated.
The valid syntax is interface{}, which is the empty interface, i.e. an interface with no name and empty method set.
If you compare it to a named interface, you will see that the extra set of curly braces at the end makes no sense:
type Fooer interface {
Foo() error
}{} // ???
You can instantiate an empty interface{} by converting nil:
a := (interface{})(nil)
Or you can declare a var of unnamed interface type:
type A struct {}
func (a A) Foo() string {
return "foo"
}
var a interface{ Foo() string } = A{}
To answer your question:
So, if I wanted to pass a composite type [...]
you can assign any value to a variable of type interface{}, that's about it. Whether the value is composite or not is irrelevant because all types satisfy the empty interface:
var a interface{} = []byte{0x01, 0x02}
var b interface{} = "string_literal"
Playground: https://play.golang.org/p/w-l1dU-6Hb5
The empty interface interface{} essentially says "I don't care". Anything can be passed as an empty interface. So for your examples they all could be stored as the empty interface.
Possibly a more interesting question is why you want to avoid types in the first place, and what you're trying to achieve. But for the purposes of using interface{} you can pass anything to it, even a "nil".
interface{} type of empty interface.
you assign []byte or int to any empty variable of empty interface (interface{} type) or you can pass it directly to function that exepts interface values.

Assertion of zero int to int32

I noticed that Go assertion doesn't work as I expect for zero int. Here is the code:
var i interface{}
i = 0
i32, ok := i.(int32)
fmt.Println(ok)
fmt.Println(i32)
The output is following:
false
0
I can't find an explanation of this behavior. Is it a bug?
i doesn't contain an int32, it contains an int, and so the type assertion fails.
Assigning a literal value directly to an interface{} like this or using one in a short variable declaration can be a bit confusing because you don't really get to see what type of value you get; you need to know the rules for the "default type" of a constant. If this gives you trouble, you can explicitly cast it to a type, like
i = int32(0), which will ensure that i does in fact contain an int32.
No, it's not a bug, it's a well defined behavior.
This line:
i = 0
Is an assignment, and you use the untyped 0 integer constant to assign to i. Since a (concrete) type is needed to carry out the assignment (and is type being interface{} does not define one), the default type of that untyped constant will be used which is int. Read The Go Blog: Constants:
The answer is that an untyped constant has a default type, an implicit type that it transfers to a value if a type is needed where none is provided.
You can verify it if you modify it like this:
i2, ok := i.(int)
fmt.Println(ok)
fmt.Println(i2)
Which outputs:
true
0
If you would use a typed constant:
i = int32(0)
Then yes, the stored value would be of type int32, and you would get the same output:
i = int32(0)
i32, ok := i.(int32)
fmt.Println(ok)
fmt.Println(i32)
Try the examples on the Go Playground.

Why `fmt.Println("%T\n", e)` where `e` is an error variable prints out <nil> and not its type?

I was recently playing with the Go language and I bumped into something a bit weird to say the least, let's consider a very simple function:
func main() {
n, e := fmt.Println(`He said: "Hello"`)
fmt.Printf("%T\n", n)
}
Which outputs what I was expecting:
He said: "Hello"
int
Now if I want to display the type of e:
func main() {
n, e := fmt.Println(`He said: "Hello"`)
fmt.Printf("%T\n", e)
}
and this time prints out:
He said: "Hello"
<nil>
I get the part that there is no error so e is an empty pointer: nil but I would have not expected to be a ~~type~~ on its own.
Why am I not getting the actual type?
If so, is there a workaround? (not saying my use case is a realistic one but curious if there is any possibility)
The Go Programming Language Specification
Errors
The predeclared type error is defined as
type error interface {
Error() string
}
It is the conventional interface for representing an error condition,
with the nil value representing no error.
Interface types
An interface type specifies a method set called its interface. A
variable of interface type can store a value of any type with a method
set that is any superset of the interface. Such a type is said to
implement the interface. The value of an uninitialized variable of
interface type is nil.
The zero value
When storage is allocated for a variable, either through a declaration
or a call of new, or when a new value is created, either through a
composite literal or a call of make, and no explicit initialization is
provided, the variable or value is given a default value. Each element
of such a variable or value is set to the zero value for its type: nil
for interfaces.
A zero-value error type, an interface, has no type.Its value is nil.
e is an empty pointer
Nope, error itself - interface, so you won't have type here.

Object instantiation by reference

Here is a sample of Go code which I do not really understand:
type MyClass struct {
field1 string
field2 string
}
...
objectinstance1 := MyClass{field1:"Hello", field2:"World"}
objectinstance2 := &MyClass{field1:"Hello", field2:"World"}
I can do exactly the same thing with objectinstance1 and objectinstance2 (method call for example) with the same syntax.
So I do not understand the role of the & operator. What I understand is that objectinstance1 contains an object whereas objectinstance2 contains a pointer.
It is for me the same thing in C than the difference between char and char*.
But in this case I should use -> instead of . (dot)?
The & operator gives you a pointer to a struct, while not using it gives you the struct value.
The biggest place this is relevant is when you pass this struct over to another function - if you pass the pointer that you made using the & operator, the other function has access to the same struct. If that function changes it, you've got the changed struct as well.
If you pass the variable that you made without the & operator, the function that you pass it to has a copy of the struct. There is nothing that that function or any other function can possibly do to change what you see in your variable.
This effectively makes the value variable safe for use across multiple go routines with no race conditions - everyone has their own copy of the struct.
If you pass the pointer made with & to other go routines, all have access to the same struct, so you really want that to be intentional and considered.
Difference is not visible because it’s hidden in 2 things:
Operator := which assigns value and type for a variable simultaneously. So it looks like objectinstance1 and objectinstance2 are the same. But in fact first is a MyClass instance and second is a pointer to it. It will be more palpable if use long-form operator:
var objectinstace1 MyClass = MyClass{}
var objectinstance2 *MyClass = &MyClass{}
If you omit * or & variable and type become incompatible and assignment fails.
Implicit pointer indirection. Go does it automatically in statements like ptr1.Field1 to access a specific field in struct by pointer to it.
Only on rare cases when there’s ambiguity you have to use full form:
*ptr1.Value1
or sometimes even:
(*ptr1).Value1
UPDATE:
Explicit pointer usage for disambiguation:
type M map[int]int
func (m *M) Add1() {
// this doesn't work - invalid operation: m[1] (type *M does not support indexing)
// m[1] = 1
// the same - invalid operation: m[1] (type *M does not support indexing)
// *m[1] = 1
// this works
(*m)[1] = 1
}
https://play.golang.org/p/JcXd_oNIAw
But in this case i should use -> instead of . (dot) ?
No. Golang is not C is not Golang. In Golang there is no ->. You use dot (.) for pointers aswell. Golang is meant to be simple, there is no point in introducing another operator if the intention is clear (what else would . on a pointer mean than calling a method?)
In go, the & operator takes the address of its argument and returns a pointer to the type of the argument.
Pointer indirection happens automatically so there is no -> operator, the dot operator handles all field (member) operations and accesses for all types, whether a pointer or a struct.
package main
import (
"fmt"
"reflect"
)
func main() {
type Foo struct{ name string }
foo1 := Foo{"Alpha"} // A plain struct instance.
foo2 := &Foo{"Bravo"} // A pointer to a struct instance.
fmt.Printf("foo1=%v, name=%v\n", reflect.TypeOf(foo1), foo1.name)
fmt.Printf("foo2=%v, name=%v\n", reflect.TypeOf(foo2), foo2.name)
// foo1=main.Foo, name=Alpha
// foo2=*main.Foo, name=Bravo
}

Resources