Syntax of functions...unc (receiver) identifier(parameters) (returns) { code }


(Cherolyn Lexvold) #1

I have the following information for the syntax of functions: func (receiver) identifier(parameters) (returns) { code }

Since all of the following items are marked by paqrenthesis: (receiver) , (parameters) , and (returns); how do I distinguish them, or know which is which when I see them in a function?


(Norbert Melzer) #2

By their position.

Also please keep in mind that while parenthesis around the receiver and the parameters are mandatory, while those around the returns are only necessary when you have a multi-value return.


(Cherolyn Lexvold) #3

I notice sometimes functions have no receiver. Will parameters always come after an identifier? and will returns, when they are present ( for it seems to me that I have seen functions that have no returns), always come after the parameters? Are there cases when a function has no parameters?

In this function: https://play.golang.org/p/AEbN6j-ClwC, which of the 3 items is (y int)?

In explaining the code just mentioned, the teacher states that “we pass x into here (foo), it gets assigned to y”

I don’t understand this concept: it gets assigned to y


(Norbert Melzer) #4

It’s the arguments/parameters.

A receiver is in fact optional (but if it’s there parens are mandatory), as well as returns.

Parameters can be empty, but the parents need to be there. Just look at the main function in the same example you posted.


(Cherolyn Lexvold) #5

Parents?


(Holloway) #6

It’s a rule by its way of writing and with the first word func indicates that line is a function. Hence, a function must carry:

func (receiver)* name(parameters) (return)* {
    ...
}

* = optional

yes. It’s a rule, something like thumb is always facing toward your chest; pinky is facing away from body.

value return are optional. If exists, the return keyword must be inside the code respecting the output. Otherwise, it serves as an instruction to exit the function.

the parameter of the foo function takes in y, an integer. When main calls foo(x), it jumps into function foo. Since the input is x, it is being passed in as y when the execution enters foo function. This is known as “Pass by Value”.


(Norbert Melzer) #7

Should have been “parens”, mobile virtual keyboards autocorrect kicking in. And “parens” is just short for parentheses.


(Holloway) #8

Same here. It’s so hard to reply this forum on mobile.


(Cherolyn Lexvold) #9

Helpful

Requires study. My brain rebels, but I will silence it![quote=“hollowaykeanho, post:6, topic:15656”]

"When main calls foo(x),it jumps into function foo. "…these words really help!

Thanks!!!


(Cherolyn Lexvold) #10

I thought that might be the case. So now, I will examine what you said again.

So,foo is the identifier. And if there were a receiver, it would come before the word “foo”.


(Holloway) #11

One easy way to understand is injecting debug messages before and after lines. Consider the following modified codes:

package main

import (
	"fmt"
)

func liner(functionName string, format string, a ...interface{}) {
	info := fmt.Sprintf(format, a...)
	fmt.Printf("[%s] %v\n", functionName, info)
}

func main() {
	liner("main", "debug line before define x")
	x := 2
	liner("main", "debug line before calling foo, x=%v", x)
	foo(x)
	liner("main", "debug line after foo, x=%v", x)
	fmt.Println(x)
	liner("main", "debug line after foo, after print, x=%v", x)
}

func foo(y int) {
	liner("foo", "debug line enters foo. y=%v", y)
	fmt.Println(y)
	liner("foo", "debug line, after print y, y=%v", y)
	y = 43
	liner("foo", "debug line, after set y, y=%v", y)
	fmt.Println(y)
	liner("foo", "debug line, end foo, y=%v", y)
}

Output with mixed-up liner:

[main] debug line before define x
[main] debug line before calling foo, x=2
[foo] debug line enters foo. y=2
2
[foo] debug line, after print y, y=2
[foo] debug line, after set y, y=43
43
[foo] debug line, end foo, y=43
[main] debug line after foo, x=2
2
[main] debug line after foo, after print, x=2

The main function is indicated by [main] tag while foo function indicated by [foo] tag.

Notice that at the first line of [foo] tag after the cpu enters the function, y is the same as x instead of 0. This is what it meant by your lecturer, the value was passed in from x to y.

Due to the nature of “Passed by Value”, when [main] resumes back after [foo] exited, x is still back to 2 instead of 43, like how you modified it inside foo function. This essentially means that the function clones the value into y instead of modifying x directly.

NOTE:

You can only do this liner experiment when not dealing with concurrency. Otherwise, it’s pointless
and incomprehensible. You need a different tool for that.


(Cherolyn Lexvold) #12

I don’t know what that is. How could I discover that on my own?

Is it possible to run this on my own? How?


(Holloway) #13

It’s just a simple function I built with fmt. You can check them out by reading the documentations (https://golang.org/pkg/fmt/) or start with hunting new tools with Google.

Yes. It’s just an idea for you to test your hypothesis.


(Johann Forster) #14

@cherilexvold1974 have you done the Tour of Go? It’s a good place to start.
https://tour.golang.org/


(Norbert Melzer) #15

Yes, she has. As far as I understood her, she did the tour several times, and she also refered to it in her questions.


(Cherolyn Lexvold) #16

Would you explain this, piece by piece?

Do the same with this, please.


(Holloway) #17

Sure.

This function parts of input: functionName of course, it’s just a name. As for format and a, they are what we called variadic function’s parameters where you can put as many parameters into a without altering the code. a in this case, is a slice.

The objective is basically to print a statement, like your fmt.Printf(...). The only difference here is I added it to prepend the function name.

The function first process the messages (format and a) using fmt.Sprintf(...), where it output into a string (saved into info) instead of printing out to the console. Then, I use fmt.Printf(...) to prepend the functionName in front of the message.

With the new liner(...) printing function, I can easily print statements everywhere.

So when I call liner(...), I provided the function name manually (because apparently can complicates the codes), and the message I want to print out. So, I pass in:

  1. main, which will pass into functionName variable.
  2. debug line before define x, which will pass into format.
  3. Since I don’t have 3rd variable, the variadic parameter a, is empty.