Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I recently started learning to Go, and I am quite confused as to why it has a strange "non-traditional" syntax unlike other languages (C, C++, C#, JAVA)
For example, a code like this in Go:
package main
import "fmt"
func sum(a int, b int) int {
return a + b
}
func main() {
numbers := [4] int {1, 2, 3, 4}
for _,n := range numbers {
result := sum(n, 2)
fmt.Println(result)
}
}
But, could be written something like in some languages:
package main
import "io"
int sum(int a, int b) {
return a + b
}
void main() {
int numbers[4] = {1, 2, 3, 4}
foreach (n in range(numbers)) {
result = sum(n, 2)
io.print(result)
}
}
So my question is, is there any technical reason behind this syntax, or is it just a personal preference of the team? Especially that the team behind Go used "C Language" to write Go, which means it would've made much more sense to type it in C-Style syntax ?
Few points that I'd like to highlight:
Go is inspired by many languages and not just C.
C: statement and expression syntax
Pascal: declaration syntax
Modula 2, Oberon 2: packages
CSP, Occam, Newsqueak, Limbo, Alef: concurrency
BCPL: the semicolon rule
Smalltalk: methods
Newsqueak: <-, :=
APL: iota
There are more
From when foreach and range become C-style syntax?
Third, don't confuse "For" statements with for clause and range clause. Read the spec.
In Go, you can do this is as well:
for i := 0; i < len(numbers); i++
But range clause is much more powerful once you understand it and yes it is not strange syntax. I'd suggest to read the spec and see a few examples.
Also, it's Go and not GoLang (Read). Always prefer the former over the latter.
Try the Go Tour. Some concepts are explained well.
Also, read Go's FAQ and Pike's blog on declaration syntax. The FAQ should answer many such queries.
import "io"
Go has fmt and io packages, although they do have some overlap. For example, fmt.Fprint lets you write to any io.Writer, and fmt.Fscan lets you read from any io.Reader.
Similarly you can write to console with io.Copy(os.Stdout, something), and read from console with io.Copy(something, os.Stdin).
int sum(int a, int b) {
I think I read that by having func first, it makes lexical parsing much faster. Also Go function can have named return values:
func sum(a int, b int) (n int)
I am not sure how you'd do that with the other syntax.
int numbers[4] = {1, 2, 3, 4}
Go syntax allows you to omit the type, which you can't do with C.
foreach (n in range(numbers))
Go doesn't have a while keyword, for the reason that less keywords again makes for faster lexical parsing. Instead you have different for invocations:
var n int
for {
if n > 9 {
break
}
println(n)
n++
}
var n int
for n < 9 {
println(n)
n++
}
for n := 0; n < 9; n++ {
println(n)
}
for range numbers {
println("hello")
}
for index := range numbers {
println(index)
}
for index, value := range numbers {
println(index, value)
}
For this:
result = sum(n, 2)
Go has two different syntax for variable assignment:
result := 1
result = 2
First is a declaration, second is assigning to an already declared variable.
io.print(result)
fmt.Println is uppercase, because any function that starts with an uppercase letter is a "public" function. This saves on typing public or pub everywhere.
Related
This question already has answers here:
How can go-lang curry?
(3 answers)
Closed 9 months ago.
What is the idiomatic approach for adding two numbers in this kind of manner
Add(5)(3) -> This is done in C# with delegate but I'm not sure what the right way to do that in Go since there's no delegate.
Return a function that gets the first value from the the enclosing scope and the second number from an argument.
func Add(a int) func(int) int {
return func(b int) int {
return a + b
}
}
fmt.Println(Add(3)(5)) // prints 8
None of this is idiomatic. The idiomatic code is 3 + 5.
The idiomatic way to do that in Go is not to do that.
Go's emphasis on performance and procedural nature means that functional patterns like currying are strongly anti-idiomatic. The only idiomatic way to add two numbers is Go is:
sum := 5 + 3
You could implement it with a function returning a function
func Add(val int) func(int) int {
return func (other int) int {
return val + other
}
}
But you shouldn't. It adds complexity and slows down your program without any befit.
I'm still new to programming. Forgive my lack of computer science knowledge. Not sure if this question is specific to Golang or computer science in general...
I always thought that functions do not alter variables/data held outside their own scope unless you use a return statement back into the other scope, or unless they are higher in the hierarchy of scopes. One may argue that functions f1 and f2 in this example are called from a lower scope. However, this still doesn't explain why I'm getting different results for variable num and nums.
package main
import "fmt"
func f1(a int) {
a = 50 // this will not work, as it shouldn't
}
func f2(a ...int) {
a[0] = 50 // this will work without return statement
a[1] = 50 // this will work without return statement
}
func main() {
num := 2
nums := []int{2, 2}
f1(num)
f2(nums...)
fmt.Printf("function f1 doesn't affect the variable num and stays: %v\n", num)
fmt.Printf("function f2 affects the variable nums and results in: %v", nums)
Questions:
Why doesn't f2 require a return statement to modify nums like num
would within f1?
Golang functions are said to pass values (rather than reference),
shouldn't that force the function to return copies?
Can this happen in other languages? (I think I may have
seen this in other languages).
This is the correct behaviour, since a ...int is equal to a slice e.g.: a []int
func f2(a []int) {
a[0] = 50
a[1] = 50
}
func main() {
b := []int{2, 2}
f2(b)
fmt.Println(b) // [50 50]
}
And a slice is a view to the original data, here 'b'.
"Why doesn't f2 require a return statement to modify nums like num would in f1?"
In f2 you are using the slice, which has a pointer to the original array, so f2 can change the outside array.
"Golang functions are said to pass values (not reference), shouldn't that force to return copies? (If the question is related...)"
In f2 the slice itself is passed by value, meaning pointer and length and capacity of the original array.
"Can this happen in other languages? (I think I may have seen this in other langues)"
Too broad to answer, there are many languages and in general if you have a pointer to the outside world array, yes.
Edit:
package main
import "fmt"
func sum(a ...int) int {
s := 0
for _, v := range a {
s += v
}
return s
}
func f2(a []int) {
c := make([]int, len(a))
copy(c, a)
c[0] = 50
fmt.Println(sum(c...)) // 52
}
func main() {
b := []int{2, 2}
fmt.Println(sum(1, 2, 3, 4)) // 10
fmt.Println(sum(b...)) // 4
f2(b)
fmt.Println(b) // [2 2]
}
Notes:
The sum() function above is a pure function, since it has no side effect.
The new f2 function above is a pure function, since it has no side effect: it makes a copy of a into c then calls the sum.
In go, function arguments are passed by value. That means, if you pass an int (like in f1), compiler will pass the value of f1, essentially copying it. If the function takes a *int and you pass &num, then the compiler passes the value of &num, which is a pointer to num. When the function changes *num, the value of the variable outside the function will change. If the function changes num, the pointer value of num will change, and it will point to a different variable.
As a contrast, Java passes all primitive values as value, and all objects by reference. That is, if you pass an int, there is no way for the function to modify the value of that int that is visible to the caller. If you want to pass an int the function can modify, you put that in a class and pass an instance of that class in Java.
A slice (as in f2) contains a pointer to the underlying array. When you call a function with a slice, the slice header (containing a pointer to the underlying array) is copied, so when the function changes the slice elements, the underlying array elements change.
The question of scope is somewhat different. Scope of a function is all the variables it can see. Those are the global variables (if from different packages, exported global variables), function arguments, and if the function is declared nested within another function, all the variables visible in that function at that point.
1 & 2) Both questions can be answered when looking at how slices work in Go. There's a blog article on it.
In general, all variables are passed by value in Go. You can use pointers (e.g. *int for f1) to pass by reference (or more correct, the address of the pointer).
However, slices are technically also passed by value.
When we look here, we can get an idea how they work:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
Len and Cap are integers, but Data is a pointer.
When this struct is copied (when passing by value), a copy of Len, Cap and Data will be made. Since Data is a pointer, any modifications made to the value it's pointing to will be visible after your function returns.
You can also read this
What is the Go equivalent of, for example, Python's operator package for calling builtin operators by name?
Meaning, how can I do something like:
func f(op func(int, int)bool, a int, b int)
...
if op(a, b) {
...
f(operators.LessThan, 1, 2) // true
Stated otherwise, how to write a function that takes in what basic operator to apply as a function argument?
First, you shouldn't assume language X has any equivalent for feature Y in language Z. Also you should write/design code for the language you're using rather than designing as if it was another language and then translating line-by-line or function-by-function.
As comments mentioned, operators are builtin in Go with no operator overloading or functional equivalents. If you haven't already you should take the Go Tour and read the Language Specification to see what Go does have.
If you really want/need to do something like you ask this is one way:
package main
import "fmt"
type Compare func(int, int) bool
func DoCompare(cmp Compare, a, b int) bool {
return cmp(a, b)
}
var (
CmpLessThan = func(a, b int) bool { return a < b }
CmpLessThanOrEqual = func(a, b int) bool { return a <= b }
CmpGreaterThan = func(a, b int) bool { return a > b }
CmpGreaterThanOrEqual = func(a, b int) bool { return a >= b }
)
func main() {
fmt.Println(DoCompare(CmpLessThan, 1, 2))
}
Go Playground.
Normally if something like this is needed, instead of multiple comparison functions, a single compare function is used that returns <0, 0, or, >0 (e.g. -1, 0, +1) for less-than, equal, greater-than. For example, big.Int.Cmp.
Update 2023 / Go with Generics
Powered by Go generics, I made a new package to do this at github.com/tawesoft/golib/v2/operator:
For your example use case,
import "tawesoft/golib/v2/operator"
...
f := operator.LT[int] // less than
f(1, 2) // true
Old answer
I needed the same thing - basic operators as first-class functions in Go - and ended up writing a template and a bit of Python to generate my own.
I've packaged it up into a single well-tested Go module, called operator after the Python module.
Hope this helps!
Go Get:
go get -u tawesoft.co.uk/go/operator
Examples:
operator.Boolean.Not(true) == false
operator.Boolean.Nary.Any(false, true, true, false) == true
operator.Int.Binary.Add(1, 2) == 3
In your case:
f(operator.Int.Binary.Lt, 1, 2)
So I am new to Go and fairly inexperienced with programming in general so I hope I don't get downvoted again for asking stupid questions.
I am working my way through the project euler problems and at problem 25 "1000-digit Fibonacci number" I encountered what seems to be strange behavior. The following is the code I wrote that resulted in this behavior.
package main
import (
"fmt"
"math/big"
)
func main() {
index := 2
l := new(big.Int)
pl := big.NewInt(1)
i := big.NewInt(1)
for {
l = i
i.Add(i, pl)
pl = l
index++
if len(i.String()) == 1000 {
break
}
}
fmt.Println(i, "\nindex: ", index)
}
Naturally this did not generate the correct answer so in the process of determining why I discovered that I had inadvertently discovered a neat way to generate powers of 2. I made the following changes and this did generate the correct result.
package main
import (
"fmt"
"math/big"
)
func main() {
index := 2
l := new(big.Int)
pl := big.NewInt(1)
i := big.NewInt(1)
for {
l.Set(i)
i.Add(i, pl)
pl.Set(l)
index++
if len(i.String()) == 1000 {
break
}
}
fmt.Println(i, "\nindex: ", index)
}
My question is what is happening in the first example that causes each big Int variable to be set to the value of i and why this did not generate an error if this was not the correct way to assign a big Int var value? Is i = l, etc a legitimate big Int operation that is simply incorrect for this situation?
The lines
l = i
and
pl = l
aren't doing what you think they are.
l, pl, and i are pointers, and assigning them to each other copies the pointer value, not the big.Int value.
After executing l = i, l is now the same pointer value as i, pointing to the same big.Int. When you use l.Set(i), it sets l's big.Int value to i's big.Int value, but l and i still point to two separate values.
Is it possible to use an operator in place of a function in go?
For example, in the following code is it possible to replace add with +?
package main
import "fmt"
var cur, prev int = 1, 1
func fib(f func(int, int) int) int {
return f(cur, prev)
}
func main() {
add := func(x int, y int) int { return x + y };
fmt.Println(fib(add))
}
If it's not possible to use operators as functions, then I would appreciate a link to the documentation clarifying this.
Operators are not first-class values in Go (nor most other languages), so no, you cannot pass them as arguments. Notice that even the Go documentation uses a func(x,y int) int { return x+y } in its examples.
Also note that the grammar for operators does not allow any options for an operator without a corresponding expression to operate on.