 So here we're creating the same cat struct we've created many times and we're defining two methods for cat and the way you define methods is it looks like a function definition but you put the so-called receiver of the method first in its own pair of parentheses before the method name. So this is defining a method sleep where the receiver is of type cat and inside the method will refer to the receiver as C though we're not actually using it in this particular method but we could. And then all the other parameters you put inside the parentheses after the name of the method but in this case we don't have any so we just leave that empty and the sleep method is just simply printing out zzzz and this method eat also has a receiver of type cat which we will call C and it has another parameter food which is a float32 and it's returning a float32. And when we call the eat method on a cat the method receives a copy of the cat in C and we're going to access the weight of that copy add food to it and that's the value returned. So down here in Maine we're using the colon equal syntax to declare a variable C and a type is implicit from what we assign to it because we're assigning a cat value to C here the compiler knows that this is a cat variable and here we're calling the method sleep on C this C is passed to C of sleep it gets a copy of the same cat be clear C here in Maine and C and the methods are totally unrelated they just happen to have the same name and this method called to sleep will simply just print out zzzz and here we're calling the eat method on C passing in also the float value 0.3 so C of Maine gets copied to C of the eat method and 0.3 gets copied to food and we take the weight value of this C in the eat method and add food to it and that's what we return so this should be 15.2 plus 0.3 that gives us 15.5 and that's what this returns down here when we use the reference operator on a cat variable what we get back is a pointer to cat so that's what the type of p is it's going to be a variable which is a pointer to cat and given a pointer to cat we can get back the cat at points to using the dereference operator and then we could call the sleep method on that cat and so that's actually what the syntax is doing the asterisk the dereference operator has a lower precedence than the dot so we need the parentheses here to make sure the dereference is done first and then we are calling the method sleep on the cat value returned by this expression but the go compiler as a convenience we don't have to actually explicitly dereference it'll just automatically do that for us so we could just write p dot sleep and the compiler will implicitly do this it'll dereference p get the cat value and then call sleep on that cat value which we got from dereferencing and same thing down here when we call eat we could explicitly dereference but we don't normally do so and go because the compiler will do it for us and this is also true if we want to access the fields not just methods like say we want to create a variable z here which is an int variable and assign the age of the cat in p so we could do dereference p dot age and that's getting the cat value pointed to getting this age and assigning that to new int variable z but we don't have to actually explicitly dereference we can just write this and the compiler will implicitly do the dereference same if we assign to a dereference so we could explicitly write p dot age equals nine but we don't have to explicitly do the dereference if we just left it like this the compiler would do the dereference implicitly again be clear strictly speaking a pointer to a cat is not something that actually has its own fields or methods but the compiler knows that and says okay you must mean to dereference and so it'll do the dereference for you implicitly the receiver of a method not only can be a struct type it can also be a pointer to struct type so here again we have the the same cat struct we just defined the same sleep method but now the eat method is defined to have a receiver of not type cat but pointer to cat and so when eat is called it's called not on a regular cat but on a pointer to cat and the rule is that a struct and a pointer to that struct share the same set of methods so having to find sleep on cat i can't define a sleep method for pointer to cat and having to find eat for pointer to cat i can't define a method on regular cat so if i tried to write c cat eat and it wouldn't matter what else the signature is like it could be the same parameters are different so i've just made like a and this returns a string or something totally different regardless because we already have eat defined on pointer to cat we can't also have eat defined for regular cat so the compiler would object to having both of those we could only have one and the reason for this will be evident when we look down here in main we're creating the same variable c which is a cat and we're calling the sleep method just like we did before everything's same so far but now when we call c.eat this is valid but the eat method is not expecting a regular cat it wants a pointer to cat so implicitly what the compiler is doing for us is we could write this explicitly but it just does this for us implicitly if we write c.eat it gets a pointer to c and that is what we're calling the eat method on and oops there should actually of course be the argument 0.3 in there and same down here now that's correct yes this is just shorthand for this over here the compiler knows this is not a pointer and it knows that only pointer to cat has an eat method not cat itself so it knows that we need to get a reference to c implicitly and down here we're again creating a variable p which is a pointer to cat which is holding a reference to the c variable and if we call p.sleep well again like before the compiler knows to implicitly dereference p because p is not a regular cat it's a pointer to cat it knows you need to dereference first and then it can call the method sleep but then down here when we call p.eat p is a pointer to cat and that's what the eat method is expecting as its receiver so so the value of p is simply copied to c directly with no dereference or or reference and inside the method we've changed things a little bit here when we access c.weight c is a pointer to cat and of course pointers to cats don't really have their own fields this is implicitly dereferencing c and then accessing the weight field of that and this assignment where we're taking the current value of weight and incrementing it by food because the c here in eat is now effectively a pointer to this variable c from main this assignment is modifying the cat value stored in c what was 15.2 here in c is now 15.5 anyway having modified c.weight when we then access it here in the return statement it's now 15.5 and that's what's returned from the method call and then back in main here after the call to eat when we access p.weight or in fact if we were to access c.weight it would be the same thing because p points to c we get the value 15.5 because the method call has effectively modified the cat that was passed in that's one reason why you would want the receiver to be a pointer rather than the cat type itself because when we receive a pointer we can modify the thing passed in if we just had a regular cat we wouldn't be modifying cat back in main we'd just be modifying the local cat inside the eat method and the change wouldn't be seen outside the method the reason we're not allowed to have a method of a particular name like say eat defined for both cat and pointer to cat but wouldn't create an ambiguity for the compiler but it would create scenarios where you you may end up accidentally changing how a method behaves because of the simplistic behavior where if you call a method on a pointer it'll automatically dereference or vice versa if you call a method a non pointer if necessary it'll get a reference to the thing if the method is expecting a pointer like imagine here if I could come and add a method on regular cat of eat and we'll just give it the same signature and now we just do something in there and now down here when we call c.eat well before it was implicitly getting a reference to see and calling this version but then if this were allowed you would expect this call to be calling this one instead so there would be a potential for creating new methods which would change what gets called from existing calls in a way that could be very unexpected and create problems so so because of this allows this convenience of automatically referencing and dereferencing when we call methods you wouldn't want to have methods defined for both cat and pointer to cat at the same time it would create accidents so if we can define methods on pointer types can those pointer types then also implement interfaces and the answer is yes and the rule governing this is a little strange the rule is that if you implement for an interface all of the methods of that interface for some type t for the non pointer type then automatically both t and pointer to t are considered to implement the interface but this doesn't go both ways if you implement all the methods of an interface on some pointer type t then only pointer type t implements the interface not regular t and in fact if you implement all the methods of an interface some on t and some on pointer to t is as soon as just one of them is implemented for pointer to t rather than t then only pointer to t will implement the interface so here a concrete example if we have this interface animal with three methods eat sleep and drink and our type cat a regular cat non pointer cat is implementing all the methods then not only does cat implement the interface but also pointer to cat will implement the interface animal and so down here in main if I create a variable of type animal I can create a variable of type a and assign a cat to it but it can also assign pointers to cat to it and that's also okay because both cat and pointer to cat implement the interface however as soon as any one of these like say sleepier if I make it have a receiver of pointer to cat instead of regular cat well now only pointer to cat implements the interface and this here would be a compile error regular cat we couldn't assign to a because it wouldn't be considered to implement the animal interface very strangely this doesn't affect what happens when given a cat or pointer to cat when we call these methods having defined all these methods we can call any one of them on a cat or pointer to cat and the go compiler will as appropriate either reference or dereference the thing as needed to call the method for the the cat or pointer to cat but it's a separate question of whether cat and or pointer to cat implement the interface and so as soon as any one of the methods is implemented on pointer to cat rather than the cat it could just be one it could be two of them could be all of them well then only pointer to cat the implements the interface and remember the rule having defined a method eat on pointer to cat we can't also define it on cat or vice versa given a particular method name it can only be implemented on either cat or pointer to cat not both so the only way to implement the method on a non-pointer type is to have all the methods implemented on the non-pointer type and this is the only way that cat will implement the interface but effectively whenever cat implements the interface and pointed cat will also always implement the interface why does asymmetry why does it not work both ways the answer for that is quite archaic if the rule did work both ways it would create scenarios where you might do certain things on accident it's a very archaic scenario but that's why the rules are this way to avoid those strange accidents so now the question is does this imply that you should always implement your methods on the non-pointer type so they're conveniently both a pointer and non-pointer type would implement the interface because that's only way to have both and the answer is well sometimes that's useful but sometimes it isn't and the trade-off is that sometimes you want your methods to have pointer receivers because you don't want to pass the full thing keep in mind with non-pointer parameters to a function or or non-pointer receivers for methods the thing itself is being copied and full and imagine you had some struck type that was very large you may not necessarily want to pay the cost of of copying that thing in full every time you call the method and so in those cases you would probably want to have a pointer receiver rather than a non-pointer receiver so I think what most go programs do is just on a case-by-case basis they just decide whether a method should have a pointer receiver or a non-pointer receiver and they don't really think about the implication of which implements the interface because when in doubt well at least the pointer type will implement the interface right so even though you have to have all non-pointer receivers to implement an interface for both t and pointer to t I wouldn't really let that stop you from implementing methods with pointer receivers sometimes you just need a pointer receiver not only can we implement methods on structs and pointer distructs but we can also implement methods on named types and pointers to named types and yes that means that a name type and a pointer to a name type can implement interfaces and the rules are exactly the same so here for example we have some named type called time which is defined as a float 64 and so we can have a method fly where the receiver is of type time and a method kill where the receiver is a pointer to time and both are valid methods we couldn't though have a method defined on float 64 itself even though time and float 64 are really the same thing the compiler just will not allow it it only allows us to find methods on named types and structs not for any other thing I think the rationale for that is that well the built-in types are used in all parts of code so like you have your program and you're bringing in a bunch of packages that other people have written to make up your one program and if we could give methods to built-in types in one package then that that in a sense would be like redefining this thing used in other packages in a way that could be kind of strange and unexpected named types however are things that we ourselves are defining and oh yes there's one very important rule I haven't mentioned when you define methods on a type you can only do so in the package where that type is defined so when you define a struct or you define a named type all the methods you define for that type have to be defined in the same package recall that an interface value what it actually represents is a reference to some concrete value of some implementer of the interface and also a reference to the type of that value so say for example if we have an animal interface and it's implemented by both dog and cat well if I create an animal variable I can assign to it dogs or cats both are acceptable and say I assign it a dog what that variable is going to store is a reference to the dog value and also reference to the dog type and so what we will want to do sometimes with interface values is get at the concrete value which it references and get it as its type to do so we use a type switch and here's the syntax we had in go pigeon where here's a function foo as a single parameter f of type fruit where fruit is an interface implemented by both banana orange and perhaps some other types as well and so to switch over this interface value right type switch an expression which gives us an interface value here and then we have cases for the different possibilities of what it might be it might be a banana might be an orange or it might be something else and we don't have to have default that's optional but if it's there it's at the end we don't have to have either banana or orange we can leave them out so we can just choose which cases we care about but what happens is that in the case that this fruit value here is referencing a banana then the banana case runs and in that banana case we access the banana value as b it's stored in this variable b that exists only in this body but then in the case it's not a banana and instead an orange then this orange case runs and the value stored in this variable o and if it's not a banana or an orange if none of the cases match then the default is executed and if we want to access the the value well we have it as the fruit value f so we just use that instead the equivalent in go is written with the word switch not type switch and then you have here's the interface value just some expression that gets us back in interface value in this case of fruit then you write dot and then in print you have the reserved word type it is a reserved word I don't know what's not highlighted here the editor should be highlighting it but it's not and then you have colon equals with a variable which you're assigning that value to and then you have the different cases notice there's no variable name here just have the type names and in the banana case if you want to access the banana it will be available as the variable x and in the orange case if you want to access the orange it'll be available as x and in the default case if you want to access the original interface value it's available as x so x is present in all of these different cases and the default but the strange thing is that it has the different type in the different cases on the default and in the banana case it'll be a banana in the orange case it'll be an orange and in the default case, it'll be the original interface type, in this case, fruit. Sometimes given an interface value, we just want to test if it's one specific type, not multiple types. And so in that case, it's generally more convenient to use what's called a type assertion rather than a type switch. And a type assertion is an operation where you have your interface value, and you write dot, and then in parenz, you put the concrete type name you want to assert which this thing is. And what we get back is two values, we get back, in this case, because we're certain that that f here, this fruit value is a banana, we get back a banana value, but we also always get back a boolean. And that boolean will be true if this interface value actually is a banana, if it's referencing a banana. Otherwise, if it's referencing some other type, like say an orange or mango or something, then okay, we'll be false. And regardless whether the interface value is actually referencing a banana, it could be something else, it could be an orange, could be something totally different. But regardless, we always get back a banana value, which is being assigned to be here. And of course, in the event that f is storing a banana, then we get back a copy of that banana value, the value which f is referencing. But in the event of something else, what we get back for this banana value here will be the default value, the so called zero value of the banana type. And so what we want to do generally after performing the type assertion is you want to look at the boolean and branch accordingly of like, okay, it was a banana. And so now we can use B as a banana. And so in here, the value of B will be useful. Whereas otherwise, in this else clause, the value of B is simply just the zero value for banana, and not really useful. So you'll want to branch accordingly after doing type assertions. And of course, we can use the convenient colon equals syntax here, we just use colon equals, and we wouldn't have to explicitly declare these variables. In fact, if I left these variable declarations here, the compiler would complain that we're redeclering being okay. And it wouldn't like that. So you'd want to get rid of these after using colon equals syntax. Now, sometimes when you do a type assertion, you might in a certain context be very confident that a particular interface value is referencing a value of a particular type. You might be really confident that this fruit value f here is really always going to be a banana. Because you've arranged it in your code that that's how the logic works. Every time foo is called the fruit value passed in is always banana. That'd be a strange thing to do. You might as well then just make the parameter banana, but just go along with the scenario here. So in those cases where you're absolutely confident that it's going to be a specific type, then you can use a so called single value context form, where we're not returning two values, we're just returning one. And so there's only one target of assignment here just the banana, there's no Boolean. Be careful about this though, because what will happen if f is not actually a banana in this single context form rather than a multi value context form? When this type assertion is performed at runtime, if this f here is not a banana, then you get a panic, you get a runtime error. And generally then that means your code will abort. So be careful only to use this single value context form of a type assertion in context where you're very, very confident that it's going to be that specific type and always going to be that specific type. If it's ever in doubt, then you should use the multi value context form, the form that also returns a Boolean, like here.