I couldn't understand this part

If someone could explain this challenge please.
I neither understood the given code, nor did I understand why it had to be solved that way.
(P.S: I read the get help forum page --> didn’t really help me)

Challenge: Understand the Hazards of Using Imperative Code

Link to the challenge:

Hello!

The code shows a basic tab management in the browser. It’s just an array that contains the titles of each one, not the functionality a browser actually has.

The challenge is trying to explain why side effects are bad.

In case you don’t know:

A side effect is the modification of a value by a expression or inside the local scope of a function.

TL;DR; Try copying and pasting the entire code into Python Tutor, which will show the program execution step by step :slight_smile:.

Side Effects Example

For instance, if we need a function to retrieve the last element of an array:

/**
   * Retrieves the last element from an array.
   *
   * @param array A reference to the input array.
   * @return The last element on the array.
   */
function lastElement(array) {
  // This is a side effect, since we should ONLY return
  // the last element, not modify the input array
  return array.pop();
}

const seed = [ 1, 2, 3 ];
console.log('Initial Array:', seed);
// Output: [ 1, 2, 3 ]
const last = lastElement(seed);
console.log('Last element:', last);
// Output: 3
// The seed should not have been modified
console.log('After lastElement call:', seed);
// Output: [ 1, 2 ]

No problem will arise in this example, but what happens if the array is meant to be used by another developer that expects the input array to not be modified? How would he know that it was modified (assuming he doesn’t have access to the code and the documentation doesn’t say so)?

A better way to write the function would be:

function lastElement(array) {
  // We return the last element without modifying the array
  // Without side effects
  // (This is not the only way to do it)
  return array[array.length - 1];
}

const seed = [ 1, 2, 3 ];

console.log('Initial array:', seed);
// Output: [ 1, 2, 3 ]

const last = lastElement(seed);
console.log('Last element:', last);
// Output: 3, same output as before

console.log('After lastElement call:', seed);
// Output: [ 1, 2, 3 ], the array was not modified!

Side effects only affect values that are passed by reference or mutable objects (strings are immutable, for instance, and hence would not modify the input argument). Read this to learn more about pass or call by reference.

Back to the challenge, the tabClose method has a side effect on itself. The method definition is this:

Window.prototype.tabClose = function (index) {
  var tabsBeforeIndex = this.tabs.splice(0, index); // Get the tabs before the tab
  var tabsAfterIndex = this.tabs.splice(index + 1); // Get the tabs after the tab

  this.tabs = tabsBeforeIndex.concat(tabsAfterIndex); // Join them together

  return this;
 };

The first thing that we should do is read the definition of the methods/functions used in tabClose. If we read the definition of splice it says:

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

Among the important parts is that it says, explicitly that it changes the array contents, which should hint us where the problem resides.

Analyzing the function we get this:

For brevity, I’ll work with the videoWindow. So, the initial array is this:

var videoWindow = ['Netflix', 'YouTube', 'Vimeo', 'Vine'];

Now, let’s assume we want to remove the 'Youtube' tab, which at index 1

Window.prototype.tabClose = function (index) {
  // this.tabs has the same contents as videoWindow
  var tabsBeforeIndex = this.tabs.splice(0, index);
  // this.tabs = [ "YouTube", "Vimeo", "Vine" ], the array was modified ergo the index count too!
  var tabsAfterIndex = this.tabs.splice(index + 1);
  // this.tabs = [ "YouTube", "Vimeo" ], Vimeo shouldn't be here, what happened?
  this.tabs = tabsBeforeIndex.concat(tabsAfterIndex);
  // this.tabs = [ "Netflix", "Vine" ], what?! Where's "Vimeo"?
  return this;
};
// We would be removing the 'Youtube' tab
// (At least that's what we would expect)
videoWindow.tabClose(1);

The idea was to remove only Youtube but instead we removed two elements, what happened?

The problem is that with the first call to the splice method we modified the array, which in turns modified the array length and index count, hence the second call to splice removed more elements than it should have.

Thanks very much.
I didn’t expect such a long and detailed answer.
This really helped and it cleared out many doubts I had.
I solved this first using slice() instead of splice() but I couldn’t know why it worked.

So thank you very much.

Happy to help :slight_smile:!

Hmm, me neither :laughing:!

Anyway, I hope you continue to learn and learn a lot,

Happy coding!

1 Like