[04:02:35] [connected at Mon Sep 19 04:02:35 2005] [04:02:35] <> *** Looking up your hostname... [04:02:35] <> *** Checking ident [04:02:35] <> *** Found your hostname [04:03:06] <> *** No identd (auth) response [04:03:06] <> *** Your host is kornbluth.freenode.net[freenode.freenode.net/6667], running version hyperion-1.0.2 [04:03:06] [I have joined #peak] [04:03:06] ** kornbluth.freenode.net set the topic to PEAK mailing list is back up [04:58:44] ** vlado has joined us [05:13:51] ** jack-e has joined us [05:19:09] * jack-e is gone (11:19AM): (AutoGone - 5 mins) [05:45:04] ** jack-e has left IRC (Read error: 110 (Connection timed out)) [05:58:04] ** jack-e has joined us [06:53:43] ** jack-e has left IRC (Read error: 110 (Connection timed out)) [07:39:45] ** jack-e has joined us [08:13:18] ** erikrose has joined us [08:13:44] ** jack-e has left IRC (Read error: 113 (No route to host)) [08:14:34] ** jack-e has joined us [08:48:52] ** jack-e has left IRC ("This computer has gone to sleep") [09:15:10] ** jack-e has joined us [09:24:02] ** jack-e has left us [10:14:21] ** vlado has left IRC ("Leaving") [11:30:14] [Global Notice] Hi all. John Reeves Hall, a community hacker mentioned here previously, passed away on September 17. ( http://overcode.yak.net/ ) He'll be missed. I know he would want to thank all of you who contributed to his drive for the American Cancer Society. [13:12:27] ** sprout has joined us [13:30:44] ** pje has joined us [13:31:00] erikrose, to answer your DM question from a few days ago... [13:31:09] Elements aren't supposed to have parent components [13:31:34] Model elements exist in a platonic sphere unattached to earthly component hierarchies. ;) [13:32:20] Otherwise, they'd be coupled to their application environment, and they're supposed to be usable with any application environment. [13:32:37] Services need to depend on elements, not the other way 'round. [13:36:03] *reads* [13:38:38] In my case, I have an Element with a DerivedFeature, and the DerviedFeature has to go ask something of a DM. How is it to Obtain a DM without a component hierarchy? Or can you suggest a better way to structure this? [13:39:21] If the derived feature relies on having a DM, then how can it work if the object isn't attached to a DM? [13:39:39] A different DM, not one that stores this Element. [13:40:33] Then provide the needed feature via that element's DM. [13:40:51] either by having a binding to expose the DM, or a binding to expose that method of that DM. [13:42:22] This feature used to be stored by its element's DM, but now the DB has changed, and a different DM takes care of it. That's why this feature changed to a DerivedFeature. [13:43:06] What do you mean by "a binding to expose the DM, or a binding to expose that method of that DM"? [13:43:21] And btw, how did you fare in the hurricane? [13:45:32] And actually, I pretty much worked around this problem; I just quit using Elements except where they're going to be persistent. [13:45:58] A more interesting question is how to do circular references in Elements. [13:46:12] Like... [13:46:19] class Person(model.Element): [13:46:30] class parent(model.Attribute): [13:46:36] referencedType = Person [13:46:44] which, of course, doesn't compile [13:49:41] referencedType = "Person" [13:49:49] Ah. :-) Thanks! [13:50:14] the binding would be something like: [13:50:18] class ThisDM: [13:50:33] otherDM = binding.Obtain(...key to find the other DM) [13:50:41] Yep, I did that much. [13:51:06] But you can also do [13:51:47] theMethodThatUsedToBeHere = binding.Obtain([keyForotherDM,'method_name']) [13:51:51] Or at least I think you can. [13:52:15] That's a pretty cool idea. [13:52:55] I wonder how the oid of whatever Element instance you call it on would percolate to the other DM, in that latter case. [13:54:16] Actually, that doesn't work. [13:54:32] Ah. [13:54:41] You have to do a two step, of otherDM = whatever, and method = binding.Delegate('otherDM') [13:55:00] Sequences like that would just return you a sequence of the DM and the name. :) [13:55:11] It's been too long since I've done any serious work with PEAK. :( [13:55:37] And the oid gets there magically? [13:55:50] huh? [13:55:58] It wouldn't, you'd pass in the object. [13:56:08] Oh yeah [13:56:12] Python. :-) [13:56:48] Darn, I wonder if that would work. [13:57:20] I can actually describe my original question better now that you've pasted that "otherDM = binding.Obtain..." code out there. [13:57:55] My trouble was that I was making an Element, apart from any DM, just to use within RAM for a bit. [13:59:06] I'd stuck a foreign key into it--one I knew to exist--but the Element couldn't go Obtain the DM for that foreign key and pull any data because it wasn't hooked into the component hierarchy. [13:59:23] And I couldn't hook it into the hierarchy without putting it in custody of a DM. [13:59:32] Was I insane to want to use an Element like that? [14:04:04] Probably not. [14:04:18] That makes me feel better. :-) [14:04:52] Although I say that because I want peak.schema to have an "in-memory" DM that works with anything. [14:05:17] Well, peak.schema should solve all sorts of problems, [14:05:36] Yep. At my current rate of progress, I should deliver it in, oh, 2007? :) [14:05:39] among them, that I spent 10 hours over the last few days just fighting to get an O-R mapper to work. ;-) [14:06:34] On the other hand, since I anticipate that future PEAK will rely heavily on dynamic variables and the 'with:' statement, that should be right about on time for Python 2.5 being the typical version in use. :) [14:06:34] That means I have 2 more years to get sqldm right. :-) [14:07:15] I've recently realized that an awful lot of stuff in PEAK is effectively there to substitute for the lack of dynamic variables in Python. [14:07:17] What's a dynamic var? Is it described in the same PEP as "with"? [14:07:29] No, it's a Lisp thing. (isn't everything?) [14:07:44] It's a variable whose value depends on calling context. [14:07:53] That's the whole point of PEAK. [14:07:59] context, context, context [14:08:05] Well, the PEAK core, anyway. [14:08:09] right [14:08:14] Or more specifically, binding and config. [14:08:45] Experience has shown that the majority of components tend to share a fixed set of context components for their configuration and services. [14:09:04] I'm continually fascinated that you prefer Python to Lisp. [14:09:12] Which means that most of PEAK's acrobatics to support contextually defining them are overkill - but necessary. [14:09:32] Because Lisp is tedious and more-obfuscational-than-thou. [14:09:35] You mean that things, once bound, tend to stay bound? [14:09:55] No, I mean that within a "service area" (PEAK term), most shared components are globally shared. [14:09:57] Or that config info tends to be global? [14:10:13] Ah. Yes, that's the case in my project so far. [14:10:15] Yeah - I'm saying that the default case for simple things is that everything is a global singleton. [14:10:42] PEAK exists to deal with the fact that when it *isn't*, you really need it to not be. :) [14:10:50] One place the contextual lookups really shine, though, is in testing. [14:10:56] Yeah. [14:11:10] However, it's a lot of stuff to learn in order to deal with those non-singleton cases. [14:11:22] What dynamic vars allow you to do, is to change the dynamic var in the test code. [14:11:27] Heck, and composition of multiple projects, which is really the same problem: stubbing and composition. [14:11:37] Or in the multi-application server that's calling different apps with their own configs. [14:11:38] Etc. [14:11:48] It sounds very much like component lookup. [14:11:58] Yeah, except that it's based on the call stack. [14:12:13] It's like having a try/finally to save and restore a global variable, that's thread-local. [14:12:16] rather than (usually) the containment hierarchy [14:12:23] right. [14:12:39] Very interesting. [14:12:59] I've actually implemented a prototype, but I haven't used it for anything yet. [14:13:18] Mainly because it requires try/finally or decorators to use properly, if you don't have a "with" statement. [14:13:46] Ohhhh, I remember the "with" statement now. [14:13:59] I don't know if it will actually deal well with cases that PEAK handles well now. [14:14:13] I do know that it will deal extremely well with cases that PEAK *doesn't* handle well now. [14:14:36] Like web application context (current user, current skin, locale, etc.) and multiple simultaneous transactions. [14:15:03] Because those are cases where you really *want* lookups to be call-stack based. [14:15:25] Like if a main transaction fails, and then you want to send an email using a transactional mail sender. [14:15:32] (to report the error) [14:15:50] You have to create a whole new service area right now to replace the transaction. [14:15:54] That doesn't work under PEAK? [14:16:00] !! [14:16:02] Sure it does, it's just a pain. [14:16:35] Hmmp. [14:16:42] As I said, you have to either create another service area for the second transaction, or explicitly create a transaction component and a mail sending component bound to that other transaction component. [14:17:10] Whereas if the current transaction were a dynamic variable, you'd just do something like [14:17:11] I was thinking in the direction of the latte.r [14:17:20] with transaction(newTransactionObject): [14:17:24] # do it [14:18:06] Similarly, peak.web right now has a rather clunky component that has to track a whole bunch of stuff about the current request [14:18:18] Like the user, skin, locale, etc. [14:18:42] And it's not orthogonally extensible; if you want to add something like 'shopping_cart', you have to subclass it. [14:19:07] But peak.web handles web publishing as nested function calls down to the object that's being rendered, so you could just use dynamic variables for all that stuff. [14:19:18] And it's infinitely extensible, just define new dynamic variables. [14:19:44] Why jam all the current request's stuff into one component? [14:19:47] For that matter, you could use it to do things like define menus, navigation, etc. [14:19:54] Why not offer each chunk as a separate interface? [14:20:09] Then how would you get to them? [14:20:12] Then you can extend it in whatever orthogonal directions you want. [14:20:27] Things would ask for Obtain(IShoppingCart). [14:21:17] No, they can't. [14:21:37] (Your shopping cart would, in turn, probably Obtain an IRequest to grab the form data to figure out how to populate itself.) [14:21:37] Obtain() would bind once and only once. [14:21:57] You can't obtain those things - they belong to the current request, not to the application as a whole. [14:22:27] Oh, so you don't make a new object for a new request? [14:22:38] A new request object, sure. [14:22:47] But you don't recreate all the other service objects. [14:23:08] i.e., you don't want the whole app to have each new request as its parent component. :) [14:23:29] Or rather, for this kind of data, you *do*, which is why dynamic vars are better. [14:23:44] And vastly easier to use - just refer to the variable as if it were a global. [14:24:24] Basically, inheritence of vars from all calling scopes? [14:24:31] Not exactly. [14:24:39] somevar = context.Variable("somevar") [14:24:39] Certain vars? [14:24:48] somevar.push(value) [14:24:51] somevar.get() [14:24:55] somevar.pop() [14:25:15] Technically they're objects, not variables. [14:25:29] Feels elegant. [14:25:37] However, that's the primitive interface. I was planning to add a context.Service() that's a proxy [14:25:45] So that if you do tranaction = context.Service() [14:25:50] er, transaction [14:26:03] then you can set the transaction via 'with transaction(obj):' [14:26:26] and referring to transaction.foo will delegate to transaction.get().foo [14:27:10] So it's actually even more elegant if your variable is an object, rather than some configuration value. [14:27:43] Hmm, yip. [14:27:46] My work at OSAF on Chandler has made me think about this a lot, as there is a lot of stuff in Chandler with context variables that get passed around a lot. [14:28:15] And there's no PEAK-style parent components to get things from. [14:28:27] So I've had to think about some alternative solutions. [14:30:00] Anyway, it's an utterly natural and powerful way to deal with the context problem for most things, and its lookups are faster than PEAK's initial lookups [14:30:02] Have you come up with anything lightweight enough to use for Chandler? [14:30:30] Well, my current dynamic vars implementation is less than 200 lines [14:30:39] That works. :-) [14:30:42] But as I said, it really needs the "with:" statement to be natural. [14:30:58] One of the other requirements is to work right with Twisted. [14:31:06] Thread-local variables don't work for Twisted at all. [14:31:39] So, there's a way to get a cheap copy-on-write snapshot of *all* dynamic vars, and also a cheap way to swap back in a snapshot. [14:33:00] Very nice. :-) [14:33:40] In fact, context swaps are about 2uS on my PC [14:34:06] It's slower if you're changing the contents of the contexts; the next write is slowed down by the need to copy. [14:35:37] Dynamic variable sets (in the non-copy case) and gets are also about 2uS, so it's a pretty cheap mechanism, even though it's pure Python at the moment. [14:36:20] The main hurdle I see for PEAK components is the fact that you may need to change many vars as you pass through a particular component. [14:37:24] On the other hand, such uses are really *not* that common; few components use 'offerAs', and few are Configurable instances. [14:37:44] (the two ways in which components now would usually affect the configuration of their children) [14:38:02] Are you considering trying to reimplement component lookup using dynamic vars? [14:38:15] Yeah. [14:38:48] At first I thought you wouldn't be able to do it, but I suppose you could hook, what, one of those __getattribute__ things to do your pushing and popping on method call? [14:38:52] Although I was also thinking that you could just save a snapshot of the context at the time the object was created, and then do all your binding lookups using that context. [14:39:19] No, I was thinking we'd just move from using properties and interfaces to dynamic variables. [14:39:20] Is there a generic __I'mCallingSomethingOnThisObject__ hook? [14:39:30] O. [14:39:56] If you think about it, all of them are just symbols that live someplace. [14:40:11] Well, a property is just a name, it doesn't have to exist. [14:40:53] Though I like to manifest them as symbols if I use them in more than one place [14:40:59] Yep. [14:41:12] There are dynamic property namespaces, though, and it might not be a good idea to lose those. [14:41:33] On the other hand, I can envision a subclass of context.Variable that would allow dynamic children. [14:41:34] I don't know those. [14:41:47] well, there's environ.* [14:41:51] Ah. [14:41:53] I do know that. [14:41:57] That's the first one that comes to mind. [14:42:02] I see what you mean now. [14:42:08] But you could do something like [14:42:32] environ = context.Property() [14:42:51] if Property() had a __getattr__ so you could do environ.FOO and thus get to a sub-variable. [14:42:57] Well, if your dynamic vars are objects, you're all set. [14:42:58] I haven't thought any of those ideas out at all. [14:43:46] Oh, that reminds me! Do you have time for one more PEAK question? [14:43:53] Should be an easy one, I hope. [14:43:58] One more, and then I should really get back to work. [14:44:04] Me too. :-) [14:44:07] I didn't mean to end up doing design brainstorming. :) [14:44:15] I love rubberducking into chat rooms. :_) [14:44:33] I had to do this inside an Element of mine, because it was a forward ref: [14:44:33] baseyDM = binding.Obtain(storage.DMFor("semreg.model.ProposalBasedOnSeminar")) [14:45:02] um, for DMFor you really need the object. [14:45:07] er, class I mean. [14:45:10] And then I did the bulletins-esque hack of this at the bottom of my model.py: [14:45:11] ProposalBasedOnSeminarDMConfigKey = storage.DMFor("semreg.model.ProposalBasedOnSeminar") [14:45:23] Yeah, exactly my [point]. [14:45:25] The string ain't gonna work. [14:45:42] do this: [14:45:47] It works, but you can't Obtain(DMFor(ProposalBasedOnSeminar)) later on. [14:46:06] pbosClass = binding.Make(lambda: importString("....")) [14:46:24] baseyDM = binding.Obtain(binding.Indirect("pbosClass")) [14:46:35] hm, or is it config.Indirect? crap, I forget. [14:46:48] PHew. Thanks. Would've taken me a million years to come up with that. [14:47:21] ah, it's naming.Indirect [14:47:30] Gotcha. [14:47:36] Thanks for reading the logs and answering my questions. :-) [14:47:41] see "peak help naming.Indirect" [14:48:11] Boy, Python startup costs are horrendous. [14:48:14] Personally, I never use bindings on Elements, so I never ran into that problem. [14:48:34] It does seem a problematic area. [14:48:53] I consider such things the repsonsibility of that class' DM to provide. [14:49:08] Because again, you're encoding application dependency into your domain model that way. [14:49:13] Anyway, I better run. [14:49:24] Thx, I'll consider that. [14:49:26] See you later! [14:49:35] ** pje has left us [22:01:10] ** sprout has left IRC ("Snak 5.0 IRC For Mac - http://www.snak.com")