Reputation: 8941
I am trying to organize my code a bit but having issues with undefined superclasses. I'm hoping it's just a load path problem, but I can't figure it out. I am running this with:
coffee rooms.coffee
rooms.coffee
Room = require('./rooms/room')
module.exports = class Rooms extends Object
constructor: ->
@
rooms/room.coffee
module.exports = class Room
@Active: require('./active')
constructor: (@id) ->
@users = {}
rooms/active.coffee
Room = require('./room')
console.log Room #=> {}
module.exports = class Active extends Room
constructor: (@id) ->
@type = "Active"
super
And if I try to do new Active
, I get the following error:
TypeError: Cannot read property 'constructor' of undefined
Active
's super
is listed as undefined
:
[Function: Active] __super__: undefined
Why Room
undefined? (or rather, just an empty Object?)
Update
This was caused by a circular dependency as many people below pointed out. I ended up just putting the subclass definitions right inside of the baseclass definition, rather than try to keep them in separate files. Something like this:
class Room
constructor: ->
# ...
class @Active extends Room
constructor: ->
# ...
class @Inactive extends Room
constructor: ->
# ...
active = new Room.Active
inactive = new Room.Inactive
Upvotes: 3
Views: 1055
Reputation: 20315
@Active: require('./active')
remove this, or move this somewhere else. You have a circular dependency. When you define room.coffee
, you're telling it to require active.coffee
before it can finish defining Room
, and active.coffee
requires Room
, so Room
will be undefined
when active.coffee
is required.
You should be able to just add a Room::Active = require('./active')
at the end, but then I ask why you even need this in the first place o.O
Upvotes: 0
Reputation: 64312
This is a case where simplifying the code down to its most primitive parts (while still seeing errors) is illuminating. If we remove the requires and strip out most of the code, we can get a structure like this:
class Room
@foo = "bar"
class Active extends Room
console.log Room.foo
which prints: bar
as expected.
So now lets try getting a little closer to the original example:
class Room
@foo = Active
class Active extends Room
console.log Room.foo
This prints undefined
because Active
was not defined when Room.foo was defined.
Finally, let's look at the case were the definitions are reversed:
class Active extends Room
class Room
@foo = Active
console.log Room.foo
This throws an error because it isn't possible to extend undefined
.
The last two cases represent changing the require order in your original example. Having the definition of a base class depend on its subclass should cause your OOP alarm bells to start ringing! :)
There may be a way to change the definitions slightly to make this work, but code with these kinds of mutual dependencies tends to be unmaintainable at best. I'd recommend figuring out a way to completely decouple the classes.
Upvotes: 2
Reputation: 5515
I can't be sure about this but I may have had a similar problem - it might be to do with the fact that the file room/active.coffee is before room/room.coffee alphabetically, so when active.coffee file is loaded the Active
class is first looked at, room.coffee and Room
haven't been yet, so the superclass can't be found.
I got around this by using the -j
operator at compile time, so while your .coffee files are nice and organised, they compile into a single .js file, which has other advantages as well.
Upvotes: 0