On Mar 29, 2006, at 5:16 PM, Lukas Renggli wrote:
I think the block constructs can be used in may cases to achieve the same goal as annotions. Looking at all the should: and shouldnt: construct can give you an idea.
[snip]
I don't understand a single word in your e-mail. What are you talking about? What are you using blocks for? What is the purpose of #test:, #should:, #shouldnt: ...?
Not a single word. Bummer! ;-)
Can you elaborate what you mean?
Sure. Let me give you three examples.
==Logging== Let's stick to the canonical example for aspects: Logging. You could describe this with an annotation "Log this".
But on the other hand you could also wrap the code you want to log with a
Bar >> foo self log:[body of foo]
construction. Whether your class browser displays you the actual source or filters out the log: could depend on some setting of your browser. If it filters, it could at least provide you with some indicator close to the method that logging is on. Yes, I mean it, the possible filter options of our class browser for code is highly underestimated currently... ;-)
Implementing Object >> log: aBlock could do all the tricks you need for logging, no?
How would I manage all the aspects? Guess I tried to get away with some stupid method category naming convention a la Monticello, as I don't know anything better. Just some method category name with an "aspects" or maybe even aspect dependent name like "aspects-loggingOut" or whatever. This is where I would store the log: method of course.
Having that in place one could easily iterate over all classes, collect the appropriate "aspects" (with all what comes first and last problems, one would need a decent tool for that) and apply them or remove them.
==Tweak Events== Let me try it with tweak:
MyMorph >> makeYellow <on: mouseDown> color := Color yellow.
this method should not be called by some other method, but only when the mouse is pressed. Another way of tagging this, could be to write sth. like
MyMorph >> makeYellow self onMouseDown: [color := Color yellow]
and
Object(Tweak-MouseEvents) >> onMouseDown: [aBlock] self precondition: [detect if mouse is really pressed]. ^aBlock value
Again, some mechanism could be installed to both put that "aspects" in and out of the code, and also manage the mousedown scheduler, to call all interested parties when appropriate.
Or just switch it off globally at runtime like a possible solution for Object >> assert: aBlock (to be found in our scg VW library) Object >> assert: aBlock AssertionsOn ifTrue: [aBlock value]
==Testing== "Unit test" is a funny name, as nobody seems to agree or make explicit what the unit under test is. Having pursued the endeavor of categorizing all unit tests of Squeak 3.7 we came to the conclusion that most of the tests written in SUnit do focus one a single method as unit under test. This is no wonder as the naming convention of SUnit makes that approach natural. (There are certainly others and better ones, the best ones I find those, that check, if the inverse function applied to the function applied to a parameter delivers the parameter in the end.)
All unit tests are decomposable into examples, which focus on single methods (I call these guys "method examples"), and tests, which focus on single methods. ("method tests"). So method examples and method tests are basically the building blocks for our test framework.
It would be nice to navigate between tests and unit under tests, which is futile if nobody makes that relationship explicit, and this is usually our main job as object-oriented developers. Romain Robbes did a nice first shot navigating between tests and code, but here every method in a test is basically treated to be somehow tested/exemplified.
On the other hand some philosophers like Wittgenstein or linguists like Lakoff would say that there are better and worse examples for a given concept - you would not explain the concept of a bird to a child with a penguin first...
So how do I make explicit which "animal" I am really interested in a test?
Again, just use the block concept. FooTest >> testBar "Our tool is actually able to detect that this is an InverseTest" "..someSetupCode for blaBla." (...) self test: [aResult := blaBla bar inverseBar] "All methods called in the test block are methods under test" "some assertions to make this a test and not a mere example" self assert: (aResult = blaBla) Java folks would have to denote the method under test using annotations, we don't have to, having our wonderful universal acid of lambda calculus.
I hope these three examples clarify my sympathy for using blocks instead of annotations more than it confuses, as I bring in my idea of examples too. ;-) Shouldn't have given the examples of should: and shouldnt: as they might not have been the best ones.
Cheers,
Markus