strict type assignability to prevent arbitrary values

177 views
Skip to first unread message

bsr

unread,
Nov 7, 2019, 5:58:17 AM11/7/19
to golang-nuts
Hello,

I am a long time user of go, but I always had the impression that below code would not work as string and Status are different type.
I thought I need to explicitly convert as ```exec(Status("abc"))``` it to work.

I think, this part of the spec may be the reason https://golang.org/ref/spec#Assignability
Is there a way I can prevent this behavior.
I am using Status like an enum, and only predefined status values should be allowed.





package main

import (
    "fmt"
)

type Status string

func main() {
    exec("abc")
}

func exec(s Status) {
    fmt.Printf("Hello, %s", s)
}

Jan Mercl

unread,
Nov 7, 2019, 6:32:06 AM11/7/19
to bsr, golang-nuts
On Thu, Nov 7, 2019 at 11:58 AM bsr <bsr...@gmail.com> wrote:

> Is there a way I can prevent this behavior.

Yes, if the rules for untyped literals are not wanted, make the
literal typed: https://play.golang.org/p/-f75y0Gb1Is

speter

unread,
Nov 7, 2019, 8:15:20 AM11/7/19
to bsr, golang-nuts
Hi bsr,

I'd suggest to use a struct type with a single string field. It will prevent conversion from untyped string constant "by mistake".
Moreover, if you make the string field unexported, you can limit new instance creation to the declaring package, allowing to enforce predefined values.
Unlike with some other languages, there is no memory or runtime overhead due to encapsulating the string within a struct.

HTH,
Peter

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/a20a7034-19c3-410a-bc86-25deff38534f%40googlegroups.com.

bsr

unread,
Nov 7, 2019, 9:10:27 AM11/7/19
to golang-nuts
Thanks Jan & Peter. I would use one of the approaches.
To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Mohamed Yousif

unread,
Nov 7, 2019, 12:02:33 PM11/7/19
to speter, bsr, golang-nuts
Hi Speter,

Can you elaborate more on this point please?
there is no memory or runtime overhead due to encapsulating the string within a struct.

Jake Montgomery

unread,
Nov 8, 2019, 12:30:46 PM11/8/19
to golang-nuts
The inability to have a type safe enum in Go has bothered me as well.

While using a struct, as Peter suggests, does prevent accidental use of literals, it also prevents you from making your enum items constant.This means that the values can be changed, accidentally, or intentionally, in another package. For example:

package enum

import "fmt"

type
Status struct {
    s
string
}

var One = Status{"one"}
var Two = Status{"two"}

func
PrintIt(stat Status) {
    fmt
.Println("Status is", stat.s)
}

But a client of your package can then do:

func Foo() {

   
enum.One = enum.Two
   
enum.PrintIt(enum.One)

}

Which will print "two", and perminantly alter the meaning of enum.One.


On Thursday, November 7, 2019 at 8:15:20 AM UTC-5, speter wrote:
To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Michael Jones

unread,
Nov 8, 2019, 12:35:40 PM11/8/19
to Jake Montgomery, golang-nuts
...job for a getter function.

To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/9df8504c-4309-43ab-86ee-518b52eb2e2f%40googlegroups.com.


--
Michael T. Jones
michae...@gmail.com

speter

unread,
Nov 8, 2019, 7:38:11 PM11/8/19
to Mohamed Yousif, bsr, golang-nuts
Hi Mohamed,

The memory layout of "string" is the same as that of "struct { string }", so there is no extra allocation or indirection involved on creation and access, hence no runtime overhead.

Peter

Wojciech S. Czarnecki

unread,
Nov 10, 2019, 12:37:54 PM11/10/19
to golan...@googlegroups.com
On Thu, 7 Nov 2019 02:58:17 -0800 (PST)
bsr <bsr...@gmail.com> wrote:

> Is there a way I can prevent this behavior.
> I am using Status like an enum, and only predefined status values should be allowed.

You cannot statically prevent someone from willfully assigning
to a variable of accessible type (eg. a function call parameter).
If you're just after sanity check there are many ways.

At runtime you can eg. use a map: https://play.golang.org/p/5rwJLFpU3a4

For compile time - you can use stringer tool to generate numerical constants mapped to strings.

hope this helps,

--
Wojciech S. Czarnecki
<< ^oo^ >> OHIR-RIPE
Reply all
Reply to author
Forward
0 new messages