|
Key
This line was removed.
This word was removed. This word was added.
This line was added.
|
Comment:
Changes (1)
View Page History\[14:28:57 CDT(-0500)\] {color:black} <yura> Bosmon: here's also a pastie of our conversation : http://pastie.org/4495346{color}
\[14:29:10 CDT(-0500)\] {color:black} <Bosmon> The issue on the table right now is, for example, how something which what you would call "at application scope" such as a DataSource can get its activities geared to request-scope actions such as error handling, etc.{color}
\[14:29:33 CDT(-0500)\] {color:black} <yura> Bosmon: so i wanted to suggest something like this gpii.when :) that is a wrapper to a deffered datasource.get or set{color}
\[14:29:33 CDT(-0500)\] {color:black} <Bosmon> The goal is to avoid unnecessary constructions and unnatural activities such as reconstructing the DataSource on every request which uses it{color}
\[14:29:56 CDT(-0500)\] {color:black} <yura> deferred{color}
\[14:29:59 CDT(-0500)\] {color:black} <colinclark> So the idea is that some datasources will be persistent across requests{color}
\[14:30:03 CDT(-0500)\] {color:black} <colinclark> thus "application scoped"{color}
\[14:30:10 CDT(-0500)\] {color:black} <Bosmon> The draft plan is to apply some kind of "event gearing" so that when the dataSource issues a fire to what it considers a "static event", it is actually geared by the framework to an appropriate request-scope event{color}
\[14:30:12 CDT(-0500)\] {color:black} <colinclark> and will take some kind of injected, request-level configuration?{color}
\[14:30:14 CDT(-0500)\] {color:black} <Bosmon> colinclark, right{color}
\[14:30:17 CDT(-0500)\] {color:black} <yura> colinclark: yes{color}
\[14:30:19 CDT(-0500)\] {color:black} <colinclark> k{color}
\[14:30:35 CDT(-0500)\] {color:black} <Bosmon> So this leaves the problem of how this "gearing mechanism" gets access to whichever request is relevant... "at the current time"{color}
\[14:30:39 CDT(-0500)\] {color:black} <colinclark> thanks for chatting here, i do always like to follow along even if i don't have immediate suggestions :){color}
\[14:30:56 CDT(-0500)\] {color:black} <Bosmon> In Java, this required things like "ThreadLocals" but of course in JS we just have one thread - but in practice many of the same issues will arise{color}
\[14:31:17 CDT(-0500)\] {color:black} <colinclark> This is a very naive question{color}
\[14:31:20 CDT(-0500)\] {color:black} <Bosmon> The primary one being that ANY callback which is supplied to any async (I/O) function which "suspends" will need to be wrapped{color}
\[14:31:26 CDT(-0500)\] {color:black} <colinclark> If I had a bigger ego, I'd probably be too embarrassed to ask it{color}
\[14:31:28 CDT(-0500)\] {color:black} <colinclark> :P{color}
\[14:31:38 CDT(-0500)\] {color:black} <colinclark> but can you tell me a bit about how Node's concurrency model works?{color}
\[14:31:48 CDT(-0500)\] {color:black} <Bosmon> Wrapped in order to restore the relevant request component to the "well-known place" (ThreadLocal) and then at the end of the callback to take it away again{color}
\[14:31:50 CDT(-0500)\] {color:black} <colinclark> there is, as you say, only one thread{color}
\[14:31:54 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[14:32:18 CDT(-0500)\] {color:black} <colinclark> Is there some kind of scheduler that suspends requests?{color}
\[14:32:34 CDT(-0500)\] {color:black} <colinclark> I imagine not{color}
\[14:32:39 CDT(-0500)\] {color:black} <Bosmon> colinclark - your request just suspends by itself, whenever it issues any async command{color}
\[14:32:44 CDT(-0500)\] {color:black} <Bosmon> I mean, "suspend" is a bad word{color}
\[14:32:46 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[14:32:49 CDT(-0500)\] {color:black} <Bosmon> Since it implies anything is suspended{color}
\[14:32:49 CDT(-0500)\] {color:black} <colinclark> :){color}
\[14:32:58 CDT(-0500)\] {color:black} <Bosmon> Since what has happened is that your request has RETURNED{color}
\[14:33:05 CDT(-0500)\] {color:black} <Bosmon> But I guess I still somehow like to use this bad word....{color}
\[14:33:28 CDT(-0500)\] {color:black} <Bosmon> Since clearly "something" remains - in the multi-threaded world, what remained was a complete stack frame complete with all the function calls in progress{color}
\[14:33:36 CDT(-0500)\] {color:black} <Bosmon> In the node world, all that remains is a "maze of callbacks"{color}
\[14:33:53 CDT(-0500)\] {color:black} <Bosmon> Which is just a data structure, waiting to revive when a callback is dispatched back into your code{color}
\[14:34:01 CDT(-0500)\] {color:black} <Bosmon> And so it is the location that these callbacks appear which is crucial{color}
\[14:34:28 CDT(-0500)\] {color:black} <Bosmon> We need to make sure that the first thing that happens, before anything else, is that what we call the "request component" is "restored" for the duration of the callback{color}
\[14:34:32 CDT(-0500)\] {color:black} <Bosmon> And that it is its own request component{color}
\[14:34:49 CDT(-0500)\] {color:black} <Bosmon> Normally this is done in node by passing the (req, res) pair as arguments through the entire rat's nest of callbacks{color}
\[14:34:55 CDT(-0500)\] {color:black} <Bosmon> But clearly this is a rather undesirable style{color}
\[14:35:37 CDT(-0500)\] {color:black} <Bosmon> So to answer yura's question, i) yes, having the async aspect of a service request wrapped up inside a promise makes this interception a great deal easier{color}
\[14:36:04 CDT(-0500)\] {color:black} <Bosmon> but ii) the same raw underlying mechanism still needs to exist, of accepting a callback and returning a callback which is a wrapped version which does the restoration{color}
\[14:37:25 CDT(-0500)\] {color:black} <yura> Bosmon: well that mechanism would need to accept a request object as well{color}
\[14:37:30 CDT(-0500)\] {color:black} <Bosmon> And then I referred to some "prior art" in the form of the "primary restoration wrapper" which existed within RSF.js for a broadly similar reason{color}
\[14:37:32 CDT(-0500)\] {color:black} <Bosmon> https://github.com/rsf/RSFComponents/blob/master/templates/src/webapp/content/js/rsf.js#L156-178{color}
\[14:37:47 CDT(-0500)\] {color:black} <Bosmon> You can tell by the tortured language how novel the idea of a higher-order function was at this point : P{color}
\[14:40:47 CDT(-0500)\] {color:black} <colinclark> ;){color}
\[14:41:01 CDT(-0500)\] {color:black} <colinclark> A THING that returns a THING{color}
\[14:41:46 CDT(-0500)\] {color:black} <Bosmon> Amazingly this code is still there in the 6-yr-old version.... and it even has a file closure!{color}
\[14:41:51 CDT(-0500)\] {color:black} <Bosmon> Had we actually met in Nov 2006?{color}
\[14:41:54 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[14:42:07 CDT(-0500)\] {color:black} <colinclark> we had indeed{color}
\[14:42:26 CDT(-0500)\] {color:black} <colinclark> yura: I couldn't tell if I was reading you right, but in the log you seemed slightly horrified by the prospect of this wrapper{color}
\[14:42:41 CDT(-0500)\] {color:black} <Bosmon> yura's private comment was that it seemed "sketchy" : P{color}
\[14:43:53 CDT(-0500)\] {color:black} <yura> colinclark: yes, generally just because that this whole conversation is related to reducing the rat's nest of function pointers{color}
\[14:44:15 CDT(-0500)\] {color:black} <colinclark> and you're hesitant to want to reduce them?{color}
\[14:44:25 CDT(-0500)\] {color:black} <yura> no the opposite{color}
\[14:44:26 CDT(-0500)\] {color:black} <colinclark> or you think this furthers the depth of the nest?{color}
\[14:44:32 CDT(-0500)\] {color:black} <colinclark> aha, yes{color}
\[14:44:52 CDT(-0500)\] {color:black} <Bosmon> Right, well, the idea is that the nest gets pushed into the framework{color}
\[14:44:56 CDT(-0500)\] {color:black} <Bosmon> At least where it exists{color}
\[14:45:07 CDT(-0500)\] {color:black} <Bosmon> In the long run we want to discourage people from writing raw callbacks at all{color}
\[14:45:16 CDT(-0500)\] {color:black} <Bosmon> But until we have infrastructure for it, we can't offer them much alternative{color}
\[14:45:21 CDT(-0500)\] {color:black} <yura> but then Bosmon mentions the whole idea of enforcing a standard approach{color}
\[14:45:28 CDT(-0500)\] {color:black} <Bosmon> The "bargain basement" level of support is i) offering callback wrappers{color}
\[14:45:45 CDT(-0500)\] {color:black} <Bosmon> As yura noted earlier, the next level of quality involves using ii) promises, which make the wrapping process less unpleasant{color}
\[14:46:02 CDT(-0500)\] {color:black} <Bosmon> Eventually we will have iii) A mature and declarative event boiling system where the whole wrapping process is completely invisible{color}
\[14:48:57 CDT(-0500)\] {color:black} <colinclark> Are you convinced by this approach, yura?{color}
\[14:49:02 CDT(-0500)\] {color:black} <colinclark> these three tiers?{color}
\[14:49:31 CDT(-0500)\] {color:black} <yura> ya that's the sort of thing that needs to be done {color}
\[14:49:57 CDT(-0500)\] {color:black} <Bosmon> Given the DataSource is one of the prime things that accepts callbacks, one level of the "wrapping" can be hidden in there{color}
\[14:50:24 CDT(-0500)\] {color:black} <Bosmon> Although ideally "one of its hands shouldn't know what the other hand is doing"{color}
\[14:50:34 CDT(-0500)\] {color:black} <Bosmon> It should just accept a generic array of callback wrappers that someone injects into it{color}
\[14:50:59 CDT(-0500)\] {color:black} <Bosmon> But in practice, one of them will be the one provided by the request-scope system which contextualises any callbacks sent into it with the appropriate request-scope object{color}
\[14:51:19 CDT(-0500)\] {color:black} <Bosmon> "with its other hand" it will then proceed to USE the wrapped callbacks by, perhaps, dispatching to a request-scoped "onError" event{color}
\[14:51:31 CDT(-0500)\] {color:black} <Bosmon> but in terms of the actual DataSource implementation code, it should be none the wiser{color}
\[14:52:08 CDT(-0500)\] {color:black} <Bosmon> It sends some callbacks into a processing function, and, quite separately, it dispatches to an apparently application-scoped event which in its own implementation makes use of the request component{color}
\[14:52:23 CDT(-0500)\] {color:black} <Bosmon> But the actual implementation code of any DataSource should stay unpolluted by (req, res) pollution{color}
\[14:52:34 CDT(-0500)\] {color:black} <yura> es{color}
\[14:52:38 CDT(-0500)\] {color:black} <Bosmon> Since obviously it's none of its business to know that it's actually executing within the scope of an express request{color}
\[14:53:02 CDT(-0500)\] {color:black} <Bosmon> This will make, naturally, writing browser-based test cases enormously easier....{color}
\[15:03:28 CDT(-0500)\] {color:black} <colinclark> so where'd we get to?{color}
\[15:03:58 CDT(-0500)\] {color:black} <Bosmon> A private chat with colinclark reminds me that another orthogonal piece of the DataSource infrastructure will be CACHING{color}
\[15:04:07 CDT(-0500)\] {color:black} <Bosmon> In addition to, as we mentioned, promise/callback orientation{color}
\[15:04:25 CDT(-0500)\] {color:black} <colinclark> bizarre how that reminiscing about the DARAPPLIER reminds you of caching ;){color}
\[15:04:36 CDT(-0500)\] {color:black} <Bosmon> A very plausible implementation of a DataSource will be one that doesn't issue more than one of a particular kind of I/O in the course of one web request{color}
\[15:04:50 CDT(-0500)\] {color:black} <Bosmon> Well, it reminded me of all that awkward code we would have to write in what was then called "BeanLocators"{color}
\[15:05:11 CDT(-0500)\] {color:black} <Bosmon> And how now we have a sensible environment supporting higher-order functions, this will just become stuffed somewhere in the "grade chain" of the DataSource{color}
\[17:03:29 CDT(-0500)\] {color:black} <colinclark> hey Bosmon {color}
\[17:04:06 CDT(-0500)\] {color:black} <colinclark> I remember a while ago Justin_o was asking about events that could distinguish between when a component has first been instantiated, and when all of its children were ready{color}
\[17:04:21 CDT(-0500)\] {color:black} <colinclark> And I realized I need to look up the semantic of our current onReady event{color}
\[17:04:48 CDT(-0500)\] {color:black} <colinclark> You mentioned "create" and "destroy" events in passing earlier{color}
\[17:05:15 CDT(-0500)\] {color:black} <colinclark> When do they both fire, specifically?{color}
\[17:05:17 CDT(-0500)\] {color:black} <Bosmon> We don't currently have an onReady event{color}
\[17:05:27 CDT(-0500)\] {color:black} <Bosmon> At least, not within the framework{color}
\[17:05:40 CDT(-0500)\] {color:black} <Bosmon> Right now I am working on events "onCreate" and "onDestroy"{color}
\[17:05:48 CDT(-0500)\] {color:black} <Bosmon> The former will fire when a component and all of its children are ready{color}
\[17:06:03 CDT(-0500)\] {color:black} <colinclark> onReady, I guess, is an ad-hoc convention amongst some component creators, I guess{color}
\[17:06:03 CDT(-0500)\] {color:black} <Bosmon> The latter will fire when/if someone issues "clearComponent" at the path it was instantiated at{color}
\[17:06:16 CDT(-0500)\] {color:black} <colinclark> I think the King will be pleased with those{color}
\[17:06:21 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[17:06:31 CDT(-0500)\] {color:black} <colinclark> And I guess it will address this bizarrely-filed issue: http://issues.fluidproject.org/browse/FLUID-4534{color}
\[17:06:34 CDT(-0500)\] {color:black} <colinclark> :){color}
\[17:06:38 CDT(-0500)\] {color:black} <Bosmon> yura currently has an ad hoc "hot patch" in CSpace's version of Infusion aimed at this functionality{color}
\[17:06:54 CDT(-0500)\] {color:black} <colinclark> Since the point seems to be "ready as an integrator would expect"{color}
\[17:07:03 CDT(-0500)\] {color:black} <Bosmon> Yes, it is pretty bizarrely filed{color}
\[17:07:13 CDT(-0500)\] {color:black} <Bosmon> Somehow, with all the details in the "environment" field{color}
\[17:07:31 CDT(-0500)\] {color:black} <colinclark> yes, I guess it's an easy mistake to make when rushing{color}
\[17:10:05 CDT(-0500)\] {color:black} <colinclark> Well, perhaps the King and I can co-review your create/destroy pull request when it lands?{color}
\[17:13:22 CDT(-0500)\] {color:black} <Bosmon> that would be awesome{color}
\[17:13:34 CDT(-0500)\] {color:black} <Bosmon> I'm finding the issue of when "onCreate" actually fires pretty interesting{color}
\[17:13:50 CDT(-0500)\] {color:black} <Bosmon> Actually when "onDestroy" fires is also pretty interesting :){color}
\[17:13:55 CDT(-0500)\] {color:black} <Bosmon> But in a slightly less interesting way{color}
\[17:14:31 CDT(-0500)\] {color:black} <Bosmon> A number of the oddities in the IoC implementation result from the difference in time between when a component is constructed, and when it is finally delivered to its parent as a property{color}
\[17:14:55 CDT(-0500)\] {color:black} <Bosmon> But there is a bit of a paradox, since you expect to be able to resolve IoC configuration for a component "as if" it is already in place in the tree...... before it actually appears in the tree{color}
\[17:15:09 CDT(-0500)\] {color:black} <Bosmon> Which is what all of this "pushUpcomingInstantiation" malarky is about{color}
\[17:15:20 CDT(-0500)\] {color:black} <colinclark> right{color}
\[17:15:36 CDT(-0500)\] {color:black} <Bosmon> As the very last action before dispatching to a component's creator, the IoC system makes a note of what component it is expecting to see{color}
\[17:15:52 CDT(-0500)\] {color:black} <Bosmon> Right now this is verging on the dangerous, since there are any number of other things which might happen instead{color}
\[17:15:57 CDT(-0500)\] {color:black} <Bosmon> But most of the time it works out{color}
\[17:16:09 CDT(-0500)\] {color:black} <Bosmon> Some of the risks are documented in the "broken trees" JIRA...{color}
\[17:16:51 CDT(-0500)\] {color:black} <Bosmon> But anyway, that issue aside, someone firing an "onCreate" event to the outside world I guess might expect rather more of the "moon landings" nature of the instantiation process to be fixed up{color}
\[17:17:13 CDT(-0500)\] {color:black} <Bosmon> Although of course once is simply NOT MEANT TO LOOK at ones subcomponents manually any more{color}
\[17:17:34 CDT(-0500)\] {color:black} <Bosmon> So whether or not they've actually arrived yet should in theory be a non-issue, so long as the IoC system is prepared to treat them as if they have{color}
\[17:18:39 CDT(-0500)\] {color:black} <Bosmon> So.... the "easy way out" of onCreate is simply to fire it immediately after the finalInitFunction{color}
\[17:19:17 CDT(-0500)\] {color:black} <Bosmon> But the risk with that approach is that someone listening to the event may be trying to do something which depends on the component being delivered to its supercomponent{color}
\[17:20:16 CDT(-0500)\] {color:black} <Bosmon> Another possibility is just to have more events{color}
\[17:21:30 CDT(-0500)\] {color:black} <Bosmon> "onCreate" at the point it is fully constructed, "onDeliver" when it is delivered into the tree (including further injections), "onClear" when it is cleared from anywhere in the tree, "onDestroy" when it is cleared from its construction point{color}
\[17:21:59 CDT(-0500)\] {color:black} <Bosmon> I'm worried about proliferating too many names, since these will now be stuck into the standard event space of every eventedComponent{color}
\[17:22:49 CDT(-0500)\] {color:black} <Bosmon> "onAttach" seems better than "onDeliver"....{color}
\[17:28:59 CDT(-0500)\] {color:black} <colinclark> Those seem like reasonable names{color}
\[17:29:22 CDT(-0500)\] {color:black} <colinclark> can you elaborate on your all-caps assertion from a bit earlier{color}
\[17:29:23 CDT(-0500)\] {color:black} <Bosmon> Uncharacteristically so, yes{color}
\[17:29:30 CDT(-0500)\] {color:black} <Bosmon> Which bit?{color}
\[17:29:36 CDT(-0500)\] {color:black} <Bosmon> Ah, not meant to look{color}
\[17:29:39 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[17:29:55 CDT(-0500)\] {color:black} <Bosmon> Yes, bearing in mind our general aesthetic of "aggregation implies no dependence"{color}
\[17:30:11 CDT(-0500)\] {color:black} <Bosmon> Which over time is seeming perhaps the only truly fundamental different to our approach over others{color}
\[17:30:33 CDT(-0500)\] {color:black} <Bosmon> I found myself wondering, for example, what exactly it is that GRADES allow us to do that we couldn't with a prototypal approach{color}
\[17:30:51 CDT(-0500)\] {color:black} <colinclark> that's a worthwhile thing to wonder, yes{color}
\[17:30:56 CDT(-0500)\] {color:black} <Bosmon> To which one immediate answer is "operate a multiple inheritance scheme without too much headache"{color}
\[17:31:06 CDT(-0500)\] {color:black} <Bosmon> But really that is relatively small beans, in the larger scheme of things{color}
\[17:31:15 CDT(-0500)\] {color:black} <colinclark> I guess the second question you have to be ready to answer, with that one...{color}
\[17:31:32 CDT(-0500)\] {color:black} <Bosmon> People might legitimately ask i) why might you go out of your way to make a multiple inheritance scheme, and ii) couldn't you do this by other means anyway{color}
\[17:31:38 CDT(-0500)\] {color:black} <colinclark> is "how does it allow you to operate a multiple inheritance scheme without the typical pitfalls of other familiar multiple inheritance schemes?"{color}
\[17:31:46 CDT(-0500)\] {color:black} <Bosmon> I remember when I first read about "mixins" I remember being puzzled by them{color}
\[17:32:03 CDT(-0500)\] {color:black} <Bosmon> Not precisely by what they did, but by the strange "no mans land" they seemed to occupy in the design space{color}
\[17:32:44 CDT(-0500)\] {color:black} <colinclark> how is it that they occupy this land?{color}
\[17:32:54 CDT(-0500)\] {color:black} <Bosmon> Which also plays into the question of "what is the distinction between GRADES and TYPES, and also, GRADES and CLASSES"{color}
\[17:33:10 CDT(-0500)\] {color:black} <Bosmon> Ok, just running back to deal with that question...{color}
\[17:33:25 CDT(-0500)\] {color:black} <Bosmon> Whenever you hear someone describing "mixins" it is invariably as some kind of "design alternative"{color}
\[17:33:40 CDT(-0500)\] {color:black} <colinclark> to inheritance, you mean?{color}
\[17:33:45 CDT(-0500)\] {color:black} <Bosmon> That is, having presented what is essentially a single-inheritance system, they will present mixins as a kind of "add-on"{color}
\[17:34:09 CDT(-0500)\] {color:black} <Bosmon> I saw them that way in C++, for example, there are numerous more or less unclear blog postings on "how to implement mixins in C++"{color}
\[17:34:11 CDT(-0500)\] {color:black} <colinclark> That's pretty much how "categories" were always presented to me in Objective-C{color}
\[17:34:28 CDT(-0500)\] {color:black} <Bosmon> And of course, not to say in C# and Java... and pretty much the same treatment for prototypal inheritance too{color}
\[17:34:38 CDT(-0500)\] {color:black} <colinclark> "you've already committed to an inheritance hierarchy, but you need some means to share some other behaviour"{color}
\[17:34:48 CDT(-0500)\] {color:black} <Bosmon> Yes, Objective-C seems to be the odd man out here, although I don't quite recall how it worked{color}
\[17:34:51 CDT(-0500)\] {color:black} <Bosmon> Did you ever use this feature?{color}
\[17:35:08 CDT(-0500)\] {color:black} <colinclark> Very rarely{color}
\[17:35:24 CDT(-0500)\] {color:black} <Bosmon> Was it implemented in a way which seemed natural, syntactically?{color}
\[17:35:37 CDT(-0500)\] {color:black} <colinclark> I guess the AppKit shipped with a handful of categories you could implement{color}
\[17:35:38 CDT(-0500)\] {color:black} <colinclark> Hmm{color}
\[17:35:47 CDT(-0500)\] {color:black} <colinclark> My memory of the syntax is pretty blurry{color}
\[17:35:53 CDT(-0500)\] {color:black} <colinclark> this was probably 2005, when I was thinking about it{color}
\[17:35:56 CDT(-0500)\] {color:black} <colinclark> let me look that up{color}
\[17:36:16 CDT(-0500)\] {color:black} <colinclark> From some random dorky tutorial:{color}
\[17:36:19 CDT(-0500)\] {color:black} <colinclark> "As an alternative to subclassing, Objective-C categories provide a means to add methods to a class."{color}
\[17:36:19 CDT(-0500)\] {color:black} <colinclark> :P{color}
\[17:36:31 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[17:36:32 CDT(-0500)\] {color:black} <Bosmon> I see it too{color}
\[17:36:47 CDT(-0500)\] {color:black} <colinclark> So, the thing about Objective-C is that, at heart, nothing is natural, syntactically{color}
\[17:36:49 CDT(-0500)\] {color:black} <Bosmon> Yes, it looks like it is the standard dorky thing, which just doesn't integrate nicely with the standard "type system" of the language{color}
\[17:37:02 CDT(-0500)\] {color:black} <Bosmon> Which leads on to the other point.... WHAT ARE TYPES{color}
\[17:37:16 CDT(-0500)\] {color:black} <colinclark> wait{color}
\[17:37:18 CDT(-0500)\] {color:black} <Bosmon> In theory, types are things which you could use to make decisions about what things are....{color}
\[17:37:27 CDT(-0500)\] {color:black} <colinclark> I'd like you to be more specific about that last point{color}
\[17:37:31 CDT(-0500)\] {color:black} <Bosmon> Ok{color}
\[17:37:39 CDT(-0500)\] {color:black} <colinclark> "integrating nicely with the standard type system"{color}
\[17:37:42 CDT(-0500)\] {color:black} <Bosmon> So in this page I see - http://macdevelopertips.com/objective-c/objective-c-categories.html{color}
\[17:37:44 CDT(-0500)\] {color:black} <colinclark> I'm curious if that is a meaningful point{color}
\[17:37:47 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[17:37:59 CDT(-0500)\] {color:black} <Bosmon> Well, it does relate to the direction I was just about to embark on{color}
\[17:38:12 CDT(-0500)\] {color:black} <colinclark> If I remember, you can refer to objects by their categories… But I might be quite wrong about that{color}
\[17:38:18 CDT(-0500)\] {color:black} <Bosmon> Which relates to "what can I do, knowing that a (category) exists"{color}
\[17:38:44 CDT(-0500)\] {color:black} <colinclark> ok{color}
\[17:38:48 CDT(-0500)\] {color:black} <colinclark> roll on{color}
\[17:39:13 CDT(-0500)\] {color:black} <Bosmon> Which usually boils down to... "how can I use these things to express polymorphism"{color}
\[17:39:26 CDT(-0500)\] {color:black} <colinclark> I guess, by the way, the main value point Apple always promoted for Categories was the first sentence on this page: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/chapters/occategories.html{color}
\[17:39:28 CDT(-0500)\] {color:black} <Bosmon> Which can come in two forms, which I guess you could call "programmatic" and "implicit"{color}
\[17:39:45 CDT(-0500)\] {color:black} <colinclark> In a compiled, closed-source dominated environment, "A category allows you to add methods to an existing class—even to one for which you do not have the source" means something, I suppose{color}
\[17:39:53 CDT(-0500)\] {color:black} <Bosmon> The first variety relates to various runtime queries you could issue, which in native JS amount to things like "instanceof"{color}
\[17:40:20 CDT(-0500)\] {color:black} <Bosmon> And it is failure of things like instanceof which would make the various "bolt-on mixin" approaches unworkable, if they were used to express multiple inheritance{color}
\[17:40:55 CDT(-0500)\] {color:black} <Bosmon> instanceof is implemented almost "in hardware" in the VM, and it's clear it could never be made to traverse up a tree, only to do a linear search{color}
\[17:41:16 CDT(-0500)\] {color:black} <colinclark> right{color}
\[17:41:25 CDT(-0500)\] {color:black} <Bosmon> Then, more traditionally, both for us and the OO types is the idea of "implicit polymorphism", which relates to the idea of "dispatch"{color}
\[17:41:56 CDT(-0500)\] {color:black} <colinclark> hmm{color}
\[17:41:57 CDT(-0500)\] {color:black} <colinclark> ok{color}
\[17:42:01 CDT(-0500)\] {color:black} <Bosmon> That is, "here is the name of an operation I want to invoke in the context of this... 'object'.... what can I make the choice of the actual operation depend on"{color}
\[17:42:44 CDT(-0500)\] {color:black} <Bosmon> Both OO-types and also we ourselves I guess would discourage people to just naturally muck in and issue "instanceof" calls to tell what something is, rather than to defer to some kind of dispatch mechanism{color}
\[17:42:56 CDT(-0500)\] {color:black} <Bosmon> But in JS we also have a 3rd possible answer to this question, which is "duck typing"{color}
\[17:43:19 CDT(-0500)\] {color:black} <Bosmon> That is, you can fail to rely on any kind of categorical model at all, and just look individually for the presence of every operation you might be interested in{color}
\[17:43:27 CDT(-0500)\] {color:black} <Bosmon> Which is a wierd kind of halfway house{color}
\[17:43:55 CDT(-0500)\] {color:black} <Bosmon> I guess Smalltalk's model for this is similar with the so-called "DoesNotUnderstand" message which as I recall was its response to attempting to invoke an operation that was missing totally{color}
\[17:44:08 CDT(-0500)\] {color:black} <Bosmon> But of course this says nothing about WHICH operation you actually end up choosing when you execute something{color}
\[17:44:23 CDT(-0500)\] {color:black} <Bosmon> I guess this is suggesting that relying on "per-operation duck typing" in the long run will be unreliable{color}
\[17:44:40 CDT(-0500)\] {color:black} <Bosmon> Since you would think there need not really be any difference between an operation which doesn't exist at all, and one that does{color}
\[17:44:43 CDT(-0500)\] {color:black} <Bosmon> If that makes any sense :){color}
\[17:45:10 CDT(-0500)\] {color:black} <Bosmon> I mean, there needn't be a categorical distinction like that, in many cases... especially if one is thinking in terms of event handlers which may have 0 or more registered listeners{color}
\[17:45:41 CDT(-0500)\] {color:black} <colinclark> yes, that makes some sense{color}
\[17:46:01 CDT(-0500)\] {color:black} <Bosmon> So yes.... people who traditionally use CLASSES have tended to want to try to see this usage in terms of the equivalent model of TYPES{color}
\[17:46:08 CDT(-0500)\] {color:black} <Bosmon> Only, as we know, with the trees seen "upside down"{color}
\[17:46:25 CDT(-0500)\] {color:black} <Bosmon> In that insofar as classes imply a type relationship, a superclass acts as a subtype.... and vice versa{color}
\[17:46:40 CDT(-0500)\] {color:black} <Bosmon> Which got enshrined in this thing the "Liskov Substitution Principle"{color}
\[17:47:06 CDT(-0500)\] {color:black} <Bosmon> Which states that if you are doing things in some sense "properly", "an instance of a derived class should be acceptable wherever an instance of a base class is acceptable"{color}
\[17:47:34 CDT(-0500)\] {color:black} <Bosmon> Where this concept of "acceptable" already gets us mired in all kinds of awkward semantics of the same kind we wrestled with when we tried to decide "what is our contract on models"{color}
\[17:48:01 CDT(-0500)\] {color:black} <Bosmon> But that aside, the basic idea was that you SHOULD use subclasses as if they were supertypes{color}
\[17:48:38 CDT(-0500)\] {color:black} <Bosmon> And so all of these odd examples where you made a class "StrangeCATT" which derived from CATT but overrode the "sound" method to say "woof" were considered as "violations of the type model"{color}
\[17:49:00 CDT(-0500)\] {color:black} <Bosmon> But with our model of GRADES, it's clear that these kinds of violations would be expected to happen ALL THE TIME......{color}
\[17:49:40 CDT(-0500)\] {color:black} <Bosmon> But that also this is not really anything "very" special, these kinds of violations were always clearly on the table in every OO-based system that was ever invented{color}
\[17:49:49 CDT(-0500)\] {color:black} <colinclark> indeed{color}
\[17:49:55 CDT(-0500)\] {color:black} <Bosmon> I guess my feeling is that in very strongly typed systems like Haskell, they are NOT on the table....{color}
\[17:50:08 CDT(-0500)\] {color:black} <Bosmon> Since as I understand it, a Haskell type contract is a firm guarantee that a particular kind of behaviour is present{color}
\[17:50:50 CDT(-0500)\] {color:black} <Bosmon> Whatever that in fact means, but it at least guarantees that there will not be a signature incompatibility, or a missing operation - the former of which is defined recursively in terms of the type system in any case{color}
\[17:51:05 CDT(-0500)\] {color:black} <Bosmon> So yes, what is new about GRADES doesn't seem to be anything to do with that{color}
\[17:51:45 CDT(-0500)\] {color:black} <Bosmon> But to leap backwards several pages, if there is anything new about the system, it is the fact that aggregation or containment doesn't imply dependence{color}
\[17:51:59 CDT(-0500)\] {color:black} <Bosmon> Which as far as I can see is genuinely new, in a system of any kind{color}
\[17:52:27 CDT(-0500)\] {color:black} <Bosmon> Finally connecting back to this point that was in caps.... that one isn't expected to actually look at your own properties to see what components are there{color}
\[17:52:57 CDT(-0500)\] {color:black} <Bosmon> And to the extent that the IoC system works already, that already may as well need not be the case{color}
\[17:53:33 CDT(-0500)\] {color:black} <Bosmon> As we see during that "magic interval" between the point when a component begins to construct, and the point where it is delivered to its parents, the system has no problem resolving IoC references which are implicit to the fact that the component is "already there" in the place it should be{color}
\[17:55:18 CDT(-0500)\] {color:black} <colinclark> okay, but you'll have to unpack these two things a bit more, since they're clearly the same in some way that won't be immediately apparent to most programmers{color}
\[17:55:27 CDT(-0500)\] {color:black} <Bosmon> Which two things?{color}
\[17:55:56 CDT(-0500)\] {color:black} <Bosmon> I guess, in passing, this is to some extent exposing the fact that the idea behind "grades" right now is pretty orthogonal to fundamental ideas of the way the IoC system works{color}
\[17:56:00 CDT(-0500)\] {color:black} <colinclark> First, with grades. So you say "aggregation or containment doesn't imply dependence"--how is it, specifically, that Grades enable this?{color}
\[17:56:06 CDT(-0500)\] {color:black} <Bosmon> But this is one of the crucial things that I expect to change in the new framework{color}
\[17:56:15 CDT(-0500)\] {color:black} <Bosmon> Ok yes, that is exactly the question{color}
\[17:56:27 CDT(-0500)\] {color:black} <Bosmon> Right now grades don't really do anything much to enable that at all{color}
\[17:56:42 CDT(-0500)\] {color:black} <Bosmon> The framework already enjoyed a lot of that property before we had grades at all{color}
\[17:56:53 CDT(-0500)\] {color:black} <colinclark> The second point is this idea that you needn't look at your own properties to see what components are there. So, what if I need to operate on a subcomponent? What do I do?{color}
\[17:57:12 CDT(-0500)\] {color:black} <colinclark> I can perhaps inuit the answers to these questions, but I think it's worth spelling them out very clearly here.{color}
\[17:57:16 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[17:57:17 CDT(-0500)\] {color:black} <colinclark> intuit{color}
\[17:57:24 CDT(-0500)\] {color:black} <Bosmon> Inuits are great too :){color}
\[17:57:27 CDT(-0500)\] {color:black} <Bosmon> I wish I had met one{color}
\[17:57:28 CDT(-0500)\] {color:black} <colinclark> :){color}
\[17:57:51 CDT(-0500)\] {color:black} <Bosmon> Yes, the answers to the two questions are somewhat related, but they're much more closely related in the "new framework" than the current one{color}
\[17:58:14 CDT(-0500)\] {color:black} <colinclark> So I'll add a third question, which I hope you can answer after discussing the "new framework"{color}
\[17:58:19 CDT(-0500)\] {color:black} <Bosmon> And this relates to the issue of "what can I do with a (grade/class/type) name"{color}
\[17:58:30 CDT(-0500)\] {color:black} <Bosmon> To which one of the answers should be.... "I can use it for dispatch"{color}
\[17:58:39 CDT(-0500)\] {color:black} <Bosmon> Or more broadly, "I can use it to locate components, as well as implementations"{color}
\[17:58:41 CDT(-0500)\] {color:black} <colinclark> which I guess is "what affordances do grades offer to developers currently, and when should they use them?"{color}
\[17:59:09 CDT(-0500)\] {color:black} <colinclark> so you're making a distinction between locating "components" vs. "implementations"{color}
\[17:59:21 CDT(-0500)\] {color:black} <colinclark> more, please :){color}
\[17:59:54 CDT(-0500)\] {color:black} <Bosmon> So, the answer to your 2nd question is, "You should use directives to the framework in order to "select" components/implementations to participate in some forms of binding"{color}
\[18:00:20 CDT(-0500)\] {color:black} <Bosmon> Of which the most classic form of binding involves events, but we also have invokers, and free functions, etc.{color}
\[18:00:31 CDT(-0500)\] {color:black} <Bosmon> Or even just the bare process of shipping values from one part of the system to the other{color}
\[18:00:35 CDT(-0500)\] {color:black} <colinclark> that's too opaque for me :){color}
\[18:00:39 CDT(-0500)\] {color:black} <Bosmon> Or shipping component references from one part of the system to another{color}
\[18:00:49 CDT(-0500)\] {color:black} <colinclark> oh wait{color}
\[18:00:55 CDT(-0500)\] {color:black} <colinclark> sorry, second question :){color}
\[18:01:12 CDT(-0500)\] {color:black} <colinclark> okay{color}
\[18:01:17 CDT(-0500)\] {color:black} <colinclark> so let's go to a naive design example{color}
\[18:01:17 CDT(-0500)\] {color:black} <Bosmon> So in order to say, "I want A connected to B", rather than in the classic model, i) getting a reference to A, ii) getting a reference to B, and then programmatically prodding them, you will instead....{color}
\[18:01:27 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[18:01:28 CDT(-0500)\] {color:black} <colinclark> go{color}
\[18:01:32 CDT(-0500)\] {color:black} <Bosmon> Issue a "rule" to the framework that designates A and B by some form of "selection"{color}
\[18:01:50 CDT(-0500)\] {color:black} <Bosmon> Such that A and B can be "recognised if they already exist" or "brought into existence if they do not exist" etc.{color}
\[18:02:18 CDT(-0500)\] {color:black} <Bosmon> And then it is the framework's job to implement whatever kind of relation should exist between A and B, for as long as they exist{color}
\[18:02:43 CDT(-0500)\] {color:black} <Bosmon> And so this feeds back into the question... "what kinds of rules can be issued to the framework in order to recognise things"{color}
\[18:03:02 CDT(-0500)\] {color:black} <colinclark> sure, but it seemed as if you were suggesting that a component never "prods" its subcomponents{color}
\[18:03:12 CDT(-0500)\] {color:black} <Bosmon> And right now these kinds of rules are extremely limited by the fact that every component in the system is provided with exactly ONE "type name"{color}
\[18:03:39 CDT(-0500)\] {color:black} <Bosmon> Yes - mainly because there should be no particular distinction between those components which are its subcomponents, and those which are elsewhere{color}
\[18:04:11 CDT(-0500)\] {color:black} <Bosmon> What may be "here today" may be "gone tomorrow"..... subject to the scoping visibility rules wich Justin_o ran in to last week{color}
\[18:04:28 CDT(-0500)\] {color:black} <colinclark> I'm still not quite satisfied{color}
\[18:04:32 CDT(-0500)\] {color:black} <Bosmon> We can't promise to "connect anything anywhere to anything else anywhere else" without constraint since the implementation would become too expensive{color}
\[18:04:45 CDT(-0500)\] {color:black} <Bosmon> And would start to have runtime costs which scaled with the size of the entire program{color}
\[18:04:51 CDT(-0500)\] {color:black} <Bosmon> Ok{color}
\[18:04:52 CDT(-0500)\] {color:black} <colinclark> All of this appears to be limited to the process of getting references to things{color}
\[18:05:04 CDT(-0500)\] {color:black} <colinclark> Surely at some point, if I'm a B and I have a reference to an A{color}
\[18:05:16 CDT(-0500)\] {color:black} <colinclark> I should be able to do something with that A?{color}
\[18:05:21 CDT(-0500)\] {color:black} <colinclark> like invoke a method on it?{color}
\[18:05:52 CDT(-0500)\] {color:black} <Bosmon> Well, perhaps bafflingly, we are heading for a point in which there is no longer any meaning given to the condition of saying "I'm a B"{color}
\[18:06:02 CDT(-0500)\] {color:black} <Bosmon> Although this is typically the point in the conversation where michelled starts throwing things at us{color}
\[18:06:07 CDT(-0500)\] {color:black} <colinclark> :){color}
\[18:06:09 CDT(-0500)\] {color:black} <colinclark> Okay...{color}
\[18:06:28 CDT(-0500)\] {color:black} <Bosmon> But yes, we do imagine a tower of "increasingly real" things much like the one we appealed to in GPII earlier today{color}
\[18:06:44 CDT(-0500)\] {color:black} <Bosmon> Somewhere in the world, real physical things like callbacks and function handles, and Bs actually exist{color}
\[18:07:10 CDT(-0500)\] {color:black} <colinclark> And surely, to get back to the original point, I need to have some stable idea of when that B will actually exist{color}
\[18:07:17 CDT(-0500)\] {color:black} <Bosmon> But we need to be prepared for a world in which was can simply behave as if they don't, and there is no longer any clear idea of being "I'm a B, I have a reference to an A and I want to invoke a method on it"{color}
\[18:07:29 CDT(-0500)\] {color:black} <colinclark> okay, let's unpack that then{color}
\[18:07:46 CDT(-0500)\] {color:black} <colinclark> How are we Dissolving the Identity of Things, specifically?{color}
\[18:08:18 CDT(-0500)\] {color:black} <Bosmon> Which eventually "disintermediates" into a statement of the kind, "I'm a B, and I reach a certain point in my lifecycle which I name Q at which point it is signalled"{color}
\[18:08:33 CDT(-0500)\] {color:black} <Bosmon> And then separatly, "I'm an A and I have such a point in my lifecycle named P"{color}
\[18:09:08 CDT(-0500)\] {color:black} <Bosmon> And then separately again, a rule which says, "in the following environment, when an A and B are simultaneously available, B's Q should be aligned with A's P"{color}
\[18:09:38 CDT(-0500)\] {color:black} <Bosmon> Which in event terms we might say, "A's P is registered as a listener to the firing of B's Q"{color}
\[18:10:19 CDT(-0500)\] {color:black} <colinclark> So this is going to seem a very blunt interpretation...{color}
\[18:10:24 CDT(-0500)\] {color:black} <colinclark> Are you simply saying that:{color}
\[18:10:34 CDT(-0500)\] {color:black} <Bosmon> But the dissolving relates to the fact that the thing which we call "B's Q" may have absolutely no idea about what B is, or what Q is either{color}
\[18:10:36 CDT(-0500)\] {color:black} <colinclark> 1. The relationship between A and B will be mediated by the framework, contextually{color}
\[18:10:38 CDT(-0500)\] {color:black} <colinclark> and{color}
\[18:11:26 CDT(-0500)\] {color:black} <Bosmon> In much the same way that our "DataSource" in the chat earlier was expected to have no idea about "express's req and res" despite the fact that if you looked at any of its actually function call workflow, it couldn't get out of bed without intimately being a consumer of these objects and their lifecycles{color}
\[18:11:33 CDT(-0500)\] {color:black} <colinclark> 2. The traditional "direct pointer to a thing which I call a method on" will be exchanged for "I fire an event, and things happen"?{color}
\[18:11:49 CDT(-0500)\] {color:black} <Bosmon> Yes, I think that's generally right{color}
\[18:11:58 CDT(-0500)\] {color:black} <colinclark> there's more to it, though{color}
\[18:12:03 CDT(-0500)\] {color:black} <Bosmon> Yes, there is{color}
\[18:12:12 CDT(-0500)\] {color:black} <Bosmon> Would you like to expand on what you see as more?{color}
\[18:12:16 CDT(-0500)\] {color:black} <colinclark> obvious questions like "how can i just fire an event, if I need some response back from the thing that handled it?"{color}
\[18:12:20 CDT(-0500)\] {color:black} <Bosmon> Right{color}
\[18:12:27 CDT(-0500)\] {color:black} <colinclark> and even "there could be multiple things!"{color}
\[18:12:37 CDT(-0500)\] {color:black} <colinclark> clearly this ties to the model idiom{color}
\[18:12:38 CDT(-0500)\] {color:black} <Bosmon> I had a good "shower insight" about this just yesterday, I think{color}
\[18:12:42 CDT(-0500)\] {color:black} <colinclark> but you'll have to elaborate{color}
\[18:12:52 CDT(-0500)\] {color:black} <Bosmon> Which leads on from the discussion we had when I was in Toronto, I think 2 visits back{color}
\[18:13:01 CDT(-0500)\] {color:black} <Bosmon> When we were talking with KINGG about this idea of "events and counter-events"{color}
\[18:13:14 CDT(-0500)\] {color:black} <Bosmon> Which in this modern world of "events and callbacks" and "promises" starts to become more and more concrete{color}
\[18:13:26 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[18:13:36 CDT(-0500)\] {color:black} <colinclark> i suppose you are right{color}
\[18:13:37 CDT(-0500)\] {color:black} <Bosmon> But it's clear that this idea of "getting a value back" could only ever be implemented in terms of "there being an event fired which delivered the value"{color}
\[18:13:51 CDT(-0500)\] {color:black} <Bosmon> Which then feeds on to, "how on earth do we think about and configure such things"{color}
\[18:14:34 CDT(-0500)\] {color:black} <colinclark> I was going to argue that we have some of this, via the idea of a shared, visible model and the changeApplier{color}
\[18:14:37 CDT(-0500)\] {color:black} <Bosmon> And I realised that the next thing which has to come shortly in the "event boiling syntax" is this kind of "V shaped pattern" - where one has to be able to designate a PAIR of events, either on the same component, or on different components, that participate in this kind of relationship{color}
\[18:14:49 CDT(-0500)\] {color:black} <Bosmon> Right now, we would have to do it somewhat messily, one at a time{color}
\[18:15:01 CDT(-0500)\] {color:black} <Bosmon> That is, configure the two halves of the relationship separately{color}
\[18:15:37 CDT(-0500)\] {color:black} <Bosmon> But "one half" of it can be seen in our current boiling syntax where we say "Register the following event as "fired in relay" by firing of this other event"{color}
\[18:16:08 CDT(-0500)\] {color:black} <Bosmon> Which automatically brings an implicit "listener" into existence, which attaches to, say, B's event, such that the body of the listener fires A's event in relay, possibly with some boiled arguments{color}
\[18:16:48 CDT(-0500)\] {color:black} <Bosmon> But obviously the other part of that is being able to say, "A, after that, is going to indulge in some corresponding activity which fires back the other way"{color}
\[18:17:02 CDT(-0500)\] {color:black} <Bosmon> To, presumably, some yet differently named thing on B{color}
\[18:17:24 CDT(-0500)\] {color:black} <Bosmon> Which is what we will have which fills the role of "calling a function and getting a return value from it" in the Olde World{color}
\[18:18:13 CDT(-0500)\] {color:black} <colinclark> So then, how does the ChangeApplier fit into this?{color}
\[18:18:26 CDT(-0500)\] {color:black} <Bosmon> So events of this kind WILL come in "pairs"... but they will be pairs which are drawn up in configuration, rather than by some convention{color}
\[18:18:28 CDT(-0500)\] {color:black} <colinclark> Aside from simply not yet having "first class status" within IoC-bound events{color}
\[18:18:31 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[18:18:41 CDT(-0500)\] {color:black} <Bosmon> The ChangeApplier shouldn't disrupt this picture too much{color}
\[18:18:52 CDT(-0500)\] {color:black} <colinclark> ok{color}
\[18:18:56 CDT(-0500)\] {color:black} <colinclark> keep going{color}
\[18:19:00 CDT(-0500)\] {color:black} <Bosmon> Since all it amounts to is a particular signature and semantic for dealing with events{color}
\[18:19:25 CDT(-0500)\] {color:black} <Bosmon> It should be possible to boil events "up" into ChangeApplier events and then back "down" again into plain events without any particular formality{color}
\[18:20:01 CDT(-0500)\] {color:black} <Bosmon> As well as exploiting the fact that the framework has some insight into what the signature of ChangeApplier events actually is, and use this for more complex boiling scenarios where there isn't a one-to-one correspondence between the events{color}
\[18:20:21 CDT(-0500)\] {color:black} <Bosmon> The kind of thing you ran into when you were trying to "demultiplex" the events in your FileQueueView and realised the framework wasn't capable of it{color}
\[18:20:35 CDT(-0500)\] {color:black} <colinclark> right{color}
\[18:20:53 CDT(-0500)\] {color:black} <Bosmon> You had an event source which fired model-coordinated events from a single model, which was required to broadcast onto just ONE of a selection of components, all laid out coordinated with the model path{color}
\[18:21:21 CDT(-0500)\] {color:black} <Bosmon> So yura's "superApplier" work will feed into this bit of the implementation{color}
\[18:21:31 CDT(-0500)\] {color:black} <Bosmon> But in the end it will be represented as just more "boiling" configuration{color}
\[18:22:16 CDT(-0500)\] {color:black} <Bosmon> But in the end, we want the framework to be able to "consume" any conceivable style for expressing asynchrony{color}
\[18:22:33 CDT(-0500)\] {color:black} <Bosmon> Whether it is expressed in "rat's nest" callback style, promises of one kind or another, or monads, or some other thing{color}
\[18:22:56 CDT(-0500)\] {color:black} <Bosmon> And allow it all to be expressed by essentially the same configuration describing the "callback geometry" in each case{color}
\[18:23:39 CDT(-0500)\] {color:black} <Bosmon> Which separately, controls two things - i) what is the relationship between the TIMING of the elements participating, and ii) what is the relationship between the IDENTITY of the elements participating{color}
\[18:23:52 CDT(-0500)\] {color:black} <Bosmon> And optionally a 3rd thing, what actual information do they exchange during the interaction{color}
\[18:24:11 CDT(-0500)\] {color:black} <Bosmon> Right now we are doing quite well at part 3, moderately well at part 2, and quite badly at part 1{color}
\[18:24:47 CDT(-0500)\] {color:black} <Bosmon> In that we can iii) boil "event signatures" quite easily, ii) with moderate flexibility, talk about how things are wired together, but i) have at the moment only ONE primitive for adjusting the timing and multiplicity of events{color}
\[18:24:59 CDT(-0500)\] {color:black} <Bosmon> Which is our "AND"-based "last event of a set" boiling scheme{color}
\[18:25:16 CDT(-0500)\] {color:black} <colinclark> what does that look like, in practice?{color}
\[18:25:22 CDT(-0500)\] {color:black} <Bosmon> "once each of the events in this set have fired once, fire the following event"{color}
\[18:25:43 CDT(-0500)\] {color:black} <colinclark> ok, yes{color}
\[18:26:58 CDT(-0500)\] {color:black} <colinclark> So let's go back to grades,then{color}
\[18:27:02 CDT(-0500)\] {color:black} <Bosmon> https://github.com/fluid-project/infusion/blob/master/src/webapp/tests/framework-tests/core/js/FluidIoCTests.js#L524-545{color}
\[18:27:04 CDT(-0500)\] {color:black} <Bosmon> Like this{color}
\[18:27:21 CDT(-0500)\] {color:black} <Bosmon> Somehow it takes me at least a dozen clicks before I figure out how to select a range of lines in github{color}
\[18:27:40 CDT(-0500)\] {color:black} <colinclark> :){color}
\[18:27:50 CDT(-0500)\] {color:black} <colinclark> i thought it had gotten a bit more reliable{color}
\[18:27:56 CDT(-0500)\] {color:black} <Bosmon> And I'm SURE the shift key is involved somehow{color}
\[18:28:02 CDT(-0500)\] {color:black} <Bosmon> But it never seems to work the first few times{color}
\[18:28:25 CDT(-0500)\] {color:black} <Bosmon> Anyway, this shows an event named "boiledDouble" which fires only once two constituent events have fired already{color}
\[18:28:37 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[18:28:57 CDT(-0500)\] {color:black} <colinclark> what other timing primitives do you envision?{color}
\[18:28:58 CDT(-0500)\] {color:black} <Bosmon> We already have "power of free reference" around the tree, so any of these events may be on the same component, or different components{color}
\[18:29:23 CDT(-0500)\] {color:black} <Bosmon> So the two next most powerful ones will be i) the "callback timing" and ii) the "demultiplex timing"{color}
\[18:29:41 CDT(-0500)\] {color:black} <Bosmon> So i) says, this event fires, and expects a response back, to be delivered somewhere{color}
\[18:30:12 CDT(-0500)\] {color:black} <Bosmon> ii) says, we don't necessarily want to fire this event at the same target 1-for-1, but instead use some details of the events contents (say, its model reference) to decode which target to deliver it to{color}
\[18:30:23 CDT(-0500)\] {color:black} <colinclark> "to be delivered somewhere" is an interesting point{color}
\[18:30:43 CDT(-0500)\] {color:black} <Bosmon> And of course the inverse of ii), "we want to collect together events from this collection of sources onto this ONE target"{color}
\[18:31:14 CDT(-0500)\] {color:black} <Bosmon> Should we have those down, we will be in a very powerful position...{color}
\[18:31:34 CDT(-0500)\] {color:black} <Bosmon> I wonder if you had any "shower time" to think of the implications of FRP for Flocking yet...{color}
\[18:31:40 CDT(-0500)\] {color:black} <colinclark> not yet{color}
\[18:31:59 CDT(-0500)\] {color:black} <colinclark> i am close to a point where it will become quite relevant{color}
\[18:32:09 CDT(-0500)\] {color:black} <colinclark> and it has been keeping me tossing and turning in bed for the past week or two{color}
\[18:32:15 CDT(-0500)\] {color:black} <Bosmon> So yes, grades, will eventually have a better role in the system, since the new implementation, ALL grade names ("type names") used to derive a component's options will be available through resolution through the IoC system{color}
\[18:32:19 CDT(-0500)\] {color:black} <colinclark> but i'm not yet clear enough on the issue{color}
\[18:32:30 CDT(-0500)\] {color:black} <Bosmon> AS WELL AS being able to use any type names which are issued through the "renaming" action of a demands block{color}
\[18:32:44 CDT(-0500)\] {color:black} <Bosmon> Which will get rid of this appalling horribleness we have in Uploader, for example{color}
\[18:32:53 CDT(-0500)\] {color:black} <colinclark> how so?{color}
\[18:32:58 CDT(-0500)\] {color:black} <colinclark> that seems very appealing :){color}
\[18:33:10 CDT(-0500)\] {color:black} <Bosmon> Where it simply becomes impossible for people on the outside to refer to the thing as just an "uploader" without having to know all kinds of grimy details about what concrete type it ends up having in the end{color}
\[18:33:26 CDT(-0500)\] {color:black} <Bosmon> Since the framework right now always decisively picks the "final concrete type" as the one used to describe the component to the framework{color}
\[18:33:55 CDT(-0500)\] {color:black} <Bosmon> And so I guess this is where the "grade-like thinking" comes in{color}
\[18:34:13 CDT(-0500)\] {color:black} <colinclark> that makes sense{color}
\[18:34:16 CDT(-0500)\] {color:black} <colinclark> So, let's back up a bit{color}
\[18:34:16 CDT(-0500)\] {color:black} <Bosmon> In that it is simply impossible to avoid having a kind of "unbounded multiple inheritance system" for how implementations are described in terms of types{color}
\[18:34:40 CDT(-0500)\] {color:black} <Bosmon> Given that ANY third party needs to be able to come along, invent a completely new type name and start to use it, without disturbing any of the people in the original codebase{color}
\[18:34:50 CDT(-0500)\] {color:black} <colinclark> I was surprised, when the new model transformation system landed, to see what struck me as the first examples of Grades in "user code"{color}
\[18:35:02 CDT(-0500)\] {color:black} <Bosmon> Ah, which things are you referring to{color}
\[18:35:12 CDT(-0500)\] {color:black} <colinclark> I had previously just imagined that Grades were some kind of limited, fixed collection of things{color}
\[18:35:24 CDT(-0500)\] {color:black} <colinclark> So, first today, and then in the future...{color}
\[18:35:35 CDT(-0500)\] {color:black} <Bosmon> Yes, I guess to some extent they were{color}
\[18:35:42 CDT(-0500)\] {color:black} <colinclark> What do Grades offer an ordinary developer using Infusion?{color}
\[18:35:49 CDT(-0500)\] {color:black} <Bosmon> There was certainly a small "shock" when the first user-defined grade was seen in the wild : P{color}
\[18:36:05 CDT(-0500)\] {color:black} <colinclark> I mean, why would me or michelled make a grade, and what would it do?{color}
\[18:36:10 CDT(-0500)\] {color:black} <Bosmon> But I guess the idea had always been implicitly there that there would be some, it just hadn't been emphasised{color}
\[18:36:11 CDT(-0500)\] {color:black} <colinclark> What was the first user-defined grade, anyway?{color}
\[18:36:23 CDT(-0500)\] {color:black} <Bosmon> Well, I think a great example of a "half-user-defined-grade" is in the VideoPlayer integration, for example{color}
\[18:36:33 CDT(-0500)\] {color:black} <Bosmon> I mean, "half" in the sense that it wasn't really a proper user who made this one : P{color}
\[18:36:37 CDT(-0500)\] {color:black} <Bosmon> BUt still, it could have been anyone{color}
\[18:36:42 CDT(-0500)\] {color:black} <colinclark> lol{color}
\[18:36:46 CDT(-0500)\] {color:black} <Bosmon> Let me see if I can find the relevant code...{color}
\[18:37:37 CDT(-0500)\] {color:black} <Bosmon> https://github.com/fluid-project/videoPlayer/blob/demo/js/VideoPlayer_framework.js#L181-186{color}
\[18:37:39 CDT(-0500)\] {color:black} <Bosmon> This one{color}
\[18:37:49 CDT(-0500)\] {color:black} <Bosmon> I mean, I think it is particularly useful because it is sort of "opportunistic"{color}
\[18:38:01 CDT(-0500)\] {color:black} <Bosmon> Arguably, it was only done to compensate for a lack of framework facility in another area{color}
\[18:38:08 CDT(-0500)\] {color:black} <Bosmon> But it could have been done for any reason...{color}
\[18:38:42 CDT(-0500)\] {color:black} <Bosmon> But it was observed, over some time, that a whole bunch of components were starting to cooperate in using a particular style, with certain piece of repeated "boilerplate"£{color}
\[18:39:07 CDT(-0500)\] {color:black} <Bosmon> But this couldn't be factored out completely by just using free functions, since a lot of the boilerplate related to elements which were already in common in between the code sites in terms of being components{color}
\[18:39:24 CDT(-0500)\] {color:black} <Bosmon> In that they were already "model components", and then they all had another option on them which expressed a "path indirection"{color}
\[18:39:50 CDT(-0500)\] {color:black} <Bosmon> So.... in many ways, this is pretty "classical"{color}
\[18:40:09 CDT(-0500)\] {color:black} <colinclark> from this light, it looks like a mixin :){color}
\[18:40:17 CDT(-0500)\] {color:black} <Bosmon> There are only a few things here that aren't the same as they would be in the "classic OO refactoring story" that would have arisin through just "extracting a new base class"{color}
\[18:40:23 CDT(-0500)\] {color:black} <colinclark> but one you can determine exists, given an instance of the thing at some point{color}
\[18:40:34 CDT(-0500)\] {color:black} <colinclark> ok, keep going{color}
\[18:40:36 CDT(-0500)\] {color:black} <Bosmon> I mean, for a start, in a language which, as you say, didn't support free mixins, it would have been impossible : P{color}
\[18:42:01 CDT(-0500)\] {color:black} <colinclark> what else?{color}
\[18:42:22 CDT(-0500)\] {color:black} <Bosmon> Well, I guess this usage is relatively "vanilla"... we get to export a couple of helpful implementations to "client code" that also gain some power as a result of the use of the "model idiom"{color}
\[18:42:39 CDT(-0500)\] {color:black} <Bosmon> I mean, perhaps there isn't anything particularly profound here, other than the fact that the implementation style is quite clear and natural{color}
\[18:42:59 CDT(-0500)\] {color:black} <Bosmon> And doesn't involves any annoyances about "multiple base classes" or "type contracts" etc.{color}
\[18:43:12 CDT(-0500)\] {color:black} <colinclark> elaborate on those annoyances?{color}
\[18:43:24 CDT(-0500)\] {color:black} <Bosmon> Perhaps this could have been done almost as easily using "categories", minus getting the model idiom for free{color}
\[18:44:03 CDT(-0500)\] {color:black} <colinclark> So how did we get the "model idiom" for free?{color}
\[18:44:07 CDT(-0500)\] {color:black} <colinclark> I must be driving you nuts{color}
\[18:44:12 CDT(-0500)\] {color:black} <Bosmon> Well, we knew that the component was already a "modelComponent"{color}
\[18:44:14 CDT(-0500)\] {color:black} <colinclark> since many of these questions are somewhat circular{color}
\[18:44:21 CDT(-0500)\] {color:black} <Bosmon> And in fact made sure that it was one, by mentioning this again in our grade{color}
\[18:44:26 CDT(-0500)\] {color:black} <colinclark> ah, yes{color}
\[18:44:31 CDT(-0500)\] {color:black} <Bosmon> Which perhaps leads on to the "multiple base class" issue{color}
\[18:44:50 CDT(-0500)\] {color:black} <Bosmon> Since ordinarily, this might have raised some annoying question like, "Am I two model components or am I one?" : P{color}
\[18:45:16 CDT(-0500)\] {color:black} <colinclark> lol{color}
\[18:45:18 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[18:45:20 CDT(-0500)\] {color:black} <Bosmon> Which reminds me of ROGERS THE BULLS in the Terry Pratchett novels about this Bull, who because he saw double all the time, had decided he was actually two bulls{color}
\[18:45:38 CDT(-0500)\] {color:black} <colinclark> :){color}
\[18:46:00 CDT(-0500)\] {color:black} <colinclark> Okay, so at risk of dangerously essentializing... {color}
\[18:46:05 CDT(-0500)\] {color:black} <Bosmon> In many multiple-inheritance languages, the concept of inheritance gets confused with the concept of aggregation{color}
\[18:46:12 CDT(-0500)\] {color:black} <colinclark> The answer to my question about "why would a developer use Grades today?"{color}
\[18:46:30 CDT(-0500)\] {color:black} <Bosmon> And so to declare that "I derive from X" somehow separately implies, "I 'contain' an 'instance' of X"{color}
\[18:46:56 CDT(-0500)\] {color:black} <Bosmon> Since the grade-based system only talks about aggregation of CONFIGURATION rather than aggregation of runtime artifacts, this confusion goes away{color}
\[18:46:57 CDT(-0500)\] {color:black} <colinclark> Is that it provides a scheme for reusing behaviour in manner that avoids the key pitfalls of multiple inheritance and mixins{color}
\[18:47:09 CDT(-0500)\] {color:black} <Bosmon> Yes, I guess that is a basic kind of answer{color}
\[18:47:13 CDT(-0500)\] {color:black} <colinclark> which in the first case, the problem is the ambiguity of multiple base classes{color}
\[18:47:33 CDT(-0500)\] {color:black} <colinclark> the second is the fact that mixins don't typically engage with a "type system"{color}
\[18:47:34 CDT(-0500)\] {color:black} <Bosmon> In the future, we expect these things to be even more powerful, as a result of being able to use the extra grade names later on, for the purposes of component selection{color}
\[18:47:49 CDT(-0500)\] {color:black} <colinclark> even if our "type system" is specifically mediated by a particular framework{color}
\[18:48:08 CDT(-0500)\] {color:black} <Bosmon> But there are a lot of very simple uses of grades like this one, that just amount to factoring out a certain group of "instance-related common behaviour or configuration"{color}
\[18:48:25 CDT(-0500)\] {color:black} <Bosmon> Actually this grade is pretty untypical in actually bothering to define new methods{color}
\[18:48:25 CDT(-0500)\] {color:black} <colinclark> So then the future answer hinges on the fact that Grades become further names by which users can contextually resolve relationships between things?{color}
\[18:48:40 CDT(-0500)\] {color:black} <Bosmon> but that is largely because of the issue I mentioned earlier, that its job is to compensate for a framework deficiency{color}
\[18:48:47 CDT(-0500)\] {color:black} <Bosmon> Yes, that's right{color}
\[18:48:50 CDT(-0500)\] {color:black} <colinclark> so what else am i missing here?{color}
\[18:49:04 CDT(-0500)\] {color:black} <colinclark> to bring it up from the level of essentializing to being at least satisfying{color}
\[18:49:19 CDT(-0500)\] {color:black} <Bosmon> It will in the future be possible to "dispatch" on the fact that components in a relationship might include an "indirectReader" etc.{color}
\[18:49:21 CDT(-0500)\] {color:black} <Bosmon> Hmm{color}
\[18:49:21 CDT(-0500)\] {color:black} <colinclark> have i missed out on other important nuances?{color}
\[18:49:31 CDT(-0500)\] {color:black} <Bosmon> Well, what aspects of essentializing are not satisfying : P{color}
\[18:49:49 CDT(-0500)\] {color:black} <colinclark> I don't know{color}
\[18:49:55 CDT(-0500)\] {color:black} <colinclark> I just felt that my summary was a bit blunt{color}
\[18:49:56 CDT(-0500)\] {color:black} <colinclark> unrefined{color}
\[18:50:02 CDT(-0500)\] {color:black} <Bosmon> It is the fact that we expect 100% of the responsibilities of future components to be derived from pure configuration, that makes grades eventually so powerful{color}
\[18:50:08 CDT(-0500)\] {color:black} <Bosmon> Since they simply operate on this configuration{color}
\[18:51:02 CDT(-0500)\] {color:black} <Bosmon> In some views, grades just represent a particularly complex case of model transformations...{color}
\[18:51:28 CDT(-0500)\] {color:black} <Bosmon> With the power of i) resolving a set of names up chains which form a graph, and ii) making sure that just one instance of each name is retained{color}
\[18:51:48 CDT(-0500)\] {color:black} <Bosmon> And then iii) in the particular tree order visited, merging together the blocks of configuration which were found{color}
\[18:52:42 CDT(-0500)\] {color:black} <Bosmon> And in the future, iv) retaining the set of names which were seen in order to make further decisions about locating implementations{color}
\[18:54:42 CDT(-0500)\] {color:black} <Bosmon> So yes, I guess it is the fact that grades are a means of interacting with configuration, rather than some opaque handle to some data structures which may or may not be managed by a compiler and runtime, that makes them more powerful{color}
\[18:55:11 CDT(-0500)\] {color:black} <Bosmon> I guess it's not really clear what ALL the implications of that are, but certainly the benefits lie in that direction, and derive from it...{color}
\[18:55:27 CDT(-0500)\] {color:black} <colinclark> yes{color}
\[18:55:43 CDT(-0500)\] {color:black} <michelled> seems to me the power is in the truly fine grained reuse of code {color}
\[18:55:43 CDT(-0500)\] {color:black} <colinclark> Okay, this was actually a really satisfying{color}
\[18:55:44 CDT(-0500)\] {color:black} <Bosmon> For example, they allow people to reason about aspects of some object that they produce, before they produce it{color}
\[18:55:58 CDT(-0500)\] {color:black} <Bosmon> For example, what kind of signature it has, and other dependences, etc.{color}
\[18:56:22 CDT(-0500)\] {color:black} <Bosmon> Typically these kinds of "reflective" systems are cumbersome at best, where they are provided at all{color}
\[18:56:40 CDT(-0500)\] {color:black} <colinclark> right{color}
\[18:56:45 CDT(-0500)\] {color:black} <colinclark> I have been trying to pin down grades in a clearer way, and this helps a lot{color}
\[18:57:00 CDT(-0500)\] {color:black} <colinclark> Next conversation like this, I'd like to revisit one of your more abstract assertions again{color}
\[18:57:13 CDT(-0500)\] {color:black} <colinclark> the notion of JSON component trees as a kind of AST{color}
\[18:57:19 CDT(-0500)\] {color:black} <colinclark> which we talked about a few months ago{color}
\[18:57:23 CDT(-0500)\] {color:black} <Bosmon> So it is grades, for example, which allow the framework to tell which argument position you have decided to put your "options" into, should you want to put them somewhere else{color}
\[18:57:35 CDT(-0500)\] {color:black} <colinclark> right{color}
\[18:57:47 CDT(-0500)\] {color:black} <Bosmon> And I imagine there is a whole host of similar kinds of use cases which will emerge over time{color}
\[18:58:05 CDT(-0500)\] {color:black} <colinclark> Is that because Grade configuration includes an argumentMap?{color}
\[18:58:12 CDT(-0500)\] {color:black} <Bosmon> Yes, it is{color}
\[18:58:25 CDT(-0500)\] {color:black} <Bosmon> Java is sort of exceptional in having a mostly complete, "static" introspection system which lets you get information about code before it starts executing{color}
\[18:58:38 CDT(-0500)\] {color:black} <Bosmon> But it is extremely hard to use, and no ordinary developer would dream of trying it{color}
\[18:59:20 CDT(-0500)\] {color:black} <Bosmon> In LISP, you could try to "inspect" the entire implementation of something, but it would be almost impossible to tell the "wood from the trees"{color}
\[19:00:17 CDT(-0500)\] {color:black} <Bosmon> In Haskell you could write a program which depended on the static properties of some implementation, but it would be very hard to say whether you had actually instantiated the target item or not : P{color}
\[19:00:22 CDT(-0500)\] {color:black} <colinclark> meaning, what was data and was functions, for example?{color}
\[19:00:36 CDT(-0500)\] {color:black} <colinclark> (in the LISP case){color}
\[19:00:37 CDT(-0500)\] {color:black} <Bosmon> Given that the details of the Haskell type system are intimately built in to its runtime engine{color}
\[19:00:44 CDT(-0500)\] {color:black} <Bosmon> Yes{color}
\[19:01:09 CDT(-0500)\] {color:black} <colinclark> I'll have to look at the Haskell type system at some point{color}
\[19:01:33 CDT(-0500)\] {color:black} <Bosmon> I can't say I really know much "of" it.... just a collection of things "about" it{color}
\[19:02:05 CDT(-0500)\] {color:black} <Bosmon> Much like my knowledge of Chinese doesn't actually make me fit to have conversations with Chinese people : P{color}
\[19:02:29 CDT(-0500)\] {color:black} <Bosmon> I think I understood a bit more about "monads" in the shower yesterday as well{color}
\[19:02:38 CDT(-0500)\] {color:black} <Bosmon> After thinking about Yura's callback/promises problem{color}
\[19:02:58 CDT(-0500)\] {color:black} <Bosmon> That article by "C.D. Smith" was more helpful than I thought, once boiled down to its essentials{color}
\[19:03:13 CDT(-0500)\] {color:black} <Bosmon> http://cdsmith.wordpress.com/2012/04/18/why-do-monads-matter/{color}
\[19:04:02 CDT(-0500)\] {color:black} <Bosmon> He makes the crucial point that all "monads" which are ever used by practical computer scientists can be derived from the so-called "Kleisli arrows"{color}
\[19:04:14 CDT(-0500)\] {color:black} <Bosmon> "first, Kleisli arrows are just plain old ordinary functions, but with weird-looking ranges."{color}
\[19:04:23 CDT(-0500)\] {color:black} <Bosmon> And so, this is a fact that was already familiar to us in Engage{color}
\[19:04:32 CDT(-0500)\] {color:black} <Bosmon> Since it relates to our pattern of an "extended payload"{color}
\[19:05:10 CDT(-0500)\] {color:black} <Bosmon> We had already observed that all the effects of an AJAX call, including success or failure, could be condensed into an "extended payload" by embedding the actually returned value at a path within the outer, more full payload{color}
\[19:05:19 CDT(-0500)\] {color:black} <Bosmon> Which then left space to store all of the extra, extraneous status info{color}
\[19:05:47 CDT(-0500)\] {color:black} <Bosmon> So, C.D. Smith already makes clear that this kind of thing is ALL that is going on when you use some kind of Monadic pattern for "signalling" values from place to place{color}
\[19:06:13 CDT(-0500)\] {color:black} <Bosmon> The only OTHER thing that is going on is that you can say that there is a thing which you might call an "execution model" or a "semantic"{color}
\[19:06:26 CDT(-0500)\] {color:black} <Bosmon> Or more directly, a rule for combining such "extended payloads" together{color}
\[19:06:53 CDT(-0500)\] {color:black} <colinclark> last question, and then I have to run{color}
\[19:07:03 CDT(-0500)\] {color:black} <colinclark> Are grades completely distinct from the IoC system?{color}
\[19:07:12 CDT(-0500)\] {color:black} <Bosmon> In the case of the "fallible I/O" or as they call it "Maybe Monad" this has a very simple consequence - any operation which gives a "failed" result, when combined with any other, also yields a "failed" result{color}
\[19:07:12 CDT(-0500)\] {color:black} <colinclark> In that they are just operated on by the options merging system?{color}
\[19:07:34 CDT(-0500)\] {color:black} <Bosmon> And also by a form of "short-circuit" propery that avoids ever trying to evaluate any of the "inner payloads" of the resulting expressions{color}
\[19:07:45 CDT(-0500)\] {color:black} <Bosmon> Yes, they are right now almost completely distinct{color}
\[19:07:55 CDT(-0500)\] {color:black} <Bosmon> In that grades are implemented in the core framework{color}
\[19:08:14 CDT(-0500)\] {color:black} <Bosmon> Well, firstly in that sense, and secondly in the sense that the IoC system also pretty much ignores whatever was in them{color}
\[19:08:40 CDT(-0500)\] {color:black} <Bosmon> They can be used to derive IoC configuration, but in the case IoC isn't loaded, they can just be used to derive plain option values{color}
\[19:08:53 CDT(-0500)\] {color:black} <Bosmon> In the absence of having any "expansion" process when components instantiate{color}
\[19:09:21 CDT(-0500)\] {color:black} <Bosmon> I don't see why we can't carry on with that split, but the "new options merging system" will be implemented quite differently in order to enable it to call out to IoC expansion during merging{color}
\[19:10:26 CDT(-0500)\] {color:black} <colinclark> Have you ever benchmarked flud.merge() alongside $.extend(), given your comment a while back about using the two strategically?{color}
\[19:10:43 CDT(-0500)\] {color:black} <Bosmon> I don't think I ever have, no{color}
\[19:11:40 CDT(-0500)\] {color:black} <colinclark> ok{color}
\[19:12:01 CDT(-0500)\] {color:black} <colinclark> just idly curious :){color}
\[19:12:05 CDT(-0500)\] {color:black} <colinclark> thanks, dude{color}
\[19:12:15 CDT(-0500)\] {color:black} <colinclark> this was very interesting and satisfyingly enlightening{color}
\[19:12:16 CDT(-0500)\] {color:black} <Bosmon> Thanks for hanging out, dude...{color}
\[19:12:34 CDT(-0500)\] {color:black} <colinclark> see you soon{color}