CoffeeScript: How to return an array from a class?
What is wrong with this class in CoffeeScript?
@module "Euclidean2D", -> class @Point constructor: (x,y) -> return if Float32Array? then Float32Array([ x, y ]) else Array(x,y) I want him to behave like this:
p = new Point(1.0,2.0); p[0] == 1.0 p[1] == 2.0 But testing with Jasmine, I get "Expected undefined equal to 1".
describe "Point", -> beforeEach -> @point = new Euclidean2D.Point(1.0,2.0) it "extracts values", -> (expect @point[0]).toEqual 1.0 (expect @point[1]).toEqual 2.0 Is there a bug in CoffeeScript or in Jasmine?
And all this in a module like:
@module = (names, fn) -> names = names.split '.' if typeof names is 'string' space = @[names.shift()] ||= {} space.module ||= @module if names.length space.module names, fn else fn.call space In the Chrome console, I get:
a = new Euclidean2D.Point(1.0,2.0) -> Point a[0] undefined b = new Float32Array([1.0,2.0]) -> Float32Array b[0] 1 EDIT: again .. sorry
Decided to use a combination of @brandizzi and @ arnaud576875 answers. @module, proposed on the official Wikipedia CoffeeScript, does not work. Result:
class @Point constructor: (x, y) -> return if Float32Array? then Float32Array([ x, y ]) else Array(x,y) You must use new to create the object:
p = new Euclidean2D.Point(1.0,2.0) If you want to return Array from the constructor, do this explicitly:
constructor: (x,y) -> return if Float32Array? then Float32Array([x,y]) else Array(x,y) (By default, Coffeescript does not return values ββfrom the constructor, so you need to do this explicitly.)
You could do this too:
class @Point constructor: (x,y) -> @[0] = x @[1] = y You define a constructor, but expect it to behave as a function. However, the constructor simply sets the values ββin the returned object. Since your constructor does not set any attributes in the initialization object, this is really not useful.
You have several alternatives:
Initialize the class as @amaud sugested.
It returns the value from the constructor as @amaud sugested (which does not make much sense to me. This is not a constructor function as I feel it. In this case, solution # 3 looks better).
define a function instead of a class. IMHO, is the simplest and most functional solution
@Point = (x, y) -> if Float32Array? then Float32Array([x,y]) else Array(x,y)If you want
Pointbe either aFloat32ArrayorArrayspecialization, use option # 1, but makePointinherits from the class you need:superclass = if Float32Array? then Float32Array else Array class @Point extends superclass constructor: (x,y) -> @[0] = x @[1] = y
EDIT : @ amaud676875 posted an interesting question as a comment. Since a reasonable answer will include some code, I am posting the answer as an edit.
@amaud, to test your point, I wrote the following CoffeeScript module:
class Float32Array extends Array first: -> # Just for testing @[0] superclass = if Float32Array? then Float32Array else Array class @Point extends superclass constructor: (x,y) -> @[0] = x @[1] = y Then I imported the module into the console:
coffee> point = require './point' { Point: { [Function: Point] __super__: [ constructor: [Object], first: [Function] ] }, Float32Array: { [Function: Float32Array] __super__: [] } } and created Point :
coffee> p = new point.Point 3, 2 [ 3, 2 ] This Point has a first() method from Float32Array :
coffee> p.first() 3 and instanceof say this is also an instance of Float32Array :
coffee> p instanceof point.Float32Array true So, I put that new Point x, y returns an instance of Float32Array . Of course, this is an instance of Point , and that is not a problem, because Point is-a Float32Array to use the classic OOP expression.