Basics of Go

Functions

Maximiliano Firtman

Maximiliano Firtman

Independent Consultant
Basics of Go

Check out a free preview of the full Basics of Go course

The "Functions" Lesson is part of the full, Basics of Go course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano highlights the characteristics of functions in Go, emphasizing their capability to return multiple values and use labeled variables. The segment includes a demonstration of how to handle functions that return multiple variables.

Preview
Close

Transcript from the "Functions" Lesson

[00:00:00]
>> Functions are similar to other languages, they can receive arguments or humans can have default values. The last argument can be of variable length that means that you can receive n things, we will see some examples of that. The tricky part, functions can return more than one value, again, functions can return more than one value.

[00:00:29]
That's typically new, I mean, most of the functions out there, they return a value, a type one value. Well, here they can return more than one. How, why? We'll see. And why is that useful, okay?. Function can also return labeled variables that's kind of up to they it's seen as a bad practice, I will show you in a second how that looks like.

[00:00:57]
And this is important, function to receive arguments always by value, you know what that means?
>> But it's not receiving a pointer to a different object or a reference to a different object. It's receiving just the value of that object.
>> Just the value.
>> Or it's not an object.

[00:01:19]
>> It's not an object, we don't have objects here. So the thing is that when you are passing a value as an argument, you are not passing the reference to the variable that has the value. You are cloning the value, you're creating a copy of the value, okay?

[00:01:35]
Have that in mind because we will use that later. So functions, this is how it looks like when you define arguments. We don't have one with arguments yet, but you receive, this is the name of the argument and this is the type. Remember, here we first use identifier and then the type.

[00:01:53]
If the function will return something, we express that with a space after the arguments parenthesis and before the code block. In this case, it returns an integer. And then you use the return keyword, as you are used to. But also, we can return more than one. In this case, we use parentheses to group with the comma all the types that you want to return.

[00:02:18]
So in this case, it's going to add and subtract at the same time and then your return both. I know that at first it's like, why do I need that? Okay, but you will see that there are a couple of design patterns where that becomes useful. So we will see that in action, yeah?

[00:02:37]
>> So the second parenthesis there are the types of values that you wanna return?
>> Yeah, those are the types of the return key, so when you're returning you must return two integers. And it says that I need to return them at the same time so I cannot return first, the first integer and then the second one.

[00:02:58]
No, no, I need to call return and at the same time I'm returning both. Okay, that's how that works. Pointers, I say, ooh, pointers gets weird. You can receive, remember I mentioned we pass always arguments by copy. What if I don't want a copy? I want a reference too and we will see some examples.

[00:03:29]
Why do you want a reference? Because maybe you wanna change it. So let's try this in our code. So, let me comment this because I'm not using it. So let's say that here in my main, first, can I have more than one main? No, that's just for in it.

[00:03:51]
What if I have a main in another file? If it's in the same package, also, it's not gonna work because remember, all the package goes to the same structure, so no, it's not gonna work. So I need to have only one main one, one entry point. There are ways to have modules with more than one entry points, but yeah, that's for very specific niche use cases.

[00:04:17]
But I was trying to see how the functions work. So let's say, I have a function here that I'm going to, let's try, going to calculate the tax, okay, for a price. So I receive a price as an integer or a float32. And then I need to return something, let's say I have stateTax and cityTax.

[00:04:46]
So I can return both at the same time. So I can say here, both are float32. Does it make sense? So then when I return in, I need to return two values always. So in this case it can be, let's take any tax percentage, 0.09 on the other one, 0.02.

[00:05:17]
It's weird, right, it's weird, it's odd. When you see that, it's like, what? So then, I can go and say, Print, go to Println, calculateTax of and they have a price, 100. And what's their return of that? Cuz I don't have one value, I have two values. So, which one is going to go to print?

[00:05:43]
We understand that there's something weird that's going on here. So something's happening. Let's first create the variable for this, so let's call the variable, let's say result. I'm going to use a shortcut, so := and then calling calculateTax. And now you'll see that we do have an error.

[00:06:02]
The error says, assignment mismatch. 1 variable, but actually it says there is that we have expecting 2. So, I don't need one variable, I need two. So I need the stateTax and cityTax and that's how you set two variables. Why is giving me an error? Anxiety [LAUGH], right, because I'm not using them.

[00:06:29]
So if you print this it will stop complaining. So that's how you create two variables on the fly, receiving two values from one function. What if you don't need one? Let's say I just need a state, not cityTax? Because, yeah, you can say, well, just ignore cityTax. At one point, the garbage collector will just delete it from memory.

[00:06:57]
But it can be even more efficient because if I don't need it, I can just use a special variable name, but it's not really a variable name, it's underscore. An underscore means, hey, I know that we received a value there but I'm not gonna use it. So yeah, I'm not even gonna waste an identifier to create the variable for it.

[00:07:21]
But it's mandatory to set something because if not, it will complain. So I have to use comma underscore or it can be underscore first as well. And if you do both it says, come on, you don't need variables. So then but you can say this is a cityTax and then print the cityTax if you just need that one, okay?

[00:07:48]
>> Why would you need something that you wouldn't want to?
>> Well, first, because maybe you are executing a function that it wasn't your creation. It's part of a library, and that library is giving you two numbers and you need only one. Well, but you're forced to declare both, you need to express to the compiler what to do with each value.

[00:08:12]
Well, you can say ignore that one, and that's underscore, okay? By the way that's available, the same technique of underscore is available on some modern languages as well, so not just Go. I know that you are still not finding a good use case for this. But give me a sec because you will see a use case for this, that we use a lot when we are building Go applications, okay?

[00:08:42]
Do you have any question, this one?
>> Can you not return a collection then from a function?
>> Let me see if I understand, so can you not return a collection? This is not a collection, actually. This is more like a tuple, so this is not a collection, so I cannot treat it as a collection.

[00:09:05]
You can if you want to return the collection, I mean, you could say, you know what, I'm going to return just one value of type slice of float, which is okay. But it's not the same. In this case, we are returning one value of type slice or type array of two.

[00:09:23]
>> I'm just wondering what the functional difference is between that and what you just did where you have two separate.
>> Well, for example that maybe, I can have a third one that is a string. Maybe the type is not the same when we have collections? While there are ways to mix types within the collection that we may see later.

[00:09:44]
Then it becomes more complicated to put everything in a collection, okay? It can be anything actually. So now it complaining because I'm not returning the last value, but I can just return a string. I know it says, well, do you have a string also? Okay, I don't want it so, let's ignore it.

[00:10:02]
It's not just two and they don't need to be of the same type. Again, I know that you still say, okay, why do I need that? But now that you know that it exists and now that you will see some examples of that being applied. You will start thinking differently and says, maybe that thing that I'm typically doing that in this way, maybe I can do this in this other way.

[00:10:33]
Okay, makes sense. So now you can return more than one value, it's just that, makes a simple concept powerful, but also weird. And you always need to return all of them. Maybe on some cases, you might return nil because that's a valid value but at least, you need to explicitly say, okay, for that argument, nil.

[00:10:57]
Okay, make sense, it's just that. So also I mentioned that you can name them. Let me create another version of that so you can see how that looks like, so let's say WithName. In this case, lemme remove the third argument. So you can see that arguments are named, they have a name.

[00:11:21]
Well, I can also add a name to return types. In this case, they can be stateTax and cityTax, cityTax space and you say, what? When you do that, you're actually creating local variables, okay? So first, I'm creating local variables, so I can actually say now, that the stateTax is actually this one and the cityTax is actually that one.

[00:11:52]
And when I am finishing setting all my variables, I can just return with no additional metadata.
>> Then in the place in the main on line 28 would you be able to eliminate those underscores then.
>> No, that's the same because I'm still getting two. So if I change that with calculateTaxWithName, I'm still receiving two arguments.

[00:12:17]
The name is internal to the function.
>> I see.
>> So I'm not changing how you are consuming the function, I'm changing how we are defining the returned values. Instead of adding the values in the return declaration, I just save values in those variables. And then I say, hey, return and the dinner is ready, and then you need to go and grab the dinner from the same place.

[00:12:44]
It's just that, actually, it's not being used a lot to be honest. And as the function gets larger, the more difficult is to use this in a nice way because it becomes really obscure. Where are your return declarations? Because it's actually on the value that you're saving on those variables that they can be anywhere in the function, but you still need to call return.

[00:13:16]
But in this case, you don't need to set the value because the values are going to be returned automatically from these two variables. There is another way of defining function. Just as I mentioned before, we don't have function overloads, so I cannot create another function with the same name even though it has a different signature, no way.

[00:13:38]
CalculateTax is already defined there. Now, this is for clinco, so no way. The only exception is Init, remember that you can have more than one Init, that's the only exception.
>> Can a functions return type set to different values, for example, return string or nil and how would you deal with it if it could return nil?

[00:14:05]
>> That's a good question. So, the quick answer is no. You must return a type and two types are not one type. However, you can create your own types, we haven't seen that yet. So, that might lead to an answer because if you create your own type, then you can return your own type and on that situation you can solve that problem.

[00:14:32]
But it's more a design pattern than a feature from the from the Go syntax, okay?

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now