Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

This mergesort should "of" failed, right?

I noticed something weird while reviewing this mergesort implementation on Code Review…

/************************************************************
 * Mergesort implementation
 ***********************************************************/

function sort(array) {
  var len = array.length;
  var middle = Math.floor(len*0.5);
  var left = array.slice(0,middle);
  var right = array.slice(middle, len);

  if (len == 1) {
    return array;
  } else {

  }

  return merge(sort(left), sort(right));
}


function merge(left, right) {
  var a = left.length;
  var b = right.length;


  if (a > 0 && b > 0) {
    if (left[0] > right[0]) {
      return [].concat(left[0], merge(left.slice(1,a), right));
    } else {
      return [].concat(right[0], merge(right.slice(1,b), left));
    }
  } else if (a == 0) {
    return right;
  } else of (b == 0)
    return left;

}


/************************************************************
 * Demonstration
 ***********************************************************/

function doSort() {
    var array = document.getElementById('in').value.split(/[, ]+/).map(function(e) {
        return parseInt(e);
    });
    var sorted = sort(array);
    document.getElementById('out').value = sorted;
}

function generateRandom(len) {
    var array = [];
    for (var i = 0; i < len; i++) {
        array.push(Math.round(Math.random() * 100));
    }
    document.getElementById('in').value = array;
};

generateRandom(20);
<button onclick="generateRandom(20)">⬇︎ Generate random numbers ⬇︎</button>
<div><input id="in" size="80"></div>
<button onclick="doSort()">⬇︎ Sort ⬇︎</button>
<div><input id="out" size="80" disabled></div>

The last conditional branch is else of rather than else if. Normally, else of should result in a syntax error. Yet, no matter how hard I try, I can't trigger the syntax error — it always successfully returns an array sorted in descending order!

I know, else of (b == 0) could just be replaced by else, but still, I want to know: How could this code possibly work?

like image 377
200_success Avatar asked May 28 '15 11:05

200_success


2 Answers

This works because of a combination of 2 "bad things" about Javascript: skipping braces in block statements that contain only a single statement, and semicolon insertion.

Your if statement, properly braced, should look like this:

if (a > 0 && b > 0) {
    if (left[0] > right[0]) {
        return [].concat(left[0], merge(left.slice(1,a), right));
    } else {
        return [].concat(right[0], merge(right.slice(1,b), left));
    }
} else if (a == 0) {
    return right;
} else of (b == 0) {
    return left;
}

but, because of the missing braces and semicolon insertion, Javascript is seeing/parsing it like this:

if (a > 0 && b > 0) {
    if (left[0] > right[0]) {
        return [].concat(left[0], merge(left.slice(1,a), right));
    } else {
        return [].concat(right[0], merge(right.slice(1,b), left));
    }
} else if (a == 0) {
    return right;
} else {
    of(b == 0);
}

return left;

If you always pass in legitimate left and right arrays then this last else branch is never reached, hence why you haven't seen an exception.

If you pass in an empty right array, it will reach the last branch and throw of is not a function:

merge([10, 20, 30], []);

Any respectable coding standard should explicitly require these 2 "features" of Javascript never be used... but that's just one opinion.

like image 130
Alex McMillan Avatar answered Nov 15 '22 13:11

Alex McMillan


of is a keyword in ES6, used for iterating over objects.. but in this case the of is behaving as function not keyword..

The function code never goes to else of (b == 0) return left; part.. so compiler is not throw ReferenceError: of is not defined

if you will change of keyword into another word like else often(b==0).... then also code work

when you send right side empty then code will throw error ReferenceError: of is not defined, so finally this is only typo.

like image 38
Girish Avatar answered Nov 15 '22 13:11

Girish