Namespaces, or getting function foo.bar() declarations to work

Discussion in 'Javascript' started by António Marques, May 25, 2006.

  1. Hi!

    I don't think I've ever been here, so I assume I'm addressing a bunch of
    nice people. Can you help me? I don't think there's a solution, but who
    knows.

    The thing is, picture a large project where you want some encapsulation.
    But a lot of it being grouping of what would otherwise be static members
    of the global namespace. So that instead of

    fooEcks(), fooWye, fooZed()

    you can have

    foo.ecks(), foo.wye(), foo.zed()

    with foo being a global variable.


    Now this is perfectly possible, that I know, by declaring

    var foo={} OR function foo(){}

    and then having

    foo.ecks=function(args){body}

    or then by defining them inline, as in

    var foo={ecks: function(args){body}}

    However, in all of these, the functions created are anonymous. This may
    make no difference, but I don't like it and it impacts debugging, when
    you're trying to determine their name.

    You can given them a name, as in

    foo.ecks=function ecks(args){body}

    But this is error prone, since you have to keep the two names in sync,
    and that is a sure road to damnation.


    It turns out that in IE6, if you do

    function foo(){}; // with 'var foo' it won't work
    function foo.ecks(args){body};

    the browser does create a member of foo, named ecks, which is then your
    foo.ecks function. I may be missing something, but this seems great to
    me, in absence of alternatives (my preferred would be simply that
    internal named functions were public).

    But as it is, neither Opera nor Gecko accept this notation. And for the
    life of me, I haven't been able to figure out any other way to define a
    public static member (though instance members would have the same
    problem) that isn't anonymous without referring its name twice. Needless
    to say, something like

    var foo={ecks: fooEcks};
    function fooEcks(args){body};

    isn't the solution because it keeps the repetition (though this time it
    could be automated to avoid errors - but notice that then we're going
    far away from the natural constructs of the language), clutters the
    global namespace anyhow, and probably creates all sorts of scope
    problems (otherwise, we may just delete all of those references after
    reassigning the functions to their namespace, but somehow this doesn't
    look like a sensible solution).

    So, any ideas? Thanks,
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 25, 2006
    #1
    1. Advertising

  2. António Marques wrote:
    <snip>
    > However, in all of these, the functions created are anonymous.
    > This may make no difference, but I don't like it and it impacts
    > debugging, when you're trying to determine their name.

    <snip>

    This assumption appears to be the crux of your issue, but you have not
    explained or justified it. Most javascript error reports output line
    numbers (at minimum) so I don't see any need to have a name associated
    with the function for debugging.

    Richard.
     
    Richard Cornford, May 25, 2006
    #2
    1. Advertising

  3. Richard Cornford wrote:

    >> However, in all of these, the functions created are anonymous.
    >> This may make no difference, but I don't like it and it impacts
    >> debugging, when you're trying to determine their name.

    >
    > This assumption appears to be the crux of your issue, but you have not
    > explained or justified it. Most javascript error reports output line
    > numbers (at minimum) so I don't see any need to have a name associated
    > with the function for debugging.


    It's not an assumption, they really are anonymous. But you are right
    that it it the crux of the issue: both that I can't extract a name for
    them, and more generally that they don't have one. If I could get a name
    I'd be happy, even if the function were anonymous the same. In fact, I
    wouldn't mind at all, since for instance I'd like internal functions to
    yield the name of their context and not their own:

    function foo()
    {
    function bar()
    {
    debug('hello', 1, 'a')
    }
    }

    And function debug would output something like

    '10:04:55 [foo] hello, 1, a'

    As to the why, javascript error reports are more or less the equivalent
    of exception stack traces. They can be informative, and a script
    debugger may help hunt down and fix an error, but debug outputs have
    their own value.

    Maybe there's something hidden in the function object that I haven't
    discovered yet.
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 25, 2006
    #3
  4. António Marques

    RobG Guest

    António Marques wrote:
    > Hi!
    >
    > I don't think I've ever been here, so I assume I'm addressing a bunch of
    > nice people. Can you help me? I don't think there's a solution, but who
    > knows.
    >
    > The thing is, picture a large project where you want some encapsulation.
    > But a lot of it being grouping of what would otherwise be static members
    > of the global namespace. So that instead of


    [...]

    > However, in all of these, the functions created are anonymous. This may
    > make no difference, but I don't like it and it impacts debugging, when
    > you're trying to determine their name.
    >
    > You can given them a name, as in
    >
    > foo.ecks=function ecks(args){body}
    >
    > But this is error prone, since you have to keep the two names in sync,
    > and that is a sure road to damnation.


    This question is asked from time to time, you can try searching the
    archives for answers but you've already summarised the case. Try this
    thread:

    <URL:http://groups.google.co.uk/group/comp.lang.javascript/browse_frm/thread/800641e55d59fb3a/bfab46faf88c7443?q=arguments.callee&rnum=3#bfab46faf88c7443>

    The real question is 'why do you want to know'? Presumably for
    debugging, where you could use arguments.callee to get the name of the
    function. The "best" solution is the one you've already discounted:

    foo.ecks = function ecks(...){...};

    Another 'solution' is to pass the function name to the function when you
    call it.

    It is highly desirable that stuff specific to debugging can be easily
    removed for production code - implementing either of the above will make
    that very difficult.


    > It turns out that in IE6, if you do
    >
    > function foo(){}; // with 'var foo' it won't work
    > function foo.ecks(args){body};
    >
    > the browser does create a member of foo, named ecks, which is then your
    > foo.ecks function. I may be missing something, but this seems great to
    > me, in absence of alternatives (my preferred would be simply that
    > internal named functions were public).


    Do you mean:

    function foo(){
    function bar(){}
    }
    bar(); // Error: bar is not defined.

    What would be the point of declaring a function inside a function object
    (i.e. creating a 'private member') if it was then public?


    > But as it is, neither Opera nor Gecko accept this notation. And for the
    > life of me, I haven't been able to figure out any other way to define a
    > public static member (though instance members would have the same
    > problem) that isn't anonymous without referring its name twice. Needless
    > to say, something like
    >
    > var foo={ecks: fooEcks};
    > function fooEcks(args){body};


    Read this post by Richard Cornford regarding class concepts (public,
    private, etc.):

    <URL:http://groups.google.co.uk/group/comp.lang.javascript/browse_frm/thread/d6460f64f2222442/952287418c33ae6c?q=arguments.callee&rnum=7#952287418c33ae6c>

    It may seem a little obtuse in regard to your question, but it's a good
    read anyway.


    --
    Rob
    Group FAQ: <URL:http://www.jibbering.com/faq/>
     
    RobG, May 25, 2006
    #4
  5. António Marques

    Guest

    António Marques wrote:
    >
    > The thing is, picture a large project where you want some encapsulation.
    > But a lot of it being grouping of what would otherwise be static members
    > of the global namespace. So that instead of
    >
    > fooEcks(), fooWye, fooZed()


    What is your objection to this method?


    > you can have
    >
    > foo.ecks(), foo.wye(), foo.zed()


    Richard explained to me just yesterday that this is a bad idea because
    JavaScript is not compiled but rather interpreted. He wrote

    "Simulated namespaces are a very questionable notion. In other language
    the namespaces are resolved when the code is compiled. Javascript must
    resolve those long property accessors each and every time they are
    used."

    You can find the whole post in the archives of this newsgroup.


    > However, in all of these, the functions created are anonymous. This may
    > make no difference, but I don't like it


    maybe sometimes it is worth going with the flow of the language

    > and it impacts debugging, when
    > you're trying to determine their name.


    Firefox spits out line numbers which makes it no problem.

    Peter
     
    , May 25, 2006
    #5
  6. António Marques <> writes:

    > You can given them a name, as in
    >
    > foo.ecks=function ecks(args){body}
    >
    > But this is error prone, since you have to keep the two names in sync,
    > and that is a sure road to damnation.


    Then only write it once:
    ---
    // extract name from function's toString
    function funcName(func) {
    var match = /^\s*function\s+([\w$]+)[^\w$]/.exec(func.toString());
    if (match) {
    return match[1];
    }
    }

    // extend object with named methods
    function addMethods(target /*, functions...*/) {
    for(var i = 1; i < arguments.length; i++) {
    var func = arguments;
    if(typeof func == "function") {
    var name = funcName(func);
    if (name) {
    target[name] = func;
    }
    }
    }
    return target;
    }

    // test
    var ns = addMethods({accumulator:[]},
    function add(n) {
    this.accumulator.push(n);
    return this;
    },
    function sum() {
    for(var i=0,r=0; i < this.accumulator.length; i++) {
    r+=this.accumulator;
    }
    return r;
    });

    alert(ns.add(2).add(40).sum()); // alerts 42
    ---

    > It turns out that in IE6, if you do
    >
    > function foo(){}; // with 'var foo' it won't work
    > function foo.ecks(args){body};
    >
    > the browser does create a member of foo, named ecks, which is then
    > your foo.ecks function.


    Nice idea, especially for extending prototypes:
    function Foo.prototype.doFoo() { ... }
    instead of
    Foo.prototype.doFoo = function doFoo() {...}

    But it's completely non-standard, so only viable for scripting
    specific known browsers and not for internet use.

    /L
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, May 25, 2006
    #6
  7. António Marques wrote:
    > Richard Cornford wrote:
    >>> However, in all of these, the functions created are
    >>> anonymous. This may make no difference, but I don't
    >>> like it and it impacts debugging, when you're trying
    >>> to determine their name.

    >>
    >> This assumption appears to be the crux of your issue, but
    >> you have not explained or justified it. Most javascript
    >> error reports output line numbers (at minimum) so I don't
    >> see any need to have a name associated with the function
    >> for debugging.

    >
    > It's not an assumption, they really are anonymous. ...

    <snip>

    That was not the assumption. The assumption was that using anonymous
    functions would impact debugging. It is an assumption as anonymous
    functions are common on non-trivial javascript and if their use really
    was a problem when debugging that would have been noticed by now.

    > function foo()
    > {
    > function bar()
    > {
    > debug('hello', 1, 'a')
    > }
    > }
    >
    > And function debug would output something like
    >
    > '10:04:55 [foo] hello, 1, a'

    <snip>

    The 'hello' got into that output because you put it there, why not put
    in the information that tells you what you need in the output, like
    something that tells you the context of the debug call?

    Richrd.
     
    Richard Cornford, May 25, 2006
    #7
  8. RobG wrote:

    > (stuff)


    Thank you for the references, Rob.
    Some things are just hard to find out other than asking them to a
    knowledgeable group (it's easy enough to find the answer to 'how to do
    X?', but not necessarily so when the question amounts to 'in how many
    ways can X be done?'), and you seem knowledgeable alright (this language
    is so generally misunderstood that one must be careful).

    >> It turns out that in IE6, if you do
    >>
    >> function foo(){}; // with 'var foo' it won't work
    >> function foo.ecks(args){body};
    >>
    >> the browser does create a member of foo, named ecks, which is then
    >> your foo.ecks function. I may be missing something, but this seems
    >> great to me, in absence of alternatives (my preferred would be simply
    >> that internal named functions were public).

    >
    > Do you mean:
    >
    > function foo(){
    > function bar(){}
    > }
    > bar(); // Error: bar is not defined.


    ( Actually foo.bar() )

    > What would be the point of declaring a function inside a function object
    > (i.e. creating a 'private member') if it was then public?


    I'd like it to be public. To define a private function, one could use a
    private variable and assign a function to it.
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 25, 2006
    #8
  9. wrote:

    >> The thing is, picture a large project where you want some
    >> encapsulation. But a lot of it being grouping of what would
    >> otherwise be static members of the global namespace. So that
    >> instead of
    >>
    >> fooEcks(), fooWye, fooZed()

    >
    > What is your objection to this method?


    And:

    >> you can have
    >>
    >> foo.ecks(), foo.wye(), foo.zed()

    >
    > Richard explained to me just yesterday that this is a bad idea
    > because JavaScript is not compiled but rather interpreted (...)


    Thanks for the pointer - I'll follow this on the other thread.

    >> and it impacts debugging, when you're trying to determine their
    >> name.

    >
    > Firefox spits out line numbers which makes it no problem.


    But debugging in particular and logging in general is so much more than
    looking at exception reports.
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 25, 2006
    #9
  10. Lasse Reichstein Nielsen wrote:

    >> You can given them a name, as in
    >>
    >> foo.ecks=function ecks(args){body}
    >>
    >> But this is error prone, since you have to keep the two names in sync,
    >> and that is a sure road to damnation.

    >
    > Then only write it once:
    > (...)
    > // extend object with named methods
    > function addMethods(target /*, functions...*/) {
    > for(var i = 1; i < arguments.length; i++) {
    > var func = arguments;
    > if(typeof func == "function") {
    > var name = funcName(func);
    > if (name) {
    > target[name] = func;
    > }
    > }
    > }
    > return target;
    > }
    >
    > // test
    > var ns = addMethods({accumulator:[]},
    > function add(n) {
    > this.accumulator.push(n);
    > return this;
    > },
    > function sum() {
    > for(var i=0,r=0; i < this.accumulator.length; i++) {
    > r+=this.accumulator;
    > }
    > return r;
    > });


    Hey, this looks great! But will the final code behave just in the same
    way as if it were defined with

    var ns = {accumulator:[]};
    ns.add = function add(n) { ... };
    ns.sum = function add(n) { ... };

    ?
    I see it does in the test given, but I ask this because of the scope
    chain - it seems to me that the first scope in both cases is the owner
    of var ns, but is it really?

    >> It turns out that in IE6, if you do
    >>
    >> function foo(){}; // with 'var foo' it won't work
    >> function foo.ecks(args){body};
    >>
    >> the browser does create a member of foo, named ecks, which is then
    >> your foo.ecks function.

    >
    > Nice idea, especially for extending prototypes:
    > function Foo.prototype.doFoo() { ... }
    > instead of
    > Foo.prototype.doFoo = function doFoo() {...}
    >
    > But it's completely non-standard, so only viable for scripting
    > specific known browsers and not for internet use.


    I was very unhappy when I found out it was IE specific.
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 25, 2006
    #10
  11. Richard Cornford wrote:

    >>>> However, in all of these, the functions created are
    >>>> anonymous. This may make no difference, but I don't
    >>>> like it and it impacts debugging, when you're trying
    >>>> to determine their name.
    >>>
    >>> This assumption appears to be the crux of your issue, but
    >>> you have not explained or justified it. Most javascript
    >>> error reports output line numbers (at minimum) so I don't
    >>> see any need to have a name associated with the function
    >>> for debugging.

    >>
    >> It's not an assumption, they really are anonymous. ...

    >
    > That was not the assumption. The assumption was that using anonymous
    > functions would impact debugging. It is an assumption as anonymous
    > functions are common on non-trivial javascript and if their use really
    > was a problem when debugging that would have been noticed by now.


    I said why it impacts debugging, if no one else is bothered by that is
    another matter. For all I know, people are tearing their hair off for
    the short supply of great javascript IDEs. I don't think it would hurt
    that a name could be determined for every function (if not their own,
    that of the variable they are assigned to, or that of the scope object).

    >> function foo()
    >> {
    >> function bar()
    >> {
    >> debug('hello', 1, 'a')
    >> }
    >> }
    >>
    >> And function debug would output something like
    >>
    >> '10:04:55 [foo] hello, 1, a'

    >
    > The 'hello' got into that output because you put it there, why not put
    > in the information that tells you what you need in the output, like
    > something that tells you the context of the debug call?


    Only because it would have to be done every time. Given the dynamic
    nature of javascript, it's even possible that 'bar' is bound to other
    scope, so maybe something like

    '10:04:55 [foo > bar] hello, 1, a'
    '10:04:57 [dif > bar] hello, 1, a'

    would be even more interesting. The next version of ECMAScript could
    surely define some more meta- functionality for functions, something
    that could be put to good use by IDEs.
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 25, 2006
    #11
  12. António Marques <> writes:

    > Hey, this looks great! But will the final code behave just in the same
    > way as if it were defined with
    >
    > var ns = {accumulator:[]};
    > ns.add = function add(n) { ... };
    > ns.sum = function add(n) { ... };


    It should, yes. There are no other scopes involved.

    /L
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, May 25, 2006
    #12
  13. António Marques wrote:

    > RobG wrote:
    >>> It turns out that in IE6, if you do
    >>>
    >>> function foo(){}; // with 'var foo' it won't work


    This line should work with `var foo' as well, but the next line should
    not work anyway.

    >>> function foo.ecks(args){body};
    >>>
    >>> the browser does create a member of foo, named ecks, which is then
    >>> your foo.ecks function.


    It works only in IE6 this way because it uses a proprietary extension of
    ECMAScript (or an implementation flaw). The FunctionDeclaration production
    requires the `function' keyword to be followed by whitespace, followed by
    an _identifier_ (not by a property accessor in dot notation), followed by
    the parameter list followed by the function body. Therefore, the standards
    compliant way is

    function foo() {}

    or a FunctionExpression, where the identifier after the `function' keyword
    is optional:

    var foo = function() {};

    And then:

    foo.ecks = function(args){ /* body */ };

    Because `foo' is always a reference to a Function object that can be
    augmented, like any native object:

    var foo = {}; // or `= new Object()'
    foo.ecks = function(args){ /* body */ };

    or

    var foo = {
    ecks: function(args){ /* body */ };
    };

    >>> I may be missing something, but this seems great to me,


    Even if written standards compliant, it has its drawbacks. One is that
    you need another function object. Another one, that I have pointed out
    recently, is that if you use the Function object as a constructor,
    objects created with it will not inherit the ecks() method; you have to
    augment the constructors prototype object to achieve that.

    >>> in absence of
    >>> alternatives (my preferred would be simply that internal named functions
    >>> were public).

    >>
    >> Do you mean:
    >>
    >> function foo(){
    >> function bar(){}
    >> }
    >> bar(); // Error: bar is not defined.

    >
    > ( Actually foo.bar() )


    foo.bar() in this context works only in JavaScript 1.5 due to a proprietary
    extension of ECMAScript (or an implementation flaw). With the advent of
    Gecko 1.8b2+ based UAs, like Firefox 1.5, that use JavaScript 1.6, it has
    become not only a deprecated practice but also an obsolete one.


    PointedEars

    P.S.
    Please don't remove attribution lines for quoted text that related to them.
    --
    A man who works with his hands is a laborer; a man who works with his
    hands and his brain is a craftsman; but a man who works with his hands
    and his brain and his heart is an artist.
    -- Louis Nizer, lawyer (1902-1994)
     
    Thomas 'PointedEars' Lahn, May 26, 2006
    #13
  14. wrote:

    > António Marques wrote:
    >> you can have
    >>
    >> foo.ecks(), foo.wye(), foo.zed()

    >
    > Richard explained to me just yesterday that this is a bad idea because
    > JavaScript is not compiled but rather interpreted.


    Probably you misunderstood, since JavaScript is (JIT-)compiled, then
    interpreted. Compiled vs. interpreted language is not the issue, but
    the moment of evaluation of identifiers is:

    > He wrote
    >
    > "Simulated namespaces are a very questionable notion. In other language
    > the namespaces are resolved when the code is compiled. Javascript must
    > resolve those long property accessors each and every time they are
    > used."



    PointedEars
    --
    This is Usenet. It is a discussion group, not a helpdesk. You post
    something, we discuss it. If you have a question and that happens to get
    answered in the course of the discussion, then great. If not, you can
    have a full refund of your membership fees. -- Mark Parnell in alt.html
     
    Thomas 'PointedEars' Lahn, May 26, 2006
    #14
  15. Hi,

    Thank you all for your help on this matter.
    --
    am

    laurus : rhodophyta : brezoneg : smalltalk : stargate
     
    António Marques, May 29, 2006
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    383
    John Roth
    Jul 29, 2005
  2. Jonathan Bartlett
    Replies:
    7
    Views:
    454
    Peter Nilsson
    Jul 8, 2005
  3. Wejn
    Replies:
    2
    Views:
    121
    Michal
    Nov 29, 2003
  4. Max Williams
    Replies:
    10
    Views:
    204
    Max Williams
    Dec 15, 2007
  5. Gunnar Hjalmarsson
    Replies:
    12
    Views:
    314
    Darren Dunham
    Feb 24, 2005
Loading...

Share This Page