Doubt regarding the conversion of an untyped constant '\n' into a byte

I was watching this talk given at FOSDEM '17 about implementing “tail -f” in Go => https://youtu.be/lLDWF59aZAo

In the author’s initial example program, he creates a Reader using a file handle, and then uses the ReadString method with delimiter ‘\n’ to read the file line by line and print its contents.

Program below

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	fileHandle, err := os.Open("someFile.log")
	if err != nil {
		log.Fatalln(err)
		return
	}
	defer fileHandle.Close()

	reader := bufio.NewReader(fileHandle)

	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			log.Fatalln(err)
			break
		}
		fmt.Print(line)
	}

}

Now, ReadString takes a byte as its delimiter argument[https://golang.org/pkg/bufio/#Reader.ReadString]

So my question is, how in the world did ‘\n’, which is a rune, get converted into a byte? I am not able to get my head around this. Especially since byte is an alias for uint8, and rune is an alias for int32.

I asked the same question in Gophers slack, and was told that ‘\n’ is not a rune, but an untyped constant. If we actually created a rune using ‘\n’ and passed it in, the compilation would fail. This actually confused me a bit more.

I was also given a link to a section of the Go spec regarding Type Identity => https://golang.org/ref/spec#Type_identity

If the program is not supposed to compile if it were an actual rune, why does the compiler allow an untyped constant to go through? Isn’t this unsafe behaviour?

My guess is that this works due to a rule in the Assignability section in the Go spec (golang.org/ref/spec#Assignability), which says

x is an untyped constant representable by a value of type T.

Since ‘\n’ can indeed be assigned to a variable of type byte, it is therefore converted.

Is my reasoning correct?

Thanks,
Krishna Kishore Shetty

1 Like

Pretty much, yes. Constants in Go are untyped, and '\n' is just a numeric constant with the value 10. It can be assigned to any numeric type.

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

It is not a rune constant like it would have been in some other languages (called char there, probably). You can declare a rune constant though:

const newline rune = '\n'

That can’t be passed to a function expecting a byte without conversion.

1 Like

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