This is why posting this stuff pays off. Somebody comes back with a cluestick in hand and helps out. :-)
On Thu, 2006-08-03 at 21:01 +0800, Russell Keith-Magee wrote: > > On 8/3/06, Malcolm Tredinnick <[EMAIL PROTECTED]> wrote: [...] > > (2) If a class has derived classes, you can access those via > attributes > on the class. > > Obviously, I'd still prefer an _actual_ duck, but this seems a > reasonable alternative in an duckless world. I could subclass everything from Duck if you like. Poor man's duck typing. :-) > I assume p.restaurant will return a fully functioning Restaurant > instance? i.e., p.restaurant is really just a descriptor returning > Restaurant.objects.get(pk=p.id) ? If so, +1 Yes, that's the idea. I can't see any reason not to do this, since the database work is the same. > (2) Not sure if we should go for > Place.restaurant.italianrestaurant or just make > Place.italianrestaurant work directly (I prefer the > latter, but > neither is a showstopper). > > +1 to the latter syntax. When operating on an instance, the exact > heirarchy is irrelevant. The only problem I can see here is in dealing > with repeated names in the heirarchy, to which the only solution I can > see is a model validation error. I haven't worked out the API for specifying the attribute here, but that's minor. Basically, we need something on the sub-class to say "use this attribute name in the parent(s)". An attribute in the Meta class is probably the solution, I guess. We already need to have an attribute for specifying database column(s) back to the parent(s). Failure to set the attribute and getting a name clash is a validation error. [...] > hrm... -0. I would have thought that a single isinstance() would be a > better idea than a range of is_XXX() functions. e.g., > > p.isinstance(Restaurant) > > > (possibly using strings rather than/in addition to model modules if > preferred or the implementation requries). This keeps the API small > and simple, requires less 'magically appearing' functions which could > potentially clash with user-defined functions, and keeps the API > (reasonably) aligned with Python inheritance API. You might be right, I may be .. (wait! Let's not finish that thought. Billy Joel has the copyright). All your API points are well taken. I'm just being a coward on the implementation side. It's harder that way, but that's not really a reason to avoid doing the Right Thing(tm). > This isn't necessarily an either/or suggestion - both _could_ be > supported (but I would be -1 on having both). If an isinstance() isn't horrible, I would prefer that, for all the reasons you mention. Agree that both is silly. > This approach would also allow for checking multiple baseclasses > simultaneously: > > p.isinstance(Restaurant, BaseballField) > > In itself, this wouldn't be extraordinarily useful; if Restaurant and > BaseballField both had a 'beer_price' attribute, you would still need > to use p.restaurant.beer_price and p.baseballfield.beer_price... but > more on this later Worth doing just to be in sync with how the isinstance() builtin works, if nothing else. Your later points aren't invalid either. > (4) Implementing a "what type am I" function is not > going to > exist initially. > > Not sure about this. I agree that a generic form of this type of > function is inherently expensive. However, the absence of ducks kind > of makes this kind of function a requirement, IMHO. > > To go back to the beer_price example, getting the value of the > beer_price attribute gets a bit messy; it requires nested try/catches, > and some extra effort to avoid code duplication: That is the reason for the is_XXX() (or single isinstance()) methods and why I mentioned performance (and code readability) -- all those try/excepts are going to be ugly and not free in Python cycles. The question for me is whether this is really a use case or not. If beer_price is common, why isn't it in a common base class? The only reason I can think of is that it doesn't have the same type. Which gets kind of interesting when you want to work with it later (although if it has the same "interface" always, that is fine). Kind of the reason I was punting on this was that the end-user (the developer) would be more likely to understand their hierarchy and be able to go to the things they cared about directly. Doing it in code requires more general introspection and iteration over the all the possibilities. On the other hand, your typical hierarchy is going to be a couple of layers deep with a couple of classes, so it's hardly going to kill you. > The multi-input isinstance might be one way to get around this. If > p.isinstance returns the instance of the first class in the provided > list that matches, or None if no class matches, the following would be > possible: > > obj = p.isinstance(Restaurant, BaseballField) > try: > price = obj.beer_price > print "Beer costs", price > except: > print "No beer!" > > isinstance() continues to work like a boolean interrogation, but it > also provides the ability to act as a 'narrowing' method (to use the > CORBA terminology). This provides a restricted 'what type am I' > function; it will only check those types that are provided, rather > than the full list of potential child types. > > I will concede that it isn't immediately obvious that isinstance() > will return anything other than a boolean. I don't have any particular > solution to this, other than providing isinstance() _and_ narrow() - > but the duplicated functionality, sort-of-typed API grates against my > sensibilities. Heh. I end up in "this feels like CORBA" land a lot, too, when I'm thinking about this and trying to work out how to use it. :-) I feel I can live without anything resembling narrow() -- or C++'s dynamic_cast, for those more familiar with that language -- because I'm not convinced there is an important use-case. However, if we leave it out, it does makes accessing the beer_price attribute, wherever it may live a little harder. It's also dangerous for me to be projecting my usages onto the world wide group of developers. I have some experience, but not *that* much. So, you probably have a point. In passing, overriding __getattr__ isn't an ideal solution, either, because it doesn't work well with lazy attribute resolving. I tried for a while to make that work nicely, but never came away happy. (Although, as I write this, it occurs to me that with introspection and caching which models have which fields, we would only examine the "right" tables. Hmmm.) > I will also concede that implementing a narrow method of this sort is > not a major drama, and could be easily written by the end user. > However, it does strike me as a fairly essential component of a > duckless inheritance system (as demonstrated by CORBA requiring a > narrow method due to C++'s class system). My crystal ball forsees > complaints if it is omitted. My crystal ball says the complaints won't stop if it is, though. :-) We're stuck between being explicit, efficient and being almost transparently Python-like. I'm not sure all three goals can be met, so we're discussing where to place the "here be bears" signs. How about this? In the interests of getting the code finished and giving people something to try out, we punt this one initially. It can be added later, as you mention. Unless somebody has a really big brainwave very soon, the main design here can't change too much, so debating whether we have a narrow()-equivalent or not probably distracts from the big picture. My thinking is along the lines of: if narrow() wasn't available, would it be a showstopper for this design? If so, what is the alternative? I think the answer to the first question is "no", so I don't feel too unhappy putting it in the "later" basket for now. Thanks heaps for all the feedback, Russ. Helps a lot. Cheers, Malcolm --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-developers -~----------~----~----~----~------~----~------~--~---
