Run method with reference to it's static vars from a child class - class

I have a class Child which extends Test. I want to call a function from Test from Child.
I tried this:
class Test
constructor: ->
#i = 'hello world'
f1: -> console.log #i
f2: -> console.log 'hello'
class Child extends Test
run: ->
Test::f1()
hello = new Child()
hello.run()
When I call hello.run(), it calls Test.f1(), but the result is undefined. It's not setting the static variable #i before it's running Test.f1().
If I switch Test::f1() to Test::f2(), it gives me the correct result.
I need to know how should I make Test's constructor run when I create a new Child() so that #i is defined in Test when I run Test::f1() from Child.run().
Thanks! :D

Here's one way of doing it:
class Test
#i: 'hello world'
#f1: -> console.log #i
f2: -> console.log 'hello'
class Child extends Test
run: ->
Test.f1()
hello = new Child()
hello.run()
Notice, the i variable is static, so it doesn't make sense to set it in the constructor. Also, the f1 method is now static as well.
(I'm not an expert with CoffeeScript, so I'm not sure what the :: syntax is needed for.)

The constructor is being run when you create a new instance of Child. The problem is the way that you're invoking f1.
You don't want to say Test::f1(). You can just say #f1(), since Child is a subclass of Test. These are different in a very important way: Test::f1() does not set this, so when that function requests this.i, it finds only undefined, because this is set to Window (or something ridiculous like that in the browser, not sure if you're running this in Node). Saying #f1() is the same as saying Test::f1.call(this). This is one of the nice things that CoffeeScript's class system lets you do.
Finally, a pedantic note: there are no static variables in the code you've written. i, as you've written it, is an instance variable. Static variables look like this:
class Test
#staticVar = 1234
Or like this:
class Test
# ...
Test.staticVar = 1234
Instance variables look like this:
class Test
fn: ->
#instanceVar = 1234
Or like this:
test = new Test()
test.instanceVar = 1234
Or even like this (for the default value of an instance variable shared among all instances):
Test::instanceVar = 1234
In a similar vein:
When I call hello.run(), it calls Test.f1(), but the result is undefined. It's not setting the static variable #i before it's running Test.f1().
You're never calling Test.f1(); you're calling Test::f1(), which is very different. In the code you've written, there is no Test.f1, only Test.prototype.f1.

Related

Coffeescript classes and scope

While learning coffeescript, I'm trying to create an instance of class A inside a method of class B, this is the code:
class #A
constructor: (#x) ->
show: ->
alert #x
class #B
constructor: (#y) ->
show: ->
a = new #A("eric")
alert a.x
alert #y
b = new #B("daniel")
b.show()
the error is TypeError: undefined is not a function.
Any help is appreciated.
Thanks
You have two problems:
# is just another way of saying this in CoffeeScript. That's all it means.
Classes are (more or less) just variables or properties like any other in CoffeeScript.
So when you say #A, you're just looking for the A property of this and your show is really saying:
a = new this.A("eric")
In that context, # will be an instance of B and Bs don't have A properties. Instead you should just say:
a = new A('eric')
Using # when defining a class:
class #A
#...
is just a way to make a class globally available. At the top level, # will (almost always) be window in a browser so you're really saying:
class window.A
#...
and window properties are globals. Keep in mind that each CoffeeScript file is wrapped in a function when it is converted to JavaScript:
Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.
So if you just said:
class A
then A would only be available to other code in that file. Saying:
class #A
makes A global.
If you're only working with one file then you don't need the #s on your classes:
class A
constructor: (#x) ->
show: ->
alert #x
class B
constructor: (#y) ->
show: ->
a = new A("eric")
alert a.x
alert #y
b = new B("daniel")
b.show()
Don't get in the habit of prefixing everything with #, only use it on classes when you need it and you know exactly what it will do. Even when you need it, there are better ways: use require.js to manage your dependencies, use an global application-specific object to manage scopes, ...

Coffeescript static inheritance of child classes

This works :
class Foo
class #_Bar
#narf = ''
#point : ->
#narf = 'what'
class #_Baz extends #_Bar
#point : ->
#narf = 'woo'
super()
This does not
class Foo
class #_Bar
#narf = ''
#point = ->
#narf = 'what'
class #_Baz extends #_Bar
#point = ->
#narf = 'woo'
super()
running Foo._Baz.point() will throw and error.
Please someone explain what is going on here.
It seems like a bug in the compiler to me. Writing
class X
#classMethod: ->
and
class X
#classMethod = ->
should be equivalent, yet super compiles differently across the two methods. In the first, it compiles correctly:
X.__super__.constructor.classMethod.apply(this, arguments);
In the second, it compiles as if classMethod were an instance method:
X.__super__.classMethod.apply(this, arguments);
This works:
class Foo
class #_Bar
#narf = ''
point : ->
#narf = 'what'
class #_Baz extends #_Bar
#point = ->
#narf = 'woo'
super()
alert Foo._Baz.point() # 'what'
alert new Foo._Bar().point() # 'what'
That is, the compiled #point= super ends up pointing to the instance point:. Its JS is: _Baz.__super__.point.call(this), which is _Bar.prototype.point.call(this). (extends defines: child.__super__ = parent.prototype).
It's clear from past Coffeescript changes that #point: is the intended syntax for static (class) methods (and used that way in the compiler itself).
There are a couple of fixes now on github. https://github.com/jashkenas/coffee-script/issues/3232
Currently the node tree for a #foo= method is different from that of a #foo: method. Because of that, a node created with = is never passed to the Class addParameters method, and is never flagged as static.
One solution, which will probably be accepted, makes sure both forms produce the same node tree.
The one I contributed https://github.com/jashkenas/coffee-script/issues/3232#issuecomment-28316501
adds a method to nodes.coffee class Class. This method is a stripped down version of addParameters, and specifically checks a = node tree.
If you need a fix in your own Coffee compiler, modify your src/coffee-script/nodes.coffee file, compile it, and put the resulting node.js in the lib directory (or use the cake build).

Call static method in constructor — CoffeeScript

Say I'm declaring a class Game.
class #Game
constructor: ->
#id = Game.generateNewGameId() # <---
player1: null
player2: null
#generateNewGameId: -> "blahblah23"
Here, I'm using generateNewGameId as Game.generateNewGameId().
Is this the right way or is there a better way? I've tried using this::generateNewGameId() but the scope's different.
If you really want generateNewGameId to be a class method then you can use #constructor to get at it:
Returns a reference to the Object function that created the instance's prototype. Note that the value of this property is a reference to the function itself [...]
So something like this:
class Game
constructor: ->
#id = #constructor.generateNewGameId()
#generateNewGameId: ->
"blahblah23"
Note that this will do The Right Thing if you subclass Game:
class C extends Game # With an override of the class method
#generateNewGameId: ->
'pancakes'
class C2 extends Game # or without
Demo (open your console please): http://jsfiddle.net/ambiguous/Vz2SE/
I think the way you are accessing it is OK. You can also do #constructor.generateNewGameId() if you don't want to write Game.generateNewGameId() for some reason, but i'd prefer the later. Update: as #mu is too short mentions, the #constructor allows you to get the constructor of the instance, which can be differ from Game (in a subclass) so it has greater flexibility; if that flexibility is required in this case, definitely go for that :)
If the generateNewGameId function will not be accessed from outside the Game class, you can use a private function instead of a class method:
class #Game
gameIdCounter = 0
generateNewGameId = -> gameIdCounter++
constructor: ->
#id = generateNewGameId()
player1: null
player2: null
console.log (new Game).id # -> 0
console.log (new Game).id # -> 1
Example at coffeescript.org.
There both gameIdCounter and generateNewGameId are private variables inside the Game class.

Why must my coffeescript method belong to the class?

I come from a C#/Java background which use a class based OO system and I don't get the JavaScript/CoffeeScript prototype OO system yet. I've written a CoffeeScript class below which allows me to display names for contacts according to a system-side preference. I can only get the class to work by making the joinNonEmpty(stringList, joinText) method belong to the prototype and calling it the way I would call a static method in Java/C# land.
Is there a way I can make this method call using this.joinNonEmpty(...)?
Can you shed some light on why I can reference the firstLastRender, lastFirstRender and firstOrNickThenLast methods in the constructor with this. but it doesn't work from those methods when calling the joinNonEmpty helper?
Does this have something to do with how I'm locating the appropriate method via the preference map?
prefs = displayNameFormat: "FirstOrNickThenLast"
class DisplayNameRenderer
constructor: ->
#prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
# Why does this method have to be static (a class method)?
#joinNonEmpty: (stringList, joinText) ->
nonEmptyStrings = []
for s in stringList
nonEmptyStrings.push(s) if s isnt null and s isnt ""
nonEmptyStrings.join(joinText)
firstLastRender: (contact) ->
# TypeError: Object expected.
joinNonEmpty([contact.firstName, contact.lastName], ' ')
lastFirstRender: (contact) ->
# TypeError: Object doesn't support this method or property
this.joinNonEmpty([contact.lastName, contact.firstName], ', ')
firstOrNickThenLast: (contact) ->
# Works correctly.
DisplayNameRenderer.joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
#prefToRenderMap[prefs.displayNameFormat](contact)
contact = firstName: "Jonathan", nickname: "Jonny", lastName: "Appleseed"
dnr = new DisplayNameRenderer()
# => "Jonny Appleseed"
console.log dnr.render(contact)
Thanks for taking the time to answer.
this (AKA #) is determined when the function is called (with exceptions as below). So when you do this:
#prefToRenderMap =
FirstLast: this.firstLastRender
LastFirst: this.lastFirstRender
FirstOrNickThenLast: this.firstOrNickThenLast
You're storing unbound references to the three functions in the #prefToRenderMap instance variable and #prefToRenderMap is itself an object. Then you try to call the methods in your DisplayNameRenderer instance like this:
#prefToRenderMap[prefs.displayNameFormat](contact)
and everything falls apart because the methods are called in the wrong context and # isn't what they're expecting it to be. If prefs is 'FirstOrNickThenLast' then you're effectively doing this:
#prefToRenderMap.FirstOrNickThenLast(contact)
and # (AKA this) will be #prefToRenderMap inside the firstOrNickThenLast method. But, of course, #prefToRenderMap doesn't have any of the methods that you're trying to call so you get various errors.
One solution is to use the fat arrow (=>) to define the methods:
The fat arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot.
So you could have things like this:
joinNonEmpty: (stringList, joinText) ->
#...
firstLastRender: (contact) =>
#joinNonEmpty([contact.firstName, contact.lastName], ' ')
and everything will work out. Here's a stripped down demo that will also show you your this problem:
http://jsfiddle.net/ambiguous/RAPJw/1/
You could also avoid this problem by referring to the methods by their names. Given a method name in a string, m = 'some_method', you can call that method like this o[m]() in both JavaScript and CoffeeScript and the result will be the same as if you said o.some_method(). A better structure would look more like this:
class DisplayNameRenderer
constructor: ->
#prefToRenderMap =
FirstOrNickThenLast: 'firstOrNickThenLast'
joinNonEmpty: (stringList, joinText) ->
#...
firstOrNickThenLast: (contact) ->
#joinNonEmpty([(if contact.nickname isnt null and contact.nickname isnt "" then contact.nickname else contact.firstName), contact.lastName], ' ')
render: (contact) ->
#[#prefToRenderMap['FirstOrNickThenLast']](contact)
Note the change to the structure of #prefToRenderMap and how it is used in render. And a demo of this approach: http://jsfiddle.net/ambiguous/DFYwu/
As an aside, instead of saying ClassName.class_method() inside an instance method, you can use the constructor property instead: #constructor.class_method(). Also, you usually say #method() or #property rather than this.method() and this.property in CoffeeScript.

Fields in CoffeeScript?

class #A
A_Function_Alias: => #my_function
my_function: =>
usage_of_alias: =>
#A_Function_Alias.call()
What i want, is usage_of_alias to be
usage_of_alias: =>
#A_Function_Alias
And have it behave the same. i.e. I want a more functional style syntax here. I've tried multiple combinations with no success. The fact that i have to evaluate my function to get the goodies inside bothers me.
One application would be instead of this:
event: => new Event(#my_function)
which is accessed as event.call().hi()
i could have some other declaration that would allow me to access event as event.hi()
Something that behaves more like a field instead of a property.
I'm thinking you want this:
class #A
my_function: => alert 'my function!'
A_Function_Alias: #::my_function
usage_of_alias: =>
#A_Function_Alias()
# some other code...
See what this compiles to here.
When evaluating a class # is the class constructor object, the class object itself. And the :: operator lets you drill into the prototype. So #::foo in a class body compiles to MyClass.prototype.foo.
So what this is doing is first making a normal instance method named my_function, defined on A.prototype.my_function. Then we make a new instance method named A_Function_Alias and directly assign the function from class objects prototype that we just created. Now my_function and A_Function_Alias both point to the exact same function object.
But as a more sane alternative, might I suggest a pattern that defines a private inner function that the class can use, and then assigning it more directly, without crazy the prototype accessing?
class #A
# Only code inside this class has access to this local function
innerFunc = -> alert 'my function!'
# Assign the inner funciton to any instance methods we want.
my_function: innerFunc
A_Function_Alias: innerFunc
usage_of_alias: =>
#A_Function_Alias()
# or
#my_function()
# or
innerFunc()
# they all do the same thing