On 2007.12.07., at 13:43, Jochen Theodorou wrote:
> Attila Szegedi schrieb: >> >> Yup, it's all implemented. See >> >> <http://dynalang.svn.sourceforge.net/viewvc/dynalang/trunk/dynalang/src/org/dynalang/mop/beans/ >>> >> >> OverloadedDynamicMethod is the class you're looking for. It further >> relies on both OverloadedFixArgMethod and OverloadedVarArgMethod, >> which implement the actual nitty-gritty details for fixedarg >> overloads >> and vararg overloads of a method, respectively. > > I must say I don't get it fully yet.. If I look at > OverloadedMethodUtilities#isMoreSpecific then I see two classes > involved > and this tells if one is more specific than the other.. so I would > have > expected to find a usage where you try to sort a set ci into for > example c1<c2<c3 with c3 being the call argument class and c11/c2 > being > classes from two available method.. but I don't find a place where > this > happens. Instead I think I you just compare the method parameters to > find the most specific method.. but not the method "most fitting" the > call... So coming back to my c1,c2,c3 this is all fine if you assume > that c2<c3 and c1<c3, because the most specific one will then be the > "most fitting" one too. But I don't find the place where the filtering > happens. My algorithm follows the JLS 3rd edition chapter 15.12 as closely as possible (considering JLS uses a compile-time resolution against statically computed types of parameter expressions at call site, and we're doing runtime resolution against actual types of parameter expressions at runtime). <http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12 > With that in mind I'll walk you through the code for fixarg resolution. line 100 of OverloadedFixArgMethod says: objMember = argTypes.getMostSpecific(members); "argTypes" is is an instanceof my ClassString class representing the actual arguments of the parameters at the call site. It is passed a list of all overloads (members) to select the most specific. getMostSpecific() will do the following: 1. find all methods applicable to the argument types (as per JLS 15.12.2) in its getApplicables() method. We do both applicability by subtyping (JLS 15.12.2.2) and by method invocation conversion (JLS 15.12.2.3) in a single pass, which is greatly helped by the fact that we can not pass primitive values to our dynamically invoked methods anyway, they're already wrapped into their object counterparts :-) 2. then we try to find all maximally specific methods among the applicables (methods have a partial "is more specific" ordering based on their argument types, see JLS 15.12.2.5). In case there's exactly one maximal element, it is by definition of partial ordering the most specific element, and it'll be selected to be invoked. If there's more than one maximal element, we have an ambiguity and an exception needs to be thrown. The "most specific method among all applicable methods for given types" is a formal expression of "method most fitting the call". There's one additional hurdle though. With dynamic languages, there's the question of what's the assumed Java type of the arguments used for the call, right? I maintain a map of target types, one per number of arguments for the overloaded method. I.e. if you have two 2-arg overloads: foo(java.lang.String, java.util.List) foo(java.lang.String, java.util.Set) then the target types for argument conversion for all 2-arg overloads of foo will be computed to be [java.lang.String, java.util.Collection]. When the method is dynamically invoked, the passed callProtocol will be asked to provide a representation of the first method as if it were a String, and to provide a representation of the second method as if it were a Collection. Hopefully in the real invocation, the second argument will already be either a list or a set, so it will be returned unchanged. If it is however a collection that is neither a list nor a set, then no method will be invoked and an error will be thrown. In case your overloads are really convoluted: foo(java.lang.String, boolean) foo(boolean, java.lang.String) the the target types become [java.lang.Object, java.lang.Object]. This basically means that the arguments will not be converted up front (CallProtocol.representAs() invoked with java.lang.Object as target type is expected to return its object argument unchanged). Note that you can still invoke foo() with argument expressions that evaluate to java.lang.String and java.lang.Boolean, i.e. both foo("", false) and foo(false, "") will work. But the overloaded method resolver won't be able to automatically coerce other types automatically in this case. I.e. would a JavaScript invocation of foo(0, 0) be interpreted as foo("0", false) or foo(false, "0")? It's undecidable. All in all, it does the best job possible with most overloads, and if your overloads create a _very_ ambiguous situation, you'll just need explicit language support for casting the parameter types. > ah yes, one more thing.. isn't your marshalTypes and selectorCache in > OverloadedFixArgMethod a good place for memory wholes? A memory leak? marshalTypes certainly isn't. It might retain Class objects used in argument types of the overloaded method, but those can't be unloaded anyway until the class that the method itself belongs could be unloaded. OTOH, selectorCache is, as it might retain a Class object that is a subclass of argument types of the method, loaded through a different class loader. I'd need a "WeakClassString" class that weakly references its Class objects. That said, the "mops" map in BeansMetaobjectProtocol is the one that should really be rewritten using weak references for keys and soft references for MOP objects (and then when the class gets GCed, all associated Overloaded*ArgMethod objects will get GCed as well, resulting in marsalTypes going away). There are other places in the code that accumulate class references, i.e. ClassBasedMetaobjectProtocolImpl. I'm aware of these issues, and intend to address them. Caching information pertaining to Class objects is tricky business as it's hard to get right - I've implemented few systems already in the past. Most notably, you usually can't use a map with both weak key and weak value refs, as that way the value gets GCed too often and the cache miss ratio is too high, mostly defeating the purpose. Using a weak key ref and soft value ref is better in cache hit terms, but if your soft-cached value holds a direct or indirect strong ref to the key object (and it does if the value is a method or holds a method, and key is the class declaring said method), then you've essentially promoted the weakly-referenced key object to soft reachability instead of weak reachability once its strong references are gone. This'll postpone its GC and subsequent unloading of its class loader, but is fortunately usually okay with regard to memory management semantics otherwise, even if it can cause higher temporary memory pressure (until soft references are cleared). As usual, the lunch is not free, but if implemented properly it won't lead to an OOME and all class garbage will get GCed even if with a bit of an additional delay. Anyway, these are issues I'm aware of, and intend to take care of. In the first pass, I'd like to see the API and the implementation stabilize without additional complexity of memory management issues. Then when we're happy with it, I'll apply the required dosage of weak and soft referencing where necessary :-) > bye blackdrag > > > -- > Jochen "blackdrag" Theodorou > The Groovy Project Tech Lead (http://groovy.codehaus.org) > http://blackdragsview.blogspot.com/ > http://www.g2one.com/ > Attila. -- home: http://www.szegedi.org weblog: http://constc.blogspot.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "JVM Languages" 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/jvm-languages?hl=en -~----------~----~----~----~------~----~------~--~---
