Why there are two ways of declaring variables in Go, what's the difference and which to use? - variables

According to the Go reference there are two ways of declaring a variable
Variable_declarations (in the format of var count = 0 or var count int)
and
Short_variable_declarations (in the format of count := 0)
I found it's very confusing to decide which one to use.
The differences I know (till now) are that:
I can only using a count := 0 format when in the scope of a function.
count := 0 can be redeclared in a multi-variable short declaration.
But they do behave the same as far as I know. And in the reference it also says:
It (the count:=0way) is shorthand for a regular variable declaration with initializer expressions but no types
My confusions are:
If one is just the shorthand way of the other, why do they behave differently?
In what concern does the author of Go make two ways of declaring a variable (why are they not merged into one way)? Just to confuse us?
Is there any other aspect that I should keep my eyes open on when using them, in case I fall into a pit?

The Variable declarations make it clear that variables are declared. The var keyword is required, it is short and expresses what is done (at the file level everything excluding comments has to start with a keyword, e.g. package, import, const, type, var, func). Like any other block, variable declarations can be grouped like this:
var (
count int
sum float64
)
You can't do that with Short variable declarations. Also you can use Variable declarations without specifying the initial value in which case each variable will have the zero value of its type. The Short variable declaration does not allow this, you have to specify the initial value.
One of Go's guiding design principle was to make the syntax clean. Many statements require or it is handy that they allow declaring local variables which will be only available in the body of the statement such as for, if, switch etc. To make the syntax cleaner and shorter, Short variable declaration is justified in these cases and it is unambigous what they do.
for idx, value := range array {
// Do something with index and value
}
if num := runtime.NumCPU(); num > 1 {
fmt.Println("Multicore CPU, cores:", num)
}
Another difference: Redeclaration
Quoting from the Language specification:
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block 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. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
This one is also handy. Suppose you want to do proper error handling, you can reuse an err variable because most likely you only need it to check if there were any errors during the last function call:
var name = "myfile.txt"
fi, err := os.Stat(name) // fi and err both first declared
if err != nil {
log.Fatal(err)
}
fmt.Println(name, fi.Size(), "bytes")
data, err := ioutil.ReadFile(name) // data is new but err already exists
// so just a new value is assigned to err
if err != nil {
log.Fatal(err)
}
// Do something with data

Related

What do you call doing assignment in a conditional?

Is there a special name for doing assignment in a conditional? Here is an example of what I am asking about in C:
// Assume a and b have been previously defined and are compatible types
if( (a = b) ) { // <- What do you call that?
//do something
}
A couple friends of mine and I are convinced that there is a name for it, and some other people have agreed that there is one, but we can't find it anywhere. Has anyone here ever heard a term for it?
Assuming that an assignment is intentional, there is no special name for this. C language specification places a very weak requirement on the controlling expression of an if statement:
6.8.4.1-1: The controlling expression of an if statement shall have scalar type.
An assignment expression satisfies this requirement, as long as a and b are scalar. An implicit comparison to zero is performed on the result of this assignment:
6.8.4.1-2: In both forms, the first substatement is executed if the expression compares unequal to 0. In the else form, the second substatement is executed if the expression compares equal to 0.
Note that compilers would issue a warning when they see an assignment like that, because missing second = is a common source of errors. You can prevent these warnings using parentheses, as described in this Q&A.
It doesn’t really have a name, though people do call it various things. If the code follows your question:
if( a = b )...
then common terms are: bug, error, etc. However if b is not a variable but an expression, e.g. as in the common C patterns:
if( (c = getchar()) != EOF )...
while( *q++ = *p++ )...
then it might be called an idiom, pattern, etc.
I don’t know if it has a name but I’d call it “useful feature that nobody understands”.
It is very useful indeed.
We can consider it a slang.
In C++ for example you can use this by declaring a variable directly, and this is useful for safety checks:
if (Object *a = takeObject()) {
// a is not nullptr
}
Or when I don’t want to repeat a statement in a loop:
while (a = next()) {
}
Instead of:
a = next();
while (a) {
a = next();
}
But commonly these are just mistakes which compilers like gcc and clang give warnings about (and they force you to put an horrible double tuple to silence the warning ew!).

What is "_," (underscore comma) in a Go declaration?

And I can't seem to understand this kind of variable declaration:
_, prs := m["example"]
What exactly is "_," doing and why have they declared a variable like this instead of
prs := m["example"]
(I found it as part of Go by Example: Maps)
It avoids having to declare all the variables for the returns values.
It is called the blank identifier.
As in:
_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
That way, you don't have to declare a variable you won't use: Go would not allow it. Instead, use '_' to ignore said variable.
(the other '_' use case is for import)
Since it discards the return value, it is helpful when you want to check only one of the returned values, as in "How to test key existence in a map?" shown in "Effective Go, map":
_, present := timeZone[tz]
To test for presence in the map without worrying about the actual value, you can use the blank identifier, a simple underscore (_).
The blank identifier can be assigned or declared with any value of any type, with the value discarded harmlessly.
For testing presence in a map, use the blank identifier in place of the usual variable for the value.
As Jsor adds in the comments:
"generally accepted standard" is to call the membership test variables "ok" (same for checking if a channel read was valid or not)
That allows you to combine it with test:
if _, err := os.Stat(path); os.IsNotExist(err) {
fmt.Printf("%s does not exist\n", path)
}
You would find it also in loop:
If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first:
sum := 0
for _, value := range array {
sum += value
}
The Go compiler won't allow you to create variables that you never use.
for i, value := range x {
total += value
}
The above code will return an error message "i declared and not used".
Since we don't use i inside of our loop we need to change it to this:
for _, value := range x {
total += value
}
The blank identifier may be used whenever syntax requires a variable name but program logic does not, for instance to discard an unwanted loop index when we require only the element value.
Excerpt From:
The Go Programming Language (Addison-Wesley Professional Computing Series)
Brian W. Kernighan
This material may be protected by copyright.
_ is the blank identifier. Meaning the value it should be assigned is discarded.
Here it is the value of example key that is discarded. The second line of code would discard the presence boolean and store the value in prs.
So to only check the presence in the map, you can discard the value. This can be used to use a map as a set.
The great use case for the unused variable is the situation when you only need a partial output. In the example below we only need to print the value (state population).
package main
import (
"fmt"
)
func main() {
statePopulations := map[string]int{
"California": 39250017,
"Texas": 27862596,
"Florida": 20612439,
}
for _, v := range statePopulations {
fmt.Println(v)
}
}
It is called the blank identifier and it helps in cases where you wish to discard the value that is going to be returned and not reference it
Some places where we use it:
A function returns a value and you don't intend to use it in the
future
You want to iterate and need an i value that you will not be
using
Basically, _, known as the blank identifier. In GO we can't have variables that are not being used.
As an instance when you iterating through an array if you are using value := range you don't want a i value for iterating. But if you omit the i value it will return an error. But if you declare i and didn't use it, it will also return an error.
Therefore, that is the place where we have to use _,.
Also it is used when you don't want a function's return value in the future.
An unused variable is not allowed in Golang
If you were coming from other programming languages this might feel bit difficult to get used to this. But this results in more cleaner code. So by using a _ we are saying we know there is a variable there but we don't want to use it and telling the compiler that does not complain me about it. :)
_(underscore) in Golang is known as the Blank Identifier. Identifiers are the user-defined name of the program components used for the identification purpose. Golang has a special feature to define and use the unused variable using Blank Identifier. Unused variables are those variables that are defined by the user throughout the program but he/she never makes use of these variables.
Go compiler throws an error whenever it encounters a variable declared but not used. Now we can simply use the blank identifier and not declare any variable at all.
// Golang program to show the compiler
// throws an error if a variable is
// declared but not used
package main
import "fmt"
// Main function
func main() {
// calling the function
// function returns two values which are
// assigned to mul and div identifier
mul, div := mul_div(105, 7)
// only using the mul variable
// compiler will give an error
fmt.Println("105 x 7 = ", mul)
}
// function returning two
// values of integer type
func mul_div(n1 int, n2 int) (int, int) {
// returning the values
return n1 * n2, n1 / n2
}
Output
./prog.go:15:7: div declared and not used
Let’s make use of the Blank identifier to correct the above program. In place of div identifier just use the _ (underscore). It allows the compiler to ignore declared and not used error for that particular variable.
// Golang program to the use of Blank identifier
package main
import "fmt"
// Main function
func main() {
// calling the function
// function returns two values which are
// assigned to mul and blank identifier
mul, _ := mul_div(105, 7)
// only using the mul variable
fmt.Println("105 x 7 = ", mul)
}
// function returning two
// values of integer type
func mul_div(n1 int, n2 int) (int, int) {
// returning the values
return n1 * n2, n1 / n2
}
Output
105 x 7 = 735

no new variables on left side of :=

What's happening here?
package main
import "fmt"
func main() {
myArray :=[...]int{12,14,26} ;
fmt.Println(myArray)
myArray :=[...]int{11,12,14} //error pointing on this line
fmt.Println(myArray) ;
}
It throws an error that says
no new variables on left side of :=
What I was doing was re-assigning values to an already declared variable.
Remove the colon : from the second statement as you are assigning a new value to existing variable.
myArray = [...]int{11,12,14}
colon : is used when you perform the short declaration and assignment for the first time as you are doing in your first statement i.e. myArray :=[...]int{12,14,26}.
There are two types of assignment operators in go := and =. They are semantically equivalent (with respect to assignment) but the first one is also a "short variable declaration" ( http://golang.org/ref/spec#Short_variable_declarations ) which means that in the left we need to have at least a new variable declaration for it to be correct.
You can change the second to a simple assignment statement := -> = or you can use a new variable if that's ok with your algorithm.
As a side note, redeclaration can only appear in a multi-variable short declaration
Quoting from the Language specification:
Unlike regular variable declarations, a short variable declaration may
redeclare variables provided they were originally declared earlier in
the same block 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. Redeclaration does not introduce a
new variable; it just assigns a new value to the original.
package main
import "fmt"
func main() {
a, b := 1, 2
c, b := 3, 4
fmt.Println(a, b, c)
}
Here is a very good example about redeclaration of variables in golang:
https://stackoverflow.com/a/27919847/4418897
myArray :=[...]int{12,14,26}
As stated by the previous commenters, := is a type of short-hand and/or the short-form of variable declaration.
So in the statment above you are doing two things.
You are declaring your variable to be myArray.
You are assigning an array of integers to the myArray variable.
The second part of your code fails, because what you are doing here:
myArray :=[...]int{11,12,14} //error pointing on this line
Is RE-declaring the existing variable myArray, which already contains integer values.
This works:
myArray = [...]int{11,12,14} // NO error will be produced by this line
Because, it is assigning the integer array to the existing ( pre-declared / initialized ) variable.

Ignore Ada Function Return Values

Is there a way to ignore return values in Ada functions?
I have a function which imports from an Intrinsic.
subtype int32 is Interfaces.Interger_32;
function Intrinsic_Sync_Add_And_Fetch
(P : access int32; I : int32) return int32;
pragma Import(
Intrinsic,
Intrinsic_Sync_Add_And_Fetch,
"__sync_add_and_fetch_4");
If I want to use this in a procedure, I need to accept the return value or I will get a compiler error:
cannot use function Intrinsic_Sync_Add_And_Fetch in procedure call.
But, if I create a variable that simply takes the return value of the function and is never used then I get compiler warnings. Obviously, I'd rather avoid those.
I can't very well assign the value back to the value I'm adding to; this would undermine the point of the add operation being atomic.
There is the option of taking the value and doing something with it, like:
val := Intrinsic_Sync_Add_And_Fetch(...);
if val := 0 then null; end if;
It forces the code to compile without errors or warnings, but it seems stupid to me. How can I "get around" this language feature and safely ignore the return value?
Edit: What is __sync_add_and_fetch_4?
This is a built-in atomic operation available on Intel CPUs. As such, part of my Autoconf/Automake process would be deciding if the operation is available, and use a fallback implementation, which involves a critical section, if it's not.
You can read about this and similar operations in GCC's section on atomic builtins.
The __sync_add_and_fetch_4 does pretty much exactly what it says. In C, it would look something like this:
int32_t __sync_add_and_fetch_4(int32_t *ptr, int32_t value) {
*ptr += value;
return *ptr;
}
So it's an atomic addition operation, which returns the result of the addition. Basically, it's an atomic += operator. The _4 means that it takes a 4-byte integer.
Edit: I understand that I could probably just switch off that particular compiler warning, but that always feels dirty to me. If there's a solution available that allows me to continue using -Wall -Werror then I'd love to see it.
declare
dummy : constant return_type := my_function;
pragma Unreferenced (dummy);
begin null; end;
or write a wrapper procedure.
If you never want to reference the return value, why not declare the subprogram as a procedure? The value is going to be returned in a register, so throwing it away won’t cause a lot of grief. (I stand to be corrected on this one!)
subtype int32 is Interfaces.Integer_32;
procedure Intrinsic_Sync_Add_And_Fetch
(P : access int32; I : int32);
pragma Import(
Intrinsic,
Intrinsic_Sync_Add_And_Fetch,
"__sync_add_and_fetch_4");
You said you're only targeting the GNAT compiler. The GNAT User's Guide says:
Note that a special exemption applies to variables which contain any of the substrings DISCARD, DUMMY, IGNORE, JUNK, UNUSED, in any casing. Such variables are considered likely to be intentionally used in a situation where otherwise a warning would be given, so warnings of this kind are always suppressed for such variables.
So the simplest solution to your problem is :
unused := Intrinsic_Sync_Add_And_Fetch(...);
Though you might want to wrap that in a procedure if you are going to use it more than a couple of times :
procedure Intrinsic_Sync_Add_And_Fetch(P : access int32; I : int32) is
unused : int32;
begin
unused := Intrinsic_Sync_Add_And_Fetch(P : access int32; I : int32);
end Intrinsic_Sync_Add_And_Fetch;
i don't know of any way to ignore the return value of a function in Ada: the language has been especially designed to force you to store those return values.
personally, i would store the return value and ignore any warning regarding the use of the variable. anyway, the said warning is quite strange since the variable is indeed used to store the return value.

Function/variable scope (pass by value or reference?)

I'm completely confused by Lua's variable scoping and function argument passing (value or reference).
See the code below:
local a = 9 -- since it's define local, should not have func scope
local t = {4,6} -- since it's define local, should not have func scope
function moda(a)
a = 10 -- creates a global var?
end
function modt(t)
t[1] = 7 -- create a global var?
t[2] = 8
end
moda(a)
modt(t)
print(a) -- print 9 (function does not modify the parent variable)
print(t[1]..t[2]) -- print 78 (some how modt is modifying the parent t var)
As such, this behavior completely confuses me.
Does this mean that table variables
are passed to the function by
reference and not value?
How is the global variable creation
conflicting with the already define
local variable?
Why is modt able to
modify the table yet moda is not able
to modify the a variable?
You guessed right, table variables are passed by reference. Citing Lua 5.1 Reference Manual:
There are eight basic types in Lua: nil, boolean, number, string, function, userdata, thread, and table.
....
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
So nil, booleans, numbers and strings are passed by value. This exactly explains the behavior you observe.
Lua's function, table, userdata and thread (coroutine) types are passed by reference. The other types are passed by value. Or as some people like to put it; all types are passed by value, but function, table, userdata and thread are reference types.
string is also a kind of reference type, but is immutable, interned and copy-on-write - it behaves like a value type, but with better performance.
Here's what's happening:
local a = 9
local t = {4,6}
function moda(a)
a = 10 -- sets 'a', which is a local introduced in the parameter list
end
function modt(t)
t[1] = 7 -- modifies the table referred to by the local 't' introduced in the parameter list
t[2] = 8
end
Perhaps this will put things into perspective as to why things are the way they are:
local a = 9
local t = {4,6}
function moda()
a = 10 -- modifies the upvalue 'a'
end
function modt()
t[1] = 7 -- modifies the table referred to by the upvalue 't'
t[2] = 8
end
-- 'moda' and 'modt' are closures already containing 'a' and 't',
-- so we don't have to pass any parameters to modify those variables
moda()
modt()
print(a) -- now print 10
print(t[1]..t[2]) -- still print 78
jA_cOp is correct when he says "all types are passed by value, but function, table, userdata and thread are reference types."
The difference between this and "tables are passed by reference" is important.
In this case it makes no difference,
function modt_1(x)
x.foo = "bar"
end
Result: both "pass table by reference" and "pass table by value, but table is a reference type" will do the same: x now has its foo field set to "bar".
But for this function it makes a world of difference
function modt_2(x)
x = {}
end
In this case pass by reference will result in the argument getting changed to the empty table. However in the "pass by value, but its a reference type", a new table will locally be bound to x, and the argument will remain unchanged. If you try this in lua you will find that it is the second (values are references) that occurs.
I won't repeat what has already been said on Bas Bossink and jA_cOp's answers about reference types, but:
-- since it's define local, should not have func scope
This is incorrect. Variables in Lua are lexically scoped, meaning they are defined in a block of code and all its nested blocks.
What local does is create a new variable that is limited to the block where the statement is, a block being either the body of a function, a "level of indentation" or a file.
This means whenever you make a reference to a variable, Lua will "scan upwards" until it finds a block of code in which that variable is declared local, defaulting to global scope if there is no such declaration.
In this case, a and t are being declared local but the declaration is in global scope, so a and t are global; or at most, they are local to the current file.
They are then not being redeclared local inside the functions, but they are declared as parameters, which has the same effect. Had they not been function parameters, any reference inside the function bodies would still refer to the variables outside.
There's a Scope Tutorial on lua-users.org with some examples that may help you more than my attempt at an explanation. Programming in Lua's section on the subject is also a good read.
Does this mean that table variables are passed to the function by reference and not value?
Yes.
How is the global variable creation conflicting with the already define local variable?
It isn't. It might appear that way because you have a global variable called t and pass it to a function with an argument called t, but the two ts are different. If you rename the argument to something else, e,g, q the output will be exactly the same. modt(t) is able to modify the global variable t only because you are passing it by reference. If you call modt({}), for example, the global t will be unaffected.
Why is modt able to modify the table yet moda is not able to modify the a variable?
Because arguments are local. Naming your argument a is similar to declaring a local variable with local a except obviously the argument receives the passed-in value and a regular local variable does not. If your argument was called z (or was not present at all) then moda would indeed modify the global a.