Hey John,

I hadn’t seen the exportJs support before (I haven’t done any work with 
features in a long time) -- that does look very similar!  (and as an aside -- 
hats off to whoever came up with that scheme to be able to closure compile JS 
in isolation but still have fully qualified symbols available in the global 
space -- its absolutely brilliant)

I wrote a quick test gadget which required feature exportjs and did some 
testing -- and it comes pretty close to doing everything we'd need already, so 
I don’t see any reason why it couldn’t be augmented to handle all the cases my 
helper function does.  Then it'd just be a matter of making it part of the core 
feature set so it would be available for use in any features that wanted to 
take advantage of it.

So I guess that comes back to Paul's original question though -- if enough 
people preferred the first style Paul proposed I'd be happy to take a crack at 
augmenting exportJs to support this use case.  So we'd end up with JS that 
looked something like this:

//could be from foo-utils.js
exportJs("shindig.util", (function() {
    var privateData = "this is private";

    var privateFunction = function() {
        console.log(privateData);
    };

    var calculateFoo = function() {
        privateFunction();
    };

    var doAlotOfFoo = function() {
        //do alot of foo
    };

    return {
        calculateFoo: calculateFoo,
        doAlotOfFoo: doAlotOfFoo
    };
})());

//could be from bar-utils.js
exportJs("shindig.util", (function() {
    var privateFunction = function() {
        console.log("calculateBar called");
    };

    var calculateBar = function() {
        privateFunction();
    };

    return {
        publicData: "this is public",
        calculateBar: calculateBar
    };
})());

exportJs("shindig.some.emptyNamespace", {});
shindig.some.emptyNamespace.xyz = "ABC";

--Jesse

>-----Original Message-----
>From: John Hjelmstad [mailto:[email protected]]
>Sent: Thursday, July 28, 2011 5:58 PM
>To: [email protected]
>Subject: Re: javascript readability..
>
>Hey Jesse,
>
>Interesting idea here -- this sounds suspiciously akin to the functionality
>already present in exportJs(...) used for exporting symbols. This method
>upserts the namespace in much the same way as your helper method does.
>Thoughts on whether we could reuse or augment that?
>
>-j
>
>On Thu, Jul 28, 2011 at 7:52 AM, Ciancetta, Jesse E. <[email protected]>wrote:
>
>> I agree with John -- I also prefer the first style Paul presented (which I
>> believe is also the most prevalent style in Shindig currently).
>>
>> With respect to the issues that Michael raised about building up a
>> namespace from across different files -- this got me thinking about a little
>> namespace utility a colleague of mine wrote a while back.  That utility just
>> took a target namespace like "shindig.util.foo", created an empty object in
>> it (without clobbering any parts of the target namespace that may have
>> already existed) and returned it -- so you could then do something like
>> shindig.util.foo.x = ... directly without needing to create each piece of
>> the namespace manually.
>>
>> And with some (well, a lot) of tweaking I was able to turn that function
>> into a more general purpose namespacing function that takes an optional
>> object to place into the target namespace -- and if the target namespace
>> already exists it takes the properties of the optional object and appends
>> them to the existing namespace.
>>
>> So I think if enough people preferred the first style Paul presented,
>> something like this could be used to work around the issues Michael raised.
>>  Here is the function and some sample usages (with the caveat that I haven’t
>> actually used this for anything real so there could be some bugs in it):
>>
>> var shindig = shindig || (function() {
>>    var namespace = function(targetNamespace, optObject) {
>>        //get a reference to the global window object
>>        var object = window;
>>
>>        //if no object was provided to put into the namespace create an
>> empty one
>>        optObject = optObject || {};
>>
>>        //split the namespace into its parts
>>        var namespaces = targetNamespace.split(".");
>>
>>        //for each part of the namespace
>>        for (var i = 0; i < namespaces.length; i++) {
>>            //see if this part is already defined
>>            if (typeof object[namespaces[i]] === "undefined") {
>>                //if its not defined already -- put an object into it
>>                //if we're at the end of the targetNamespace, put the new
>> object into it,
>>                //otherwise drop in an empty object as a placeholder
>>                object[namespaces[i]] = (i + 1) == namespaces.length ?
>> optObject : {};
>>            } else {
>>                //there is already something here -- see if we're at the end
>> of the targetNamespace
>>                if ((i + 1) == namespaces.length) {
>>                    //make sure its an object we can append to
>>                    if (typeof object[namespaces[i]] === "object") {
>>                        //go ahead and add all the public properties on
>> optObject to the target namespace
>>                        for (var property in optObject) {
>>                            object[namespaces[i]][property] =
>> optObject[property];
>>                        }
>>                    } else {
>>                        throw "Cannot append new properties to object of
>> type " + typeof object[namespaces[i]];
>>                    }
>>                }
>>            }
>>
>>            object = object[namespaces[i]];
>>        }
>>
>>        return object;
>>    };
>>
>>    return {
>>        namespace: namespace
>>    };
>> })();
>>
>> //could be from foo-utils.js
>> shindig.namespace("shindig.util", (function() {
>>    var privateData = "this is private";
>>
>>    var privateFunction = function() {
>>        console.log(privateData);
>>    };
>>
>>    var calculateFoo = function() {
>>        privateFunction();
>>    };
>>
>>    var doAlotOfFoo = function() {
>>        //do alot of foo
>>    };
>>
>>    return {
>>        calculateFoo: calculateFoo,
>>        doAlotOfFoo: doAlotOfFoo
>>    };
>> })());
>>
>> //could be from bar-utils.js
>> shindig.namespace("shindig.util", (function() {
>>    var privateFunction = function() {
>>        console.log("calculateBar called");
>>    };
>>
>>    var calculateBar = function() {
>>        privateFunction();
>>    };
>>
>>    return {
>>        publicData: "this is public",
>>        calculateBar: calculateBar
>>    };
>> })());
>>
>> shindig.namespace("shindig.some.emptyNamespace");
>> shindig.some.emptyNamespace.xyz = "ABC";
>>
>> >-----Original Message-----
>> >From: Michael Hermanto [mailto:[email protected]]
>> >Sent: Tuesday, July 26, 2011 6:15 PM
>> >To: [email protected]
>> >Subject: Re: javascript readability..
>> >
>> >What didn't work for me with --
>> >   shindig.foo = function() {
>> >     return { 'bar': ... };
>> >   }();
>> >... is that methods in the same namespace have to be all
>> >defined/implemented
>> >in one file.
>> >
>> >ie: it's fine if all gadgets.rpc.* is implemented in a file rpc.js, but
>> not
>> >fine when gadgets.util.* are implemented across different files/features
>> >across core.util.dom, core.util.string, etc. When feature core.util pulls
>> >all these files in, it will effectively stomp all the previously-defined
>> >core.util.*.
>> >
>> >The tendency has been to make libraries smaller and more focussed to
>what
>> >they do, ie: this means breaking up features into sub-features. To do so,
>> I
>> >had to convert more-focussed core.util.[dom|string|...] to fully-defined
>> >names. Unless the above style (with shindig.foo) doesn't have this
>> >limitation (ie: can incrementally define more methods on top what has
>been
>> >defined), I personally prefer the fully-defined names, for consistency.
>> >
>> >
>> >
>> >2011/7/26 ๏̯͡๏ Jasvir Nagra <[email protected]>
>> >
>> >> I don't have a strong preference either way although it's nice when
>> >> reviewing code to have all the exported things exported once when they
>> >> share
>> >> a scope full of private helpers and other state.  It also helps convey
>> when
>> >> the setup of a particular part of the object graph is done.
>> >> Eg.
>> >>
>> >> shindig.foo = (function() {
>> >>  // ... all the helper functions and shared state ...
>> >>  ...
>> >>  return { bar: bar, baz: baz };
>> >> }();
>> >> // at this point I know from convention that shindig.foo is done being
>> >> setup
>> >> and will have just "bar" and "baz"
>> >>
>> >> vs.
>> >>
>> >> shindig.foo.bar = function() { ... }
>> >> /// ... a lot of code later
>> >> shindig.foo.baz = function() { ... }
>> >>
>> >> If the amount of code between shindig.foo and the return is long, I'd
>> >> suggest another alternative that I think has the advantage of both:
>> >>
>> >> (function() {
>> >>  // ... all the helper functions and shared state ...
>> >>
>> >>  shindig.foo = {
>> >>    bar: bar,
>> >>    baz: baz
>> >>  }
>> >> })();
>> >>
>> >> On Tue, Jul 26, 2011 at 2:19 PM, John Hjelmstad <[email protected]>
>> >wrote:
>> >>
>> >> > With the model we're using with exportJs, you actually can't as easily
>> do
>> >> > that or wrap "singleton"/namespaced items, unless you . exportJs(...)
>> is
>> >> > injected after the closure.
>> >> >
>> >> > function() {
>> >> >  foo.bar.baz = function() { }
>> >> > }();
>> >> > exportJs("foo.bar", [foo,foo.bar], {baz:"baz"});
>> >> >
>> >> > Of course, you can if you also update the style guide to prepend
>> window:
>> >> >
>> >> > function() {
>> >> >  window.foo.bar.baz = function() { }
>> >> > }();
>> >> >
>> >> > ...though that requirement seems a little awkward and verbose to me.
>> >> >
>> >> > --j
>> >> >
>> >> > On Tue, Jul 26, 2011 at 2:12 PM, Dan Dumont <[email protected]>
>> >wrote:
>> >> >
>> >> > > As mentioned by Paul before you can define:
>> >> > >
>> >> > > function(){
>> >> > >   FooClass.prototype.method = function() { }
>> >> > >  FooClass.prototype.method2 = function() { }
>> >> > > }();
>> >> > >
>> >> > > to get a local scope.
>> >> > >
>> >> > > I think this makes it easier to audit what must be included in an
>> >> export.
>> >> > > And when you come up for air soon, maybe we can talk about AMD
>> >format
>> >> and
>> >> > > what that brings to the table.  :)
>> >> > >
>> >> > >
>> >> > >
>> >> > > From:   John Hjelmstad <[email protected]>
>> >> > > To:     [email protected],
>> >> > > Date:   07/26/2011 04:43 PM
>> >> > > Subject:        Re: javascript readability..
>> >> > >
>> >> > >
>> >> > >
>> >> > > I still prefer status quo, as it reads more like a proper class to
>> me,
>> >> > > while
>> >> > > being less verbose and centralizing the exported method definitions
>> in
>> >> a
>> >> > > single place.
>> >> > >
>> >> > > As well, this question's corollary is whether to convert all
>> >> instantiable
>> >> > > objects to the form:
>> >> > >
>> >> > > FooClass.prototype.method = function() { }
>> >> > > FooClass.prototype.method2 = function() { }
>> >> > >
>> >> > > ...from:
>> >> > > FooClass = function() {
>> >> > >  // private state
>> >> > >  function method() { }
>> >> > >  function method2() { }
>> >> > >  return {
>> >> > >    method: method,
>> >> > >    method2: method2
>> >> > >  };
>> >> > > };
>> >> > >
>> >> > > On this note, I'm conflicted. I like having actual private state,
>> but
>> >> > > prototype-style is more efficient.
>> >> > >
>> >> > > Enough people have complained over time about each of the existing
>> >> idioms
>> >> > > though that I suppose I could go the other direction, if it's
>> causing
>> >> > > development trouble.
>> >> > >
>> >> > > --j
>> >> > >
>> >> > > On Tue, Jul 26, 2011 at 6:17 AM, Ryan J Baxter <[email protected]
>> >
>> >> > > wrote:
>> >> > >
>> >> > > > +1 As well, I think its easier to read.
>> >> > > >
>> >> > > > -Ryan
>> >> > > >
>> >> > > > Email: [email protected]
>> >> > > > Phone: 978-899-3041
>> >> > > > developerWorks Profile
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > > From:   Dan Dumont/Westford/IBM@Lotus
>> >> > > > To:     [email protected],
>> >> > > > Date:   07/26/2011 09:00 AM
>> >> > > > Subject:        Re: javascript readability..
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > > +1
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > > From:   Paul Lindner <[email protected]>
>> >> > > > To:     [email protected],
>> >> > > > Date:   07/26/2011 02:51 AM
>> >> > > > Subject:        javascript readability..
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > > Hi,
>> >> > > >
>> >> > > > I'm curious to know what people think about some of the idioms in
>> the
>> >> > JS
>> >> > > > code you find in shindig.  There's an awful lot of stuff like
>> this:
>> >> > > >
>> >> > > > shindig.foo = function(){
>> >> > > >  //...
>> >> > > >  var myFunction = function() {
>> >> > > >     }
>> >> > > >
>> >> > > >  return {'foo': myFunction,
>> >> > > >            'bar': function() {
>> >> > > >               return 'bar';
>> >> > > >            }};
>> >> > > > }();
>> >> > > >
>> >> > > >
>> >> > > > Just search for @member to see the various places.
>> >> > > >
>> >> > > > What would people think if we moved to fully defined names for
>> >> > > > function/method definitions instead?
>> >> > > >
>> >> > > > You could still wrap this inside a closure if you wanted local
>> scope:
>> >> > > >
>> >> > > > function() {
>> >> > > >  shindig.foo.foo = function() {
>> >> > > >     ...
>> >> > > >  }
>> >> > > >  shindig.foo.bar = function() {
>> >> > > >     ...
>> >> > > >  }
>> >> > > > }();
>> >> > > >
>> >> > > > --
>> >> > > > Paul Lindner -- [email protected] -- linkedin.com/in/plindner
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > > >
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> >
>> >>
>>

Reply via email to