One place for hosting & domains

      Understanding

      Understanding Pointers in Go


      Introduction

      When you write software in Go you’ll be writing functions and methods. You pass data to these functions as arguments. Sometimes, the function needs a local copy of the data, and you want the original to remain unchanged. For example, if you’re a bank, and you have a function that shows the user the changes to their balance depending on the savings plan they choose, you don’t want to change the customer’s actual balance before they choose a plan; you just want to use it in calculations. This is called passing by value, because you’re sending the value of the variable to the function, but not the variable itself.

      Other times, you may want the function to be able to alter the data in the original variable. For instance, when the bank customer makes a deposit to their account, you want the deposit function to be able to access the actual balance, not a copy. In this case, you don’t need to send the actual data to the function; you just need to tell the function where the data is located in memory. A data type called a pointer holds the memory address of the data, but not the data itself. The memory address tells the function where to find the data, but not the value of the data. You can pass the pointer to the function instead of the data, and the function can then alter the original variable in place. This is called passing by reference, because the value of the variable isn’t passed to the function, just its location.

      In this article, you will create and use pointers to share access to the memory space for a variable.

      Defining and Using Pointers

      When you use a pointer to a variable, there are a couple of different syntax elements that you need to understand. The first one is the use of the ampersand (&). If you place an ampersand in front of a variable name, you are stating that you want to get the address, or a pointer to that variable. The second syntax element is the use of the asterisk (*) or dereferencing operator. When you declare a pointer variable, you follow the variable name with the type of the variable that the pointer points to, prefixed with an *, like this:

      var myPointer *int32 = &someint
      

      This creates myPointer as a pointer to an int32 variable, and initializes the pointer with the address of someint. The pointer doesn’t actually contain an int32, just the address of one.

      Let’s take a look at a pointer to a string. The following code declares both a value of a string, and a pointer to a string:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          var creature string = "shark"
          var pointer *string = &creature
      
          fmt.Println("creature =", creature)
          fmt.Println("pointer =", pointer)
      }
      
      

      Run the program with the following command:

      When you run the program, it will print out the value of the variable, as well as the address of where the variable is stored (the pointer address). The memory address is a hexadecimal number, and not meant to be human-readable. In practice, you’ll probably never output a memory address to look at it. We’re showing you for illustrative purposes. Because each program is created in its own memory space when it is run, the value of the pointer will be different each time you run it, and will be different than the output shown here:

      Output

      creature = shark pointer = 0xc0000721e0

      The first variable we defined we named creature, and set it equal to a string with the value of shark. We then created another variable named pointer. This time, we set the value of the pointer variable to the address of the creature variable. We store the address of a value in a variable by using the ampersand (&) symbol. This means that the pointer variable is storing the address of the creature variable, not the actual value.

      This is why when we printed out the value of pointer, we received the value of 0xc0000721e0, which is the address of where the creature variable is currently stored in computer memory.

      If you want to print out the value of the variable being pointed at from the pointer variable, you need to dereference that variable. The following code uses the * operator to dereference the pointer variable and retrieve its value:

      main.go

      
      package main
      
      import "fmt"
      
      func main() {
          var creature string = "shark"
          var pointer *string = &creature
      
          fmt.Println("creature =", creature)
          fmt.Println("pointer =", pointer)
      
          fmt.Println("*pointer =", *pointer)
      }
      

      If you run this code, you’ll see the following output:

      Output

      creature = shark pointer = 0xc000010200 *pointer = shark

      The last line we added now dereferences then pointer variable, and prints out the value that is stored at that address.

      If you want to modify the value stored at the pointer variable’s location, you can use the dereference operator as well:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          var creature string = "shark"
          var pointer *string = &creature
      
          fmt.Println("creature =", creature)
          fmt.Println("pointer =", pointer)
      
          fmt.Println("*pointer =", *pointer)
      
          *pointer = "jellyfish"
          fmt.Println("*pointer =", *pointer)
      }
      
      

      Run this code to see the output:

      Output

      creature = shark pointer = 0xc000094040 *pointer = shark *pointer = jellyfish

      We set the value the pointer variable refers to by using the asterisk (*) in front of the variable name, and then providing a new value of jellyfish. As you can see, when we print the dereferenced value, it is now set to jellyfish.

      You may not have realized it, but we actually changed the value of the creature variable as well. This is because the pointer variable is actually pointing at the creature variable’s address. This means that if we change the value pointed at from the pointer variable, we also change the value of the creature variable.

      main.go

      package main
      
      import "fmt"
      
      func main() {
          var creature string = "shark"
          var pointer *string = &creature
      
          fmt.Println("creature =", creature)
          fmt.Println("pointer =", pointer)
      
          fmt.Println("*pointer =", *pointer)
      
          *pointer = "jellyfish"
          fmt.Println("*pointer =", *pointer)
      
          fmt.Println("creature =", creature)
      }
      

      The output looks like this:

      Output

      creature = shark pointer = 0xc000010200 *pointer = shark *pointer = jellyfish creature = jellyfish

      Although this code illustrates how a pointer works, this is not the typical way in which you would use pointers in Go. It is more common to use them when defining function arguments and return values, or using them when defining methods on custom types. Let’s look at how you would use pointers with functions to share access to a variable.

      Again, keep in mind that we are printing the value of pointer to illustrate that it is a pointer. In practice, you wouldn’t use the value of a pointer, other than to reference the underlying value to retrieve or update that value.

      Function Pointer Receivers

      When you write a function, you can define arguments to be passed ether by value, or by reference. Passing by value means that a copy of that value is sent to the function, and any changes to that argument within that function only effect that variable within that function, and not where it was passed from. However, if you pass by reference, meaning you pass a pointer to that argument, you can change the value from within the function, and also change the value of the original variable that was passed in. You can read more about how to define functions in our How To Define and Call Functions in Go.

      Deciding when to pass a pointer as opposed when to send a value is all about knowing if you want the value to change or not. If you don’t want the value to change, send it as a value. If you want the function you are passing your variable to be able to change it, then you would pass it as a pointer.

      To see the difference, let’s first look at a function that is passing in an argument by value:

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func main() {
          var creature Creature = Creature{Species: "shark"}
      
          fmt.Printf("1) %+vn", creature)
          changeCreature(creature)
          fmt.Printf("3) %+vn", creature)
      }
      
      func changeCreature(creature Creature) {
          creature.Species = "jellyfish"
          fmt.Printf("2) %+vn", creature)
      }
      
      

      The output looks like this:

      Output

      1) {Species:shark} 2) {Species:jellyfish} 3) {Species:shark}

      First we created a custom type named Creature. It has one field named Species, which is a string. In the main function, we created an instance of our new type named creature and set the Species field to shark. We then printed out the variable to show the current value stored within the creature variable.

      Next, we call changeCreature and pass in a copy of the creature variable.

      The function changeCreature is defined as taking one argument named creature, and it is of type Creature that we defined earlier. We then change the value of the Species field to jellyfish and print it out. Notice that within the changeCreature function, the value of Species is now jellyfish, and it prints out 2) {Species:jellyfish}. This is because we are allowed to change the value within our function scope.

      However, when the last line of the main function prints the value of creature, the value of Species is still shark. The reason that the value didn’t change is because we passed the variable by value. This means that a copy of the value was created in memory, and passed to the changeCreature function. This allows us to have a function that can make changes to any arguments passed in as needed, but will not affect any of those variables outside of the function.

      Next, let’s change the changeCreature function to take an argument by reference. We can do this by changing the type from creature to a pointer by using the asterisk (*) operator. Instead of passing a creature, we’re now passing a pointer to a creature, or a *creature. In the previous example, creature is a struct that has a Species value of shark. *creature is a pointer, not a struct, so its value is a memory location, and that’s what we pass to changeCreature().

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func main() {
          var creature Creature = Creature{Species: "shark"}
      
          fmt.Printf("1) %+vn", creature)
          changeCreature(&creature)
          fmt.Printf("3) %+vn", creature)
      }
      
      func changeCreature(creature *Creature) {
          creature.Species = "jellyfish"
          fmt.Printf("2) %+vn", creature)
      }
      

      Run this code to see the following output:

      Output

      1) {Species:shark} 2) &{Species:jellyfish} 3) {Species:jellyfish}

      Notice that now when we change the value of Species to jellyfish in the changeCreature function, it changes the original value defined in the main function as well. This is because we passed the creature variable by reference, which allows access to the original value and can change it as needed.

      Therefore, if you want a function to be able to change a value, you need to pass it by reference. To pass by reference, you pass the pointer to the variable, and not the variable itself.

      However, sometimes you may not have an actual value defined for a pointer. In those cases, it is possible to have a panic in the program. Let’s look at how that happens and how to plan for that potential problem.

      Nil Pointers

      All variables in Go have a zero value. This is true even for a pointer. If you declare a pointer to a type, but assign no value, the zero value will be nil. nil is a way to say that nothing has been initialized for the variable.

      In the following program, we are defining a pointer to a Creature type, but we are never instantiating that actual instance of a Creature and assigning the address of it to the creature pointer variable. The value will be nil and we can’t reference any of the fields or methods that would be defined on the Creature type:

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func main() {
          var creature *Creature
      
          fmt.Printf("1) %+vn", creature)
          changeCreature(creature)
          fmt.Printf("3) %+vn", creature)
      }
      
      func changeCreature(creature *Creature) {
          creature.Species = "jellyfish"
          fmt.Printf("2) %+vn", creature)
      }
      

      The output looks like this:

      Output

      1) <nil> panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x109ac86] goroutine 1 [running]: main.changeCreature(0x0) /Users/corylanou/projects/learn/src/github.com/gopherguides/learn/_training/digital-ocean/pointers/src/nil.go:18 +0x26 main.main() /Users/corylanou/projects/learn/src/github.com/gopherguides/learn/_training/digital-ocean/pointers/src/nil.go:13 +0x98 exit status 2

      When we run the program, it printed out the value of the creature variable, and the value is <nil>. We then call the changeCreature function, and when that function tries to set the value of the Species field, it panics. This is because there is no instance of the variable actually created. Because of this, the program has no where to actually store the value, so the program panics.

      It is common in Go that if you are receiving an argument as a pointer, you check to see if it was nil or not before performing any operations on it to prevent the program from panicking.

      This is a common approach for checking for nil:

      if someVariable == nil {
          // print an error or return from the method or fuction
      }
      

      Effectively you want to make sure you don’t have a nil pointer that was passed into your function or method. If you do, you’ll likely just want to return, or return an error to show that an invalid argument was passed to the function or method. The following code demonstrates checking for nil:

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func main() {
          var creature *Creature
      
          fmt.Printf("1) %+vn", creature)
          changeCreature(creature)
          fmt.Printf("3) %+vn", creature)
      }
      
      func changeCreature(creature *Creature) {
          if creature == nil {
              fmt.Println("creature is nil")
              return
          }
      
          creature.Species = "jellyfish"
          fmt.Printf("2) %+vn", creature)
      }
      

      We added a check in the changeCreature to see if the value of the creature argument was nil. If it was, we print out creature is nil, and return out of the function. Otherwise, we continue and change the value of the Species field. If we run the program, we will now get the following output:

      Output

      1) <nil> creature is nil 3) <nil>

      Notice that while we still had a nil value for the creature variable, we are no longer panicking because we are checking for that scenario.

      Finally, if we create an instance of the Creature type and assign it to the creature variable, the program will now change the value as expected:

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func main() {
          var creature *Creature
          creature = &Creature{Species: "shark"}
      
          fmt.Printf("1) %+vn", creature)
          changeCreature(creature)
          fmt.Printf("3) %+vn", creature)
      }
      
      func changeCreature(creature *Creature) {
          if creature == nil {
              fmt.Println("creature is nil")
              return
          }
      
          creature.Species = "jellyfish"
          fmt.Printf("2) %+vn", creature)
      }
      

      Now that we have an instance of the Creature type, the program will run and we will get the following expected output:

      Output

      1) &{Species:shark} 2) &{Species:jellyfish} 3) &{Species:jellyfish}

      When you are working with pointers, there is a potential for the program to panic. To avoid panicking, you should check to see if a pointer value is nil prior to trying to access any of the fields or methods defined on it.

      Next, let’s look at how using pointers and values affects defining methods on a type.

      Method Pointer Receivers

      A receiver in go is the argument that is defined in a method declaration. Take a look at the following code:

      type Creature struct {
          Species string
      }
      
      func (c Creature) String() string {
          return c.Species
      }
      

      The receiver in this method is c Creature. It is stating that the instance of c is of type Creature and you will reference that type via that instance variable.

      Just like the behavior of functions is different based on whether you send in an argument as a pointer or a value, methods also have different behavior. The big difference is that if you define a method with a value receiver, you are not able to make changes to the instance of that type that the method was defined on.

      There will be times that you would like your method to be able to update the instance of the variable that you are using. To allow for this, you would want to make the receiver a pointer.

      Let’s add a Reset method to our Creature type that will set the Species field to an empty string:

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func (c Creature) Reset() {
          c.Species = ""
      }
      
      func main() {
          var creature Creature = Creature{Species: "shark"}
      
          fmt.Printf("1) %+vn", creature)
          creature.Reset()
          fmt.Printf("2) %+vn", creature)
      }
      

      If we run the program, we will get the following output:

      Output

      1) {Species:shark} 2) {Species:shark}

      Notice that even though in the Reset method we set the value of Species to an empty string, that when we print out the value of our creature variable in the main function, the value is still set to shark. This is because we defined the Reset method has having a value receiver. This means that the method will only have access to a copy of the creature variable.

      If we want to be able to modify the instance of the creature variable in the methods, we need to define them as having a pointer receiver:

      main.go

      package main
      
      import "fmt"
      
      type Creature struct {
          Species string
      }
      
      func (c *Creature) Reset() {
          c.Species = ""
      }
      
      func main() {
          var creature Creature = Creature{Species: "shark"}
      
          fmt.Printf("1) %+vn", creature)
          creature.Reset()
          fmt.Printf("2) %+vn", creature)
      }
      

      Notice that we now added an asterisk (*) in front of the Creature type in when we defined the Reset method. This means that the instance of Creature that is passed to the Reset method is now a pointer, and as such when we make changes it will affect the original instance of that variables.

      Output

      1) {Species:shark} 2) {Species:}

      The Reset method has now changed the value of the Species field.

      Conclusion

      Defining a function or method as a pass by value or pass by reference will affect what parts of your program are able to make changes to other parts. Controlling when that variable can be changed will allow you to write more robust and predictable software. Now that you have learned about pointers, you can see how they are used in interfaces as well.



      Source link

      Understanding This, Bind, Call, and Apply in JavaScript


      The author selected the Open Internet/Free Speech Fund to receive a donation as part of the Write for DOnations program.

      The this keyword is a very important concept in JavaScript, and also a particularly confusing one to both new developers and those who have experience in other programming languages. In JavaScript, this is a reference to an object. The object that this refers to can vary, implicitly based on whether it is global, on an object, or in a constructor, and can also vary explicitly based on usage of the Function prototype methods bind, call, and apply.

      Although this is a bit of a complex topic, it is also one that appears as soon as you begin writing your first JavaScript programs. Whether you’re trying to access an element or event in the Document Object Model (DOM), building classes for writing in the object-oriented programming style, or using the properties and methods of regular objects, you will encounter this.

      In this article, you’ll learn what this refers to implicitly based on context, and you’ll learn how to use the bind, call, and apply methods to explicitly determine the value of this.

      Implicit Context

      There are four main contexts in which the value of this can be implicitly inferred:

      • the global context
      • as a method within an object
      • as a constructor on a function or class
      • as a DOM event handler

      Global

      In the global context, this refers to the global object. When you’re working in a browser, the global context is would be window. When you’re working in Node.js, the global context is global.

      Note: If you are not yet familiar with the concept of scope in JavaScript, please review Understanding Variables, Scope, and Hoisting in JavaScript.

      For the examples, you will practice the code in the browser’s Developer Tools console. Read How to Use the JavaScript Developer Console if you are not familiar with running JavaScript code in the browser.

      If you log the value of this without any other code, you will see what object this refers to.

      console.log(this)
      

      Output

      Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

      You can see that this is window, which is the global object of a browser.

      In Understanding Variables, Scope, and Hoisting in JavaScript, you learned that functions have their own context for variables. You might be tempted to think that this would follow the same rules inside a function, but it does not. A top-level function will still retain the this reference of the global object.

      You write a top-level function, or a function that is not associated with any object, like this:

      function printThis() {
        console.log(this)
      }
      
      printThis()
      

      Output

      Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

      Even within a function, this still refers to the window, or global object.

      However, when using strict mode, the context of this within a function on the global context will be undefined.

      'use strict'
      
      function printThis() {
        console.log(this)
      }
      
      printThis()
      

      Output

      undefined

      Generally, it is safer to use strict mode to reduce the probability of this having an unexpected scope. Rarely will someone want to refer to the window object using this.

      For more information about strict mode and what changes it makes regarding mistakes and security, read the Strict mode documentation on MDN.

      An Object Method

      A method is a function on an object, or a task that an object can perform. A method uses this to refer to the properties of the object.

      const america = {
        name: 'The United States of America',
        yearFounded: 1776,
      
        describe() {
          console.log(`${this.name} was founded in ${this.yearFounded}.`)
        },
      }
      
      america.describe()
      

      Output

      "The United States of America was founded in 1776."

      In this example, this is the same as america.

      In a nested object, this refers to the current object scope of the method. In the following example, this.symbol within the details object refers to details.symbol.

      const america = {
        name: 'The United States of America',
        yearFounded: 1776,
        details: {
          symbol: 'eagle',
          currency: 'USD',
          printDetails() {
            console.log(`The symbol is the ${this.symbol} and the currency is ${this.currency}.`)
          },
        },
      }
      
      america.details.printDetails()
      

      Output

      "The symbol is the eagle and the currency is USD."

      Another way of thinking about it is that this refers to the object on the left side of the dot when calling a method.

      A Function Constructor

      When you use the new keyword, it creates an instance of a constructor function or class. Function constructors were the standard way to initialize a user-defined object before the class syntax was introduced in the ECMAScript 2015 update to JavaScript. In Understanding Classes in JavaScript, you will learn how to create a function constructor and an equivalent class constructor.

      function Country(name, yearFounded) {
        this.name = name
        this.yearFounded = yearFounded
      
        this.describe = function() {
          console.log(`${this.name} was founded in ${this.yearFounded}.`)
        }
      }
      
      const america = new Country('The United States of America', 1776)
      
      america.describe()
      

      Output

      "The United States of America was founded in 1776."

      In this context, this is now bound to the instance of Country, which is contained in the america constant.

      A Class Constructor

      A constructor on a class acts the same as a constructor on a function. Read more about the similarities and differences between function constructors and ES6 classes in Understanding Classes in JavaScript.

      class Country {
        constructor(name, yearFounded) {
          this.name = name
          this.yearFounded = yearFounded
        }
      
        describe() {
          console.log(`${this.name} was founded in ${this.yearFounded}.`)
        }
      }
      
      const america = new Country('The United States of America', 1776)
      
      america.describe()
      

      this in the describe method refers to the instance of Country, which is america.

      Output

      "The United States of America was founded in 1776."

      A DOM Event Handler

      In the browser, there is a special this context for event handlers. In an event handler called by addEventListener, this will refer to event.currentTarget. More often than not, developers will simply use event.target or event.currentTarget as needed to access elements in the DOM, but since the this reference changes in this context, it is important to know.

      In the following example, we’ll create a button, add text to it, and append it to the DOM. When we log the value of this within the event handler, it will print the target.

      const button = document.createElement('button')
      button.textContent = 'Click me'
      document.body.append(button)
      
      button.addEventListener('click', function(event) {
        console.log(this)
      })
      

      Output

      <button>Click me</button>

      Once you paste this into your browser, you will see a button appended to the page that says “Click me”. If you click the button, you will see <button>Click me</button> appear in your console, as clicking the button logs the element, which is the button itself. Therefore, as you can see, this refers to the targeted element, which is the element we added an event listener to.

      Explicit Context

      In all of the previous examples, the value of this was determined by its context—whether it is global, in an object, in a constructed function or class, or on a DOM event handler. However, using call, apply, or bind, you can explicitly determine what this should refer to.

      It is difficult to define exactly when to use call, apply, or bind, as it will depend on the context of your program. bind can be particularly helpful when you want to use events to access properties of one class within another class. For example, if you were to write a simple game, you might separate the user interface and I/O into one class, and the game logic and state into another. Since the game logic would need to access input, such as key press and click, you would want to bind the events to access the this value of the game logic class.

      The important part is to know how to determine what object this refers to, which you can do implicitly with what you learned in the previous sections, or explicitly with the three methods you will learn next.

      Call and Apply

      call and apply are very similar—they invoke a function with a specified this context, and optional arguments. The only difference between call and apply is that call requires the arguments to be passed in one-by-one, and apply takes the arguments as an array.

      In this example, we’ll create an object, and create a function that references this but has no this context.

      const book = {
        title: 'Brave New World',
        author: 'Aldous Huxley',
      }
      
      function summary() {
        console.log(`${this.title} was written by ${this.author}.`)
      }
      
      summary()
      

      Output

      "undefined was written by undefined"

      Since summary and book have no connection, invoking summary by itself will only print undefined, as it’s looking for those properties on the global object.

      Note: Attempting this in strict mode would result in Uncaught TypeError: Cannot read property 'title' of undefined, as this itself would be undefined.

      However, you can use call and apply to invoke the this context of book on the function.

      summary.call(book)
      // or:
      summary.apply(book)
      

      Output

      "Brave New World was written by Aldous Huxley."

      There is now a connection between book and summary when these methods are applied. Let’s confirm exactly what this is.

      function printThis() {
        console.log(this)
      }
      
      printThis.call(book)
      // or:
      whatIsThis.apply(book)
      

      Output

      {title: "Brave New World", author: "Aldous Huxley"}

      In this case, this actually becomes the object passed as an argument.

      This is how call and apply are the same, but there is one small difference. In addition to being able to pass the this context as the first argument, you can also pass additional arguments through.

      function longerSummary(genre, year) {
        console.log(
          `${this.title} was written by ${this.author}. It is a ${genre} novel written in ${year}.`
        )
      }
      

      With call each additional value you want to pass is sent as an additional argument.

      longerSummary.call(book, 'dystopian', 1932)
      

      Output

      "Brave New World was written by Aldous Huxley. It is a dystopian novel written in 1932."

      If you try to send the exact same arguments with apply, this is what happens:

      longerSummary.apply(book, 'dystopian', 1932)
      

      Output

      Uncaught TypeError: CreateListFromArrayLike called on non-object at <anonymous>:1:15

      Instead, for apply, you have to pass all the arguments in an array.

      longerSummary.apply(book, ['dystopian', 1932])
      

      Output

      "Brave New World was written by Aldous Huxley. It is a dystopian novel written in 1932."

      The difference between passing the arguments individually or in an array is subtle, but it’s important to be aware of. It might be simpler and more convenient to use apply, as it would not require changing the function call if some parameter details changed.

      Bind

      Both call and apply are one-time use methods—if you call the method with the this context it will have it, but the original function will remain unchanged.

      Sometimes, you might need to use a method over and over with the this context of another object, and in that case you could use the bind method to create a brand new function with an explicitly bound this.

      const braveNewWorldSummary = summary.bind(book)
      
      braveNewWorldSummary()
      

      Output

      "Brave New World was written by Aldous Huxley"

      In this example, every time you call braveNewWorldSummary, it will always return the original this value bound to it. Attempting to bind a new this context to it will fail, so you can always trust a bound function to return the this value you expect.

      const braveNewWorldSummary = summary.bind(book)
      
      braveNewWorldSummary() // Brave New World was written by Aldous Huxley.
      
      const book2 = {
        title: '1984',
        author: 'George Orwell',
      }
      
      braveNewWorldSummary.bind(book2)
      
      braveNewWorldSummary() // Brave New World was written by Aldous Huxley.
      

      Although this example tries to bind braveNewWorldSummary once again, it retains the original this context from the first time it was bound.

      Arrow Functions

      Arrow functions do not have their own this binding. Instead, they go up to the next level of execution.

      const whoAmI = {
        name: 'Leslie Knope',
        regularFunction: function() {
          console.log(this.name)
        },
        arrowFunction: () => {
          console.log(this.name)
        },
      }
      
      whoAmI.regularFunction() // "Leslie Knope"
      whoAmI.arrowFunction() // undefined
      

      It can be useful to use the arrow function in cases where you really want this to refer to the outer context. For example, if you had an event listener inside of a class, you would probably want this to refer to some value in the class.

      In this example, you’ll create and append button to the DOM like before, but the class will have an event listener that will change the text value of the button when clicked.

      const button = document.createElement('button')
      button.textContent = 'Click me'
      document.body.append(button)
      
      class Display {
        constructor() {
          this.buttonText = 'New text'
      
          button.addEventListener('click', event => {
            event.target.textContent = this.buttonText
          })
        }
      }
      
      new Display()
      

      If you click the button, the text content will change to the value of buttonText. If you hadn’t used an arrow function here, this would be equal to event.currentTarget, and you wouldn’t be able to use it to access a value within the class without explicitly binding it. This tactic is often used on class methods in frameworks like React.

      Conclusion

      In this article, you learned about this in JavaScript, and the many different values it might have based on implicit runtime binding, and explicit binding through bind, call, and apply. You also learned about how the lack of this binding in arrow functions can be used to refer to a different context. With this knowledge, you should be able to determine the value of this in your programs.



      Source link

      Understanding defer in Go


      Introduction

      Go has many of the common control-flow keywords found in other programming languages such as if, switch, for, etc. One keyword that isn’t found in most other programming languages is defer, and though it’s less common you’ll quickly see how useful it can be in your programs.

      One of the primary uses of a defer statement is for cleaning up resources, such as open files, network connections, and database handles. When your program is finished with these resources, it’s important to close them to avoid exhausting the program’s limits and to allow other programs access to those resources. defer makes our code cleaner and less error prone by keeping the calls to close the file/resource in proximity to the open call.

      In this article we will learn how to properly use the defer statement for cleaning up resources as well as several common mistakes that are made when using defer.

      What is a defer Statement

      A defer statement adds the function call following the defer keyword onto a stack. All of the calls on that stack are called when the function in which they were added returns. Because the calls are placed on a stack, they are called in last-in-first-out order.

      Let’s look at how defer works by printing out some text:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          defer fmt.Println("Bye")
          fmt.Println("Hi")
      }
      

      In the main function, we have two statements. The first statement starts with the defer keyword, followed by a print statement that prints out Bye. The next line prints out Hi.

      If we run the program, we will see the following output:

      Output

      Hi Bye

      Notice that Hi was printed first. This is because any statement that is preceded by the defer keyword isn’t invoked until the end of the function in which defer was used.

      Let’s take another look at the program, and this time we’ll add some comments to help illustrate what is happening:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          // defer statement is executed, and places
          // fmt.Println("Bye") on a list to be executed prior to the function returning
          defer fmt.Println("Bye")
      
          // The next line is executed immediately
          fmt.Println("Hi")
      
          // fmt.Println*("Bye") is now invoked, as we are at the end of the function scope
      }
      

      The key to understanding defer is that when the defer statement is executed, the arguments to the deferred function are evaluated immediately. When a defer executes, it places the statement following it on a list to be invoked prior to the function returning.

      Although this code illustrates the order in which defer would be run, it’s not a typical way it would be used when writing a Go program. It’s more likely we are using defer to clean up a resource, such as a file handle. Let’s look at how to do that next.

      Using defer to Clean Up Resources

      Using defer to clean up resources is very common in Go. Let’s first look at a program that writes a string to a file but does not use defer to handle the resource clean-up:

      main.go

      package main
      
      import (
          "io"
          "log"
          "os"
      )
      
      func main() {
          if err := write("readme.txt", "This is a readme file"); err != nil {
              log.Fatal("failed to write file:", err)
          }
      }
      
      func write(fileName string, text string) error {
          file, err := os.Create(fileName)
          if err != nil {
              return err
          }
          _, err = io.WriteString(file, text)
          if err != nil {
              return err
          }
          file.Close()
          return nil
      }
      

      In this program, there is a function called write that will first attempt to create a file. If it has an error, it will return the error and exit the function. Next, it tries to write the string This is a readme file to the specified file. If it receives an error, it will return the error and exit the function. Then, the function will try to close the file and release the resource back to the system. Finally the function returns nil to signify that the function executed without error.

      Although this code works, there is a subtle bug. If the call to io.WriteString fails, the function will return without closing the file and releasing the resource back to the system.

      We could fix the problem by adding another file.Close() statement, which is how you would likely solve this in a language without defer:

      main.go

      package main
      
      import (
          "io"
          "log"
          "os"
      )
      
      func main() {
          if err := write("readme.txt", "This is a readme file"); err != nil {
              log.Fatal("failed to write file:", err)
          }
      }
      
      func write(fileName string, text string) error {
          file, err := os.Create(fileName)
          if err != nil {
              return err
          }
          _, err = io.WriteString(file, text)
          if err != nil {
              file.Close()
              return err
          }
          file.Close()
          return nil
      }
      

      Now even if the call to io.WriteString fails, we will still close the file. While this was a relatively easy bug to spot and fix, with a more complicated function, it may have been missed.

      Instead of adding the second call to file.Close(), we can use a defer statement to ensure that regardless of which branches are taken during execution, we always call Close().

      Here’s the version that uses the defer keyword:

      main.go

      package main
      
      import (
          "io"
          "log"
          "os"
      )
      
      func main() {
          if err := write("readme.txt", "This is a readme file"); err != nil {
              log.Fatal("failed to write file:", err)
          }
      }
      
      func write(fileName string, text string) error {
          file, err := os.Create(fileName)
          if err != nil {
              return err
          }
          defer file.Close()
          _, err = io.WriteString(file, text)
          if err != nil {
              return err
          }
          return nil
      }
      

      This time we added the line of code: defer file.Close(). This tells the compiler that it should execute the file.Close prior to exiting the function write.

      We have now ensured that even if we add more code and create another branch that exits the function in the future, we will always clean up and close the file.

      However, we have introduced yet another bug by adding the defer. We are no longer checking the potential error that can be returned from the Close method. This is because when we use defer, there is no way to communicate any return value back to our function.

      In Go, it is considered a safe and accepted practice to call Close() more than once without affecting the behavior of your program. If Close() is going to return an error, it will do so the first time it is called. This allows us to call it explicitly in the successful path of execution in our function.

      Let’s look at how we can both defer the call to Close, and still report on an error if we encounter one.

      main.go

      package main
      
      import (
          "io"
          "log"
          "os"
      )
      
      func main() {
          if err := write("readme.txt", "This is a readme file"); err != nil {
              log.Fatal("failed to write file:", err)
          }
      }
      
      func write(fileName string, text string) error {
          file, err := os.Create(fileName)
          if err != nil {
              return err
          }
          defer file.Close()
          _, err = io.WriteString(file, text)
          if err != nil {
              return err
          }
      
          return file.Close()
      }
      

      The only change in this program is the last line in which we return file.Close(). If the call to Close results in an error, this will now be returned as expected to the calling function. Keep in mind that our defer file.Close() statement is also going to run after the return statement. This means that file.Close() is potentially called twice. While this isn’t ideal, it is an acceptable practice as it should not create any side effects to your program.

      If, however, we receive an error earlier in the function, such as when we call WriteString, the function will return that error, and will also try to call file.Close because it was deferred. Although file.Close may (and likely will) return an error as well, it is no longer something we care about as we received an error that is more likely to tell us what went wrong to begin with.

      So far, we have seen how we can use a single defer to ensure that we clean up our resources properly. Next we will see how we can use multiple defer statements for cleaning up more than one resource.

      Multiple defer Statements

      It is normal to have more than one defer statement in a function. Let’s create a program that only has defer statements in it to see what happens when we introduce multiple defers:

      main.go

      package main
      
      import "fmt"
      
      func main() {
          defer fmt.Println("one")
          defer fmt.Println("two")
          defer fmt.Println("three")
      }
      

      If we run the program, we will receive the following output:

      Output

      three two one

      Notice that the order is the opposite in which we called the defer statements. This is because each deferred statement that is called is stacked on top of the previous one, and then called in reverse when the function exits scope (Last In, First Out).

      You can have as many deferred calls as needed in a function, but it is important to remember they will all be called in the opposite order they were executed.

      Now that we understand the order in which multiple defers will execute, let’s see how we would use multiple defers to clean up multiple resources. We’ll create a program that opens a file, writes to it, then opens it again to copy the contents to another file.

      main.go

      package main
      
      import (
          "fmt"
          "io"
          "log"
          "os"
      )
      
      func main() {
          if err := write("sample.txt", "This file contains some sample text."); err != nil {
              log.Fatal("failed to create file")
          }
      
          if err := fileCopy("sample.txt", "sample-copy.txt"); err != nil {
              log.Fatal("failed to copy file: %s")
          }
      }
      
      func write(fileName string, text string) error {
          file, err := os.Create(fileName)
          if err != nil {
              return err
          }
          defer file.Close()
          _, err = io.WriteString(file, text)
          if err != nil {
              return err
          }
      
          return file.Close()
      }
      
      func fileCopy(source string, destination string) error {
          src, err := os.Open(source)
          if err != nil {
              return err
          }
          defer src.Close()
      
          dst, err := os.Create(destination)
          if err != nil {
              return err
          }
          defer dst.Close()
      
          n, err := io.Copy(dst, src)
          if err != nil {
              return err
          }
          fmt.Printf("Copied %d bytes from %s to %sn", n, source, destination)
      
          if err := src.Close(); err != nil {
              return err
          }
      
          return dst.Close()
      }
      

      We added a new function called fileCopy. In this function, we first open up our source file that we are going to copy from. We check to see if we received an error opening the file. If so, we return the error and exit the function. Otherwise, we defer the closing of the source file we just opened.

      Next we create the destination file. Again, we check to see if we received an error creating the file. If so, we return that error and exit the function. Otherwise, we also defer the Close() for the destination file. We now have two defer functions that will be called when the function exits its scope.

      Now that we have both files open, we will Copy() the data from the source file to the destination file. If that is successful, we will attempt to close both files. If we receive an error trying to close either file, we will return the error and exit function scope.

      Notice that we explicitly call Close() for each file, even though the defer will also call Close(). This is to ensure that if there is an error closing a file, we report the error. It also ensures that if for any reason the function exits early with an error, for instance if we failed to copy between the two files, that each file will still try to close properly from the deferred calls.

      Conclusion

      In this article we learned about the defer statement, and how it can be used to ensure that we properly clean up system resources in our program. Properly cleaning up system resources will make your program use less memory and perform better. To learn more about where defer is used, read the article on Handling Panics, or explore our entire How To Code in Go series.



      Source link