links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Indentifying virtual categories
Last updated at 5:55 pm UTC on 1 October 2005

How can we ask and answer: Is this method required by this trait/class?

What has to be done to set things up in the first place, so this question can be answered? First we look at the RequiresTestCase and RequiresOriginalTestCase. RequiresOriginalTestCasehas only one method a class side method which sends this message:
updateRequiredStatusFor: selector in: aClass 
		aClass updateRequiredStatusFor: selector inSubclasses: self systemNavigation allClasses 
So apparently aClass is able to update the requiredStatus for a selector in some subset of its subClasses. RequireCalculatorTestCase also implements this selector on the classSide:
updateRequiredStatusFor: selector in: aClass 
	RequiresCalculator onSelector: selector fromClass: aClass
So apparently RequiresCalculator is able to update the requiredStatus for a selector in aClass. Finally, RequiresTestCase implements this as an instanceMethod just like the cS RCTC
updateRequiredStatusFor: selector in: aClass
	self class updateRequiredStatusFor: selector in: aClass
So aClass can also update the requiredStatus for a selector in a single case.

This methodSigniture (updateRequiredStatusFor:in: ) is invoked by 5 methods in RequiresTestCase and once in RequiresCalculortTestCase. Let's look at the 5 methods in RTC first since they would appear to be "higher level" eg. tell us more about how to invoke and less about how to do the calculation. RequiresTestCase has the concepts of one and two level requires, and unalignedSuperSends and thinks these are worth testing. It also implements a method class requirments. Each test invokes the above method and then makes assertions about what requirements returns. This doesnt tell us too much. Lets look at
	^ self sendCaches requirements
So a class or trait knows about its requirements via its sendCaches
	^ requirements isNil
		ifTrue: [self newRequirementsObject]
		ifFalse: [requirements].
And the SendCaches are lazyily initialized with an empty set. So what do we need to do update it? How do we say, "find our what all your required methods are?"

[SendCaches also implements selfSendersOf: So this is likely useful for all the virtual categories.]

So let's look at all the senders of PureBehavior>>requirments. This doesn't seem like it would really answer the question at hand but maybe we can assure ourselves that the requirments method plays a real role.
	| rscc |
	rscc := RequiredSelectorsChangesCalculator onModificationOf: self withTargets: {self}.
	rscc doWork.
	^self sendCaches requirements.
So, requiredSelectors seems like a first class way to determine what a class's requirements are! On the otherhand, there are no other senders; specifically none unique to Trait.

Not sure where to go next, so let's look implementors and sends of SendCaches>>selfSendersOf: . The SendCaches class comments and methods tell us the this also implents superSenders (but not conflicts or supplies, perhaps these are trivial or local?) But this is just a holder so lets look at all class references. They are instanceside methodes in PureBehavior, Behavior and TraitBehavior. (plus classSide in SendCaches, naturally) TraitBehavior and (Class)Behavior both proved getters for SendCache. Behavior implements
	"Creates an instance of SendCaches, assigns it to the instance variable sendCaches and fills it with all the self-sends class-sends and super-sends that occur in methods defined in this class (or by used traits)."

	| localSendCache info |
	localSendCache := SendCaches newFor: self. 
	self selectorsAndMethodsDo: 
			[:sender :m | 
			info := (SendInfo on: m) collectSends.
			info selfSentSelectors 
				do: [:sentSelector | localSendCache addSelfSender: sender of: sentSelector].
			info superSentSelectors 
				do: [:sentSelector | localSendCache addSuperSender: sender of: sentSelector].
			info classSentSelectors 
				do: [:sentSelector | localSendCache addClassSender: sender of: sentSelector]].
So this is where the work gets done. But again, only for Class not for Trait. [Are we sure that trait is not an instance or subclass of Behavior? We double check and see that it is not a subclass. This whole metaclass is an instance of ....cycle is still too confussing.]
Interestingly enough PureBehavior implements
	SendCaches newFor: self

So lets take a direct look at TraitBehavior. And what do you know here's what we find.
	| sss |
	sss := self selfSentSelectorsFromSelectors: self allSelectors.
	^sss copyWithoutAll: self allSelectors.
So we're thinking that TraitBehavior can calcuate requiredSelectors without a sendCache. And thinking about it this makes sense. After all traits do not have inheritance.
	| sss aTrait |
	sss := self selfSentSelectorsInTrait: aTrait.
	^sss copyWithoutAll: aTrait allSelectors.
(A side note that in 3.02 do a senders on this method results in a MNU)

So what have we learned so far? sending the message requiredSelectors to a class or trait will cause the calculation of the desired result without any further to do on our part. Let's test it on an abstract classs which should have a nonempyt set as a result
Collection requiredSelectors ==> an IdentitySet(#add: #atRandom: #copyUniClassWith: #slotInfoButtonHitFor:inViewer: #readFrom: #remove:ifAbsent: #do: #step)
Yes. and an concrete classs, which should have an empty set as a result
True requiredSelectors ==> an IdentitySet(#slotInfoButtonHitFor:inViewer: #readFrom: #adaptToNumber:andSend: #step)
Suprising but we suspect this is traits telling us something about our concept of a nonabstract class. and an nonAbstract classs, Lets try it on a trait
TCompilingBehavior requiredSelectors ==> an IdentitySet(#instVarNames #methodDict #canUnderstand: #methodDict: #lookupSelector: #error: #environment)
TEColor requiredSelectors ==> an IdentitySet()

How can we identifiy the next virtual category: supplies and supplies/overrides.

Looking in MethodFinder for suppy supplies supplied produces nothing very intersting. So go back to looking at Traits-Tests to see if we see anything.
[Notice ClassTraitTest>>testUsers should come back to. Notice PureBehaviorTest>>testLocalSelectors should come back to ]
Looks like this functionality isn't developed. Go back and read the papers.

On the otherhand override finds us bunch of stuff on overrides Picking though the list we find the following that might be of interest.
	| classes |
	classes := OrderedCollection new.
	self addOverridersOf: self selector inClass: self theClass to: classes.
	^ classes collect: [:ea | OBMethodNode on: selector inClass: ea] 
So an OBMN can return a collection of OBMN's that override itself (?) and looks to be used to implement inheritance. But that's it and again we are not to much the wiser.

How can we ask is this method superSent by this trait/class?

Based on the required investstigation, we think that a class and trait can answer this question without any set up by us. But let's just look and see if the test cases tell us anything. We see no interesting TestCase begining with or Super ... However, pooking around in Traits-Tests, we find in PureBehaviorTest>>testSuperSends
Which asserts and denys certain methods, but not sure this tells us much. [In poking around we also see that TraitMethodDescriptionTest has a method testConflictingCategories which we should consider when we get to that category.]

From our prior reseach we know there is a method called selfSendersOf: So we use the MethodFinder to search for selfSenders and confirm that SendCache can answer selfSendersOf: aSelector (and superSendersOf:) And that Behavior and RequiresCalculator send this message. But the chain looks pretty daunting so we stop. But maybe we already know what we need. Let's try
Collection sendCaches superSenders ==> an IdentityDictionary(#printOn:->#(#printNameOn:) )
True sendCaches selfSenders ==> nil
For the class it works but not for traits: TCompilingBehavior sendCaches selfSenders gives us a message not understood. So finding class superSenders works pretty much the same as for requiredSelectors (except class is not polymorphic on this methods). However for traits there isnt a way to ask the question. Maybe the question doesn't make sense? Messages are not sent to a trait they are sent to a class..... But no the papers clearly refer to supplies for traits.

How can we find all the category of methods that are conflicts?

We found out previously that TraitMethodDescriptionTest has a method testConflictingCategories. Looking at it doesn't provide any great insights but it does show that creating traits can lead to
  (trait organization categoryOfElement: selector) = ClassOrganizer ambiguous.
This sugests one way of identifying conflicting methods. Then we notice a more direct test
However, this just shows that conficting methods simply raise an error. This really doesn't get us very far so we do a search for conflict in MethodFinder which yields a bunch of methods. Our image has MC and Kabunga, both of which deal with conflicting defintions of methods in packages, which is not what we care about so we look for conflicts defined in Behavior or some such thing.
CompiledMethod class>>conflictMarker
	^ #traitConflict
Not too intersting but its sent by CompiledMethod>>isConflict. So it looks like we can ask a method (if not a trait/class) if it is a conflict. TraitMethodDescription>>conflictMethod appears to create a method when there are conflicting definitions. There are a lot more methods to look at but bottom line is: you have to ask the method not the trait or class if it is a conflict.


Interesting we are seeing a very inconsistent interface here.
Category How class method category is identifiable
requiredaClass requiredSelectors ==> an IdentitySet.
overriden ????
supperSending aClass sendCaches selfSenders ==> an IdentityDictionary
Category How trait method category is identifiable
requiredaTrait requiredSelectors ==> an IdentitySet.
overriden ????
supperSending aClass sendCaches selfSenders ==> an IdentityDictionary
conflict aCompiledMethod isConflict==> aBoolean