csrabak@bol.com.br wrote:
Em 14/10/2009 17:11, Alexandre Bergel <alexandre@bergel.eu> escreveu:
In Squeak 3.10 TestCase >> assert: aBooleanOrBlock Squeak 3.8, Dolphin and VAST (I don't know others) have: TestCase
assert: aBoolean So...is there a reason of doing that? Is this expected? I do not see any particular reason. But having Object>>assert: aBlock is important, since one can simply redefine assert: in a class to supress all assertions.
Which begs the question: then why the same method is re-implemented in TestCase anyway?
...just thinking 'aloud'... TestCase>>assert:, by convention, accepts a Boolean, and could be extended to also accept a block (and apparently has been so extended in Squeak). Object>>assert: *should* accept a block, and it isn't really useful for it to accept a Boolean. As Alexandre says, you can suppress assertions by redefining #assert:. One could also make Object>>assert: depend on some variable somewhere to determine whether to actually run the assertion blocks. Then you can turn assertions on and off system-wide, and not be running that assertion code in the blocks all the time. If you accepted a boolean, you'd be running the assertion expression whether assertions were turned on or not, which is undesirable. It's not too nice if Object>>assert: and TestCase>>assert: take different kinds of arguments TestCase>>assert: takes a Boolean. I suspect that's too widely used to change. I don't know how widely used Object>>assert: is. Perhaps we could have a different selector for that which takes a block. Maybe a selector that implies more strongly that its argument should be a block. Our test framework (which I believe predates SUnit) uses #run:forResult:, with a block for the first argument and the expected result of evaluating the block as the second argument. I like this for a couple of reasons -- run: strongly implies that it should take a block argument, and giving the expected result separately allows failure messages of the form "Expected <a>; got <b>" which is handy anytime but *really* useful when failures are not easily reproducible. Regards, -Martin P.S. -- the following is marginally related: In performance-critical code that is executed *very* frequently, even making a message send and checking whether assertions are turned on or not can have too much impact. In those situations, I banish all assertions to a subclass, which has methods of this general form: someMethod | result | self assert: [assertions appropriate on entry to this method]. result := super someMethod. self assert: [assertions appropriate on exit from this method]. ^result. Then to turn assertions on or off, I have code that can change the class of the instances, and switch whether new instances are of the no-assertions class or the with-assertions subclass. This allows the application to run at full speed when assertions are turned off, a real advantage in some cases. This also separates the normal code from the assertion code, which has both advantages and disadvantages.