From 24183d9a3970063c77d18b8ec9b33315186c9e58 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 5 Dec 2010 15:08:41 -0500 Subject: [PATCH 1/8] Issue #894: Strange interaction between class instantiation and splats --- lib/nodes.js | 6 +++++- src/nodes.coffee | 5 ++++- test/test_functions.coffee | 12 ++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index 75f05c93..4c092247 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -520,7 +520,11 @@ __extends(Call, Base); Call.prototype.children = ['variable', 'args']; Call.prototype.newInstance = function() { - this.isNew = true; + if (this.variable.base instanceof Call) { + this.variable.base.newInstance(); + } else { + this.isNew = true; + } return this; }; Call.prototype.superReference = function(o) { diff --git a/src/nodes.coffee b/src/nodes.coffee index 26a07830..fc3e176b 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -433,7 +433,10 @@ exports.Call = class Call extends Base # Tag this invocation as creating a new instance. newInstance: -> - @isNew = true + if @variable.base instanceof Call + @variable.base.newInstance() + else + @isNew = true this # Grab the reference to the superclass's implementation of the current diff --git a/test/test_functions.coffee b/test/test_functions.coffee index 1bb26f21..1e10e217 100644 --- a/test/test_functions.coffee +++ b/test/test_functions.coffee @@ -346,6 +346,7 @@ eq ok, new -> ### Should `return` implicitly ### ### even with trailing comments. ### + #855: execution context for `func arr...` should be `null` (-> global = @ @@ -355,3 +356,14 @@ eq ok, new -> contextTest.apply null, array contextTest array... )() + + +# #894: Splatting against constructor-chained functions. +x = null + +class Foo + bar: (y) -> x = y + +new Foo().bar([101]...) + +eq x, 101 \ No newline at end of file From 06647bdd0a052deccba95e7379798d089abab4c1 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 5 Dec 2010 15:29:28 -0500 Subject: [PATCH 2/8] Adding warning about accidentally-comprehended-functions. Issue #896. --- .../coffee/array_comprehensions.coffee | 7 +--- documentation/index.html.erb | 9 ++++ documentation/js/array_comprehensions.js | 15 +------ documentation/js/splices.js | 4 +- index.html | 41 ++++++++----------- 5 files changed, 31 insertions(+), 45 deletions(-) diff --git a/documentation/coffee/array_comprehensions.coffee b/documentation/coffee/array_comprehensions.coffee index b9d9e166..8050de6e 100644 --- a/documentation/coffee/array_comprehensions.coffee +++ b/documentation/coffee/array_comprehensions.coffee @@ -1,7 +1,2 @@ # Eat lunch. -lunch = eat food for food in ['toast', 'cheese', 'wine'] - -# Naive collision detection. -for roid, pos in asteroids - for roid2 in asteroids when roid isnt roid2 - roid.explode() if roid.overlaps roid2 \ No newline at end of file +eat food for food in ['toast', 'cheese', 'wine'] diff --git a/documentation/index.html.erb b/documentation/index.html.erb index 6e985acf..7b45d6f2 100644 --- a/documentation/index.html.erb +++ b/documentation/index.html.erb @@ -517,6 +517,15 @@ coffee --bare --print --stdio end of your comprehension.

<%= code_for('range_comprehensions', 'countdown') %> +

+ Note how because we are assigning the value of the comprehensions to a + variable in the example above, CoffeeScript is collecting the result of + each iteration into an array. Sometimes functions end with loops that are + intended to run only for their side-effects. Be careful that you're not + accidentally returning the results of the comprehension in these cases, + by adding a meaningful return value, like true, or null, + to the bottom of your function. +

Comprehensions can also be used to iterate over the keys and values in an object. Use of to signal comprehension over the properties of diff --git a/documentation/js/array_comprehensions.js b/documentation/js/array_comprehensions.js index bbbe4c90..07f136c7 100644 --- a/documentation/js/array_comprehensions.js +++ b/documentation/js/array_comprehensions.js @@ -1,17 +1,6 @@ -var food, lunch, pos, roid, roid2, _i, _j, _len, _len2, _len3, _ref; +var food, _i, _len, _ref; _ref = ['toast', 'cheese', 'wine']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { food = _ref[_i]; - lunch = eat(food); -} -for (pos = 0, _len2 = asteroids.length; pos < _len2; pos++) { - roid = asteroids[pos]; - for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) { - roid2 = asteroids[_j]; - if (roid !== roid2) { - if (roid.overlaps(roid2)) { - roid.explode(); - } - } - } + eat(food); } \ No newline at end of file diff --git a/documentation/js/splices.js b/documentation/js/splices.js index ed47b9b2..a6f916f1 100644 --- a/documentation/js/splices.js +++ b/documentation/js/splices.js @@ -1,3 +1,3 @@ -var numbers, _ref; +var numbers; numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; -([].splice.apply(numbers, [3, 6 - 3 + 1].concat(_ref = [-3, -4, -5, -6])), _ref); \ No newline at end of file +[].splice.apply(numbers, [3, 4].concat([-3, -4, -5, -6])); \ No newline at end of file diff --git a/index.html b/index.html index 75c421e0..42126459 100644 --- a/index.html +++ b/index.html @@ -854,28 +854,12 @@ lyrics = function() { would use a loop, each/forEach, map, or select/filter.

# Eat lunch.
-lunch = eat food for food in ['toast', 'cheese', 'wine']
-
-# Naive collision detection.
-for roid, pos in asteroids
-  for roid2 in asteroids when roid isnt roid2
-    roid.explode() if roid.overlaps roid2
-
var food, lunch, pos, roid, roid2, _i, _j, _len, _len2, _len3, _ref;
+eat food for food in ['toast', 'cheese', 'wine']
+
var food, _i, _len, _ref;
 _ref = ['toast', 'cheese', 'wine'];
 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
   food = _ref[_i];
-  lunch = eat(food);
-}
-for (pos = 0, _len2 = asteroids.length; pos < _len2; pos++) {
-  roid = asteroids[pos];
-  for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) {
-    roid2 = asteroids[_j];
-    if (roid !== roid2) {
-      if (roid.overlaps(roid2)) {
-        roid.explode();
-      }
-    }
-  }
+  eat(food);
 }
 

@@ -901,6 +885,15 @@ countdown = (function() { } return _results; }());;alert(countdown);'>run: countdown
+

+ Note how because we are assigning the value of the comprehensions to a + variable in the example above, CoffeeScript is collecting the result of + each iteration into an array. Sometimes functions end with loops that are + intended to run only for their side-effects. Be careful that you're not + accidentally returning the results of the comprehension in these cases, + by adding a meaningful return value, like true, or null, + to the bottom of your function. +

Comprehensions can also be used to iterate over the keys and values in an object. Use of to signal comprehension over the properties of @@ -975,12 +968,12 @@ middle = copy.slice(3, 6 + 1);;alert(middle);'>run: middle
apply(numbers, [3, 4].concat([-3, -4, -5, -6])); +
+[].splice.apply(numbers, [3, 4].concat([-3, -4, -5, -6]));;alert(numbers);'>run: numbers

Note that JavaScript strings are immutable, and can't be spliced.

@@ -1920,7 +1913,7 @@ task('build:parser