> El 18 sept 2019, a las 15:05, Alistair Grant <akgrant0...@gmail.com> escribió: >>> >>> TraitedMetaclass stores methods in two different instance variables: >>> >>> - methodDict (inherited from Behavior) >>> - localMethods >>> >>> And the same method can be different in each dictionary. >> >> Yes, trais actually work by flattening the methods of traits into the user >> class. >> - localMethods defines the methods actually defined in the class >> - methodDict has the raw low-level flattened version the VM uses for the >> lookup > > So methodDict and localMethods should always contain the same instance > of CompiledMethod for a given selector, right?
Yes it should. >> >> We are tracking this, it seems you have found two bugs :D. >> >> 1st bug) Calypso and the senders/implementors should be in sync and show the >> same (always the local methods for traited classes) > > From what you've written above (and below), the two dictionaries > should always have the same instance of CompiledMethod so it shouldn't > matter where it comes from. Just for the record, yes and no :). With the new trait implementation, we have actually a modular MOP. All classes (whether traited or not) understand: - #localMethods => returning the methods as they are implemented in the class - #methods => returning the actual methods executed by the VM For normal classes, #localMethods is defined as follows: localMethods ^ self methods And methods understand - #origin => where that method is actually defined For example, in a traited class a lookup should be done in the trait composition, otherwise is the class where the method is installed. Tools should work against #localMethods and #origin, which hide how the actual implementation stores the things :). We already had in the past a lot of tools that hardcoded/duplicated the internals of Traits for example. The other advantage of this is that, imagine you want to extend Pharo with: - multimethods => localMethods will have a single multi-method implementation, and the implementation side will contain maybe an expanded version with type checks or even one method per type combination - optional parameters => a single method with many parameters should be expanded to many methods with less parameters + default values The idea is that tools do not hardcode the implementation details of these extensions, so the public API is #localMethods and #origin :) Of course, one could design a tool showing #methods, which will show the low-level view of classes. > > >> Moreover, (I’m confirming this with Pablo on line right now) the local >> methods dictionary should be just a subset of the method dictionary. >> In other words, the invariant is that methods in localMethods should be >> included in the methoddict, they should not differ as they are differing >> there. >> >> 2nd bug) UFFI? seems to be messing with this invariant :) >> >> When a UFFI binding is executed for the very first time, the ffi call >> definition gets compiled and a new compiled method is generated performing >> that call. >> When a session finishes (the image stops/restarts) ffi bindings are reset >> (because their compilation is platform dependent). >> >> What we are seeing there is that somehow UFFI managed to reset a binding >> method and put a wrong one in the local method >> >> I’ve seen this bug before but never got the insight of what was producing it >> (neither put too much time to dig on it either :P). >> Another possibility is that the culprit are the LibGit bindings, which >> extend UFFI binding compilation. > > I haven't looked at this, but what I saw was the localMethods was > correct and the methodDict was old: > > Redefine a base system method (LGitCommit>>commit_author:) using an > extension method resulted in methodDict containing the original > definition and the localMethods containing the overridden method. > What I would expect is that the overridden method is what is used > everywhere. > > I'm not sure if this is related to UFFI or not. Pablo tracked this down to possibly FFIMethodRegistry >> removeMethod: aMethod aMethod methodClass methodDict at: aMethod selector put: (aMethod propertyValueAt: #ffiNonCompiledMethod)