Circular dependencies and goog.require

910 views
Skip to first unread message

YCC

unread,
Jun 9, 2011, 9:19:45 PM6/9/11
to Closure Library Discuss
Hi, I've been thinking of how to organize my JavaScript files using
Closure's dependency system, and haven't been able to come up with a
clean solution to solving the circular dependency issue when using
goog.require(), and would like to know what the best practices for
this kind of pattern is.

Basically the problem is that let's say we are making a subclass of
another class, but the superclass wants to reference the subclass in
the code. Both files need to be loaded but the superclass should be
loaded first. The files would look like:

--------------------
sub.js:

goog.provides("sub");
goog.require("super");
var sub = function() {};
goog.inherits(sub, super);
--------------------
super.js:

goog.provides("super");
goog.require("sub");
var super = function() {};
super.prototype.doStuff() = function() {
return new sub();
};
--------------------
main.js

// This is the main logic file
goog.require("super");
var foo = new super();
var bar = foo.doStuff();
--------------------

I don't think this is going to work because main.js will pull in
super.js which pulls in sub.js first. Therefore by the time sub.js is
pulled in super.js hasn't been pulled in yet and the goog.inherits()
call won't work. We could add a goog.require("sub") first but that
kind of defeats the point of the dependency system.

I'm just thinking maybe we need a second tier version of
goog.require("some_module") where we can guaranteed "some_module" will
get loaded in but isn't part of the dependency? (so in super.js we use
this instead of goog.require)

Right now the only solution I can think of is to do the following, by
setting up a "project" that includes everything, and remove the
dependency in super.js of sub.js:

--------------------
sub.js:

goog.provides("sub");
goog.require("super");
var sub = function() {};
goog.inherits(sub, super);
--------------------
super.js:

goog.provides("super");
// goog.require("sub"); // don't need this here as sub.js is pulled in
by project.js
var super = function() {};
super.prototype.doStuff() = function() {
return new sub();
};
--------------------
project.js:

goog.provides("project");

// Sorted alphabetically, doesn't really matter which goes first
goog.require("sub.js");
goog.require("super.js");
--------------------
main.js

// This is the main logic file
goog.require("project"); // this pulls in everything I need in the
module in the correct order
var foo = new super();
var bar = foo.doStuff();
--------------------

Thoughts? Am I just missing something?

Michael Davidson

unread,
Jun 10, 2011, 11:55:07 AM6/10/11
to closure-lib...@googlegroups.com
On Thu, Jun 9, 2011 at 6:19 PM, YCC <yeeche...@gmail.com> wrote:

Basically the problem is that let's say we are making a subclass of
another class, but the superclass wants to reference the subclass in
the code. Both files need to be loaded but the superclass should be

Personally, I'd refactor the code so you don't need this. Why not have a factory that can depend on both the superclass and the subclass? Having the superclass know about its subclasses strikes me as a sign of bad design.

Michael

Rhys Brett-Bowen

unread,
Jul 31, 2012, 1:50:26 PM7/31/12
to closure-lib...@googlegroups.com, roda...@google.com
one thing you can do is pass through a reference of the parent object to the child, but in the above you only need to pull in sub, as sub already requires super so pulling in sub will also mean that super has been loaded

On Friday, July 27, 2012 11:29:07 AM UTC-7, (unknown) wrote:
Without changing the design, is there a way to fix this issue?

On Friday, June 10, 2011 8:55:07 AM UTC-7, Michael Davidson wrote:

Yesudeep Mangalapilly

unread,
Jul 31, 2012, 2:25:19 PM7/31/12
to closure-lib...@googlegroups.com
Hey there,

As a rule of thumb, as soon as you hit cyclic dependencies, you should assume
something is wrong with your design. I second Michael Davidson. With this
kind of code, you'd probably make it even harder to test. Is refactoring possible?
If it is your own code, I'd say go with a design change. It'll be simpler to manage
as well.

Cheers,
Yesudeep.
--

Yesudeep Mangalapilly | येसुदीप मंगलापिल्ली | Specialist, Tools Dev | yesu...@google.com | +91 9833470018
=) ツ ヅ ツ ッ シ (=

Andre Tannus

unread,
Jul 31, 2012, 2:44:06 PM7/31/12
to closure-lib...@googlegroups.com
If you're extending, it means the sub-class builds upon the super-class, hence sub cannot exist without sup.
With the in mind, the correct pattern becomes obvious:

Have sub require sup.

Do that and fix whatever else breaks. The dependency system is fine.

Now, from the code sample you wrote, this bit looks awkward:

// This is the main logic file
goog.require("super");
var foo = new super();
var bar = foo.doStuff();

You have sub extend sup, no problem here.
Then use sup to create an instance of sub (which, remember, extends sup).

A class that returns an instance of another class is pretty much a factory.
Your utility class, which the factory is making, extends the factory itself.

Perhaps it would be a good idea to create a third entity in your design, and call it factory.
Then you include the factory, and it will return you an instance of sup, or sub, or whatever you like.
--
A ciência consiste em perturbar um sistema e analisar sua reação. Eu, sou uma perturbação.

André Tannús | Ideas at Epungo
ata...@epungo.com.br | +55 11 8053-7636 | +55 11 2389-4360 

"Somewhere, something incredible is waiting to be known."
Carl Sagan

Lukáš Benda

unread,
Jan 5, 2015, 6:01:52 AM1/5/15
to closure-lib...@googlegroups.com
Cyclick dependenci dind't mean something is bad in design.

What if I have canvas, and object on canvas?

Canvas know about all boject on it, and object know on which canvas are.

So the Canvas has array of class Shape, and Shape have method setCanvas().

So Canvas must import Shape and Shape must import Cnavas.

I aggre the cyclick depedenci between parent and child is bad, but when you have two class of "equal level", then they want know about each toher.

So the question: How about cyclick depedencies? Still is there and unanswered.

Best regards
 Lukas Benda

Dne úterý, 31. července 2012 20:44:06 UTC+2 Andre Tannus napsal(a):

Erik Neumann

unread,
Jan 7, 2015, 6:41:32 PM1/7/15
to closure-lib...@googlegroups.com
Hi Lukas,

Two ways to handle this that I know of:

1.  Define both classes in the same file.

2.  Create an interface that one class implements, and have the other class accept objects of that interface type instead of a specific class.

--ErikN
Reply all
Reply to author
Forward
0 new messages