Surprising assignment behavior for type definitions in Go

According to the go specification on a type definition

The new type is called a defined type. It is different from any other type, including the type it is created from.

Also

A defined type is always different from any other type

I would expect that if I have a variable of a type definition Foo, only values of type Foo should be assignable to it and never values of the underlying type or any other type.
This is one of the main reasons to use a type definition in the first place, i.e I don’t want to accept any arbitrary values of the underlying type since that would likely be due to a bug on the calling side.

But that doesn’t seem to be the case in Go. see the following example where I have a type Foo with underlying type string. The compiler lets me pass in any string when the string is passed as a literal (but not if the passed value is of already type string? which seems arbitrary).

package main

func main() {
  type Foo string
  f := func(t Foo) {}
  
  f(Foo("abc")) // Works fine as expected.

  f("abc") // Works unexpectedly. Expected a type error.

  var s = "abc"
  f(s) // Type error as expected
}

Surely this isn’t a feature? If so, the behavior doesn’t seem to match the specification.

Hi, @auste, See the section in the specification on Constants. Jayts and I provided explanations specifically about numeric values in another question here, but my answer also has an example using strings which is particularly applicable to your case.

1 Like

I see, I had never heard of the term untyped constants until now and its quite unfortunate that this is allowed :stuck_out_tongue:
Thanks for the response!

@auste There are workarounds. If you don’t want string literals to be useable as Foos, turn Foo into a struct: https://play.golang.org/p/cVhNn33Wt4t

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.