Why are 'new' and 'make' not reserved keywords? - go

With syntax highlighting enabled, it's distracting while reading code like answer to this question with new used as a variable name.
I'm trying to think of a reason why only a subset of keywords would be reserved and can't come up with a good one.
Edit: Alternate title for this question:
Why are Go's predeclared identifiers not reserved ?

That's because new and make aren't really keywords, but built-in functions.
If you examine the full list of the reserved keywords, you won't see len or cap either...

In short: because using predeclared identifiers in your own declarations don't make your code ambiguous.
new and make are builtin functions, amongst many others. See the full list in the doc of the builtin package.
Keywords are a carefully chosen small set of reserved words. You cannot use keywords as identifiers because that could make interpreting your source ambiguous.
Builtin functions are special functions: you can use them without any imports, and they may have varying parameter and return list. You are allowed to declare functions or variables with the names of the builtin functions because your code will still remain unambiguous: your identifier in scope will "win".
If you would use a keyword as an identifier, you couldn't reach your entity because an attempt to refer to it by its name would always mean the keyword and not your identifier.
See this dirty example of using the predeclared identifiers of the builtin function make and the builtin type int (not recommended for production code) (try it on the Go Playground):
make := func() string {
return "hijacked"
}
int := make() // Completely OK, variable 'int' will be a string
fmt.Println(int) // Prints "hijacked"
If you could use keywords as identifiers, even interpreting declarations would cause headache to the compiler: what would the following mean?
func() - is it calling your function named func or is it a function type with no params and no return types?
import() - is it a grouped import declaration (and importing nothing) or calling our function named import?
...

Related

Function with 1/2 values and short variable declaration assigned twice to same variable

I have two questions for following code
emptyinterface.(int) can return one or two values, how the function is defined to achieve that effect?
ok has been declared twice using short variable declaration, why it is possible in this context?
package main
import (
"fmt"
)
func main() {
var emptyinterface interface{}
emptyinterface=4
i1:=emptyinterface.(int)
fmt.Println(i1)
i2,ok:=emptyinterface.(int)//<- how the function is defined such that it can return either 1 (i1) or 2 values (i2,ok)?
fmt.Println(i2,ok)
i3,ok:=emptyinterface.(string) //<--why I can reassign to ok, which has assign previously?
fmt.Println(i3,ok)
}
It's not a function, it's a language feature. You can't write a function that does that, but the compiler writers can create a bit of syntax that does.
A := is invalid if there are no new variables on its left side. If there is at least one new variable being declared, it's allowed.
In each of the cases, there is at-least new variable created along with ok, i.e. i2 and i3, so redeclaration of ok is perfectly fine.
This is well documented in the language spec (emphasis mine) under Short variable declarations
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration.
Also it is unclear, what you are referring as a function here, Type assertion is a feature of the language that asserts if a value within the interface is of a particular type. It always returns the underlying value if the assertion was successful or a failure if its not. You should always be checking the return value of the type assertion (2nd argument) before meaningfully using it elsewhere.

Assigning types to variables in Go

How to have a variable whose type is a variable type?
What do I mean by that? I have a python and java background. In both languages I can do things like assigning a class name to variable.
#Python
class A:
def __init__(self):
self.a = "Some Value"
# And asigning the class name to a variable
class_A = A
# And create instance from class A by using class_A
a = class_A()
Is there such a mechanism in go that allows me to do that? I couldn't know where to look at for such things in their documentation. Honestly, generally I don't know what these are called in programming languages.
For example I would like to be able to do:
// For example, what would be the type of myType?
var myType type = int
I will use this mechanism to take "type" arguments. For example:
func Infer(value interface{}, type gotype) {...}
Is there such a mechanism in go that allows me to do that?
The short answer is: No.
The long answer is: This sounds like an XY Problem, so depending on what you're actually trying to accomplish, there may be a way. Jump to the end to see where I address your specific use-case.
I suspect that if you want to store a data type in a variable, it's because you either want to compare some other variable's type against it, or perhaps you want to create a variable of this otherwise unknown type. These two scenarios can be accomplished in Go.
In the first case, just use a type switch:
switch someVar.(type) {
case string:
// Do stringy things
case int:
// Do inty things
}
Semantically, this looks a lot like assigning the type of someVar to the implicit switch comparison variable, then comparing against various types.
In the second case I mentioned, if you want to create a variable of an unknown type, this can be done in a round-about way using reflection:
type := reflect.TypeOf(someVar)
newVar := reflect.New(type).Interface()
Here newVar is now an interface{} that wraps a variable of the same type as someVar.
In your specific example:
I will use this mechanism to take "type" arguments. For example:
func Infer(value interface{}, type gotype) {...}
No, there's no way to do this. And it actually has much less to do with Go's variable support than it does with the fact that Go is compiled.
Variables are entirely a runtime concept. Function signatures (like all other types in Go) are fixed at compilation time. It's therefore impossible for runtime variables to affect the compilation stage. This is true in any compiled language, not a special feature (or lack thereof) in Go.
Is there such a mechanism in go that allows me to do that?
No there is not.
Use the empty interface:
var x, y interface{}
var a uint32
a = 255
x = int8(a)
y = uint8(a)
Playground example

Changing behavior based on number of return arguments like type assertions

I've been learning Go and one thing that stood out as particularly interesting to me is the way that the behavior of type assertions changes based on how many return values are being captured:
var i interface{} = "hello"
val, ok := i.(int) // All good
fmt.Println(val, ok)
val = i.(int) // Panics
fmt.Println(val)
This feels like a pattern that can be very useful for user defined functions. The user either has to explicitly get the "ok" second return value or use an underscore to ignore it. In either case, they're making it clear that they're aware that the function can fail. Whereas if they just get one return value, it could silently fail. Hence, it seems reasonable to panic or similar if the user isn't checking for an error (which would be reasonable if the error should "never" happen). I assume that's the logic behind the language developers in making type assertions work this way.
But when I tried to find out how that could be done, I found nothing. I'm aware that type assertions aren't an actual function. And many languages with multiple return values can't check how many return values are actually being used (MATLAB is the only one I'm aware of), but then again, most of those don't use behavior like the type assertions demonstrate.
So, is it possible and if so, how? If not, is there a particular reason that this behavior was excluded despite it being possible with the built in type assertions?
Sadly they cannot be used in normal functions. As far as i know only type assertions, map value access and range allow it.
Usually when you want to have a function with one and optional a second error argument you name them like
func DoSomething() (string, error) {...} // i will return an error
func MustDoSomething() string {...} // i will panic
An example would be https://golang.org/pkg/regexp/#MustCompile
This answer: https://stackoverflow.com/a/41816171/10278 by #christian provides the best practical advice for how to emulate the "overloaded-on-result-count" pattern.
My aim is to address another part of the question—this part: "But when I tried to find out how that could be done, I found nothing".
The following explains how it is done for Go type assertions.
Invocations of type assertions in Go behave as though they are overloaded based on number of results.
Yet, Go does not support overloading of methods and operators.
Looking at Go's implementation, here is the reason type assertions appear to be overloaded based on number of results:
The Go compiler provides special handling that is peculiar to these built-in operations.
This special dispatching occurs for the built-in concept of type assertions because the compiler is carving out special logic that is not available to non-built-in code.
The Go compiler and runtime are written in Go. That made it (somewhat) easy for me to discover that the compiler is the key to explaining this behavior.
Take a look at this part of the compiler:
https://github.com/golang/go/blob/8d86ef2/src/cmd/compile/internal/gc/ssa.go#L4782
The code comment already reveals a lot:
// dottype generates SSA for a type assertion node.
// commaok indicates whether to panic or return a bool.
// If commaok is false, resok will be nil.
We can go further by using a debugger to step through some type assertion code.
Take this playground snippet for example. Specifically, these lines:
object_as_closer_hardstop := thing.(io.Closer) // will panic!!
object_as_closer, ok := thing.(io.Closer)
(If you build Go from source, then) if you use a debugger to step into the first type assertion, you will end up at the following code in the Go runtime:
https://github.com/golang/go/blob/8d86ef2/src/runtime/iface.go#L438
If you step into the second one, you end up at:
https://github.com/golang/go/blob/8d86ef2/src/runtime/iface.go#L454
On line 438, you see func assertI2I (with a single return value). A bit lower, on line 454, you see assertI2I2. Note that these two functions have nearly identical names, but not quite!
The second function has a trailing 2 at the end of its name. That function also has two returned results.
As we expect:
assertI2I can panic, but
assertI2I2 cannot.
(Look at the function bodies in iface.go and note which contains panic.)
assertI2I and assertI2I2 abide by the overloading rules we expect. If they were to differ only by number of results, then those of us who compile Go from source would be unable to compile the Go runtime, due to a compiler error such as "assertI2I redeclared".
Users of the language are generally not aware of these builtin runtime functions, so on the surface, both lines of code seem to call the same function:
object_as_closer_hardstop := thing.(io.Closer) // will panic!!
object_as_closer, ok := thing.(io.Closer)
However, at compile time the compiler branches based on whether it found the case "commaok":
https://github.com/golang/go/blob/8d86ef2/src/cmd/compile/internal/gc/ssa.go#L4871
Our own end-user code does not get to modify Go's lexing/parsing/AST-walking in order to dispatch different flavors of our functions based on "commaok".
For better or for worse, that is why user-written code cannot leverage this pattern.

Using the name "function" for a variable in Python code

Is using the word function for the name of an argument considered bad style in Python code?
def conjunction_junction(function):
pass # do something and call function in here
This pattern occurs all the time, especially in decorators. You see func, fn and f used all of the time but I prefer to avoid abbreviations when possible. Is the fact that it's the name of a type enough to warrant abbreviating it?
>> type(conjunction_junction).__name__
'function'
It's not a reserved keyword, so I don't see why not.
From the Style Guide
If a function argument's name clashes with a reserved keyword, it is
generally better to append a single trailing underscore rather than
use an abbreviation or spelling corruption. Thus class_ is better than
clss. (Perhaps better is to avoid such clashes by using a synonym.)
Using function is perfectly fine.
There is nothing in the style guide about it specifically. The reason that the use of type names such as str and list is highly discouraged is because they have functionality within the language. Overwriting them would obscure the functionality of the code. function on the other hand, does nothing.
I suspect func, fn, and f are used because they are all shorter than typing function ;)

Go: naming convention for slice variables/params?

Is the convention for naming slices in Go? Specifically, do you use plurals?
I've noticed that Go App Engine doesn't (eg. it uses key not keys):
func GetMulti(c appengine.Context, key []*Key, dst interface{}) error
I haven't seen anything equivalent in the standard packages or docs I've read. Is singular or plural normal?
That should be a typo, I guess.
Names of slices and arrays are plural. It's not hard to find some samples in the standard library: function SetCookies in CookieJar, Readdirnames, or Args variable in the variables of os package.
But for any variable use a name that better explains its purpose.
A clear exception to this all-plural approach is argv which had its name for decades.
#Mostafa is right. Names of slices and arrays in Go should be a plural. fns is the plural of fn in this example from #Ainar-G. See https://stackoverflow.com/a/35648660/12817546..
package main
import "fmt"
func main() {
var fns []func()
fns = append(fns, beeper)
fns = append(fns, pinger)
for _, fn := range fns {
fn() //beep-beep ping-ping
}
}
func beeper() { fmt.Println("beep-beep") }
func pinger() { fmt.Println("ping-ping") }
#Mostafa is also right that names should explain their purpose. To add to this, self-evident names make code more readable. Self-evident names comment on and document their code.
Self-evident names are consistent. That is they are easy to guess.beeper matches "beep-beep". Self-evident names are accurate. That is they are easy to understand.fns matches fn which denotes a func.
Self-evident names are short. That is they are easy to type. Short names require a short distance between their declaration and their use. Arguments such as fn can be one or two characters-long. For everything else a short one word noun can be used. But sometimes if the distance is great more explanation is needed. A multi-word name mixedCaps can be used. But don't use an under_score_name.
The names used may not be as self-evident as they could be. As a result code may have too many // line comments. Comments can make code less readable. Rename your identifiers so they become more self-evident. And then the number of // can be reduced without loss of explanation.
There are other limits to the use of names. Go keywords cannot be used. Canonical Read, Write, Close, Flush, String etc words should not be used. The first character of a name must be a Unicode letter or a _. Remember capitalized names such as MixedCaps can be exported and type identifiers are typically uppercase.
To find out more have a look at https://talks.golang.org/2014/names.slide, https://blog.golang.org/package-names, https://talks.golang.org/2013/bestpractices.slide, https://golang.org/ref/spec#Identifiers and https://golang.org/doc/effective_go.html#names.

Resources