Hi Assertions play an important role in design by contract. It is great to have assertions in Pharo out of box (Object>>#assert:). However in projects with many post- and precondition as also class invariants heavy usage of assertions decreases performance... Would it be possible to have a compiler setting (in setting browser) to enable/disable assertions and not compile them to bytecode? Compiler should ignore the whole assertion statement with removed condition. For example: self assert: self hugeInvariant. with disabled assertion hugeInvariant must not be sent. Thanks, Alex |
Hello,
Yes, we should experiment with that. A compiler option is very easy to add… and easy to understand. And trivial to do. 1) step one: add the following line at the start of OCASTTranslator>>emitMessageNode: self compilationContext optionDisableAssert ifTrue: [ aMessageNode selector == #assert: ifTrue: [ ^methodBuilder pushReceiver ] ]. 2) step 2. There is no step. 2 ;-). Maybe a better version would use plugin… changing the code generator like that is a bit a hack. But it works. You can now turn off all sends to #assert: by enabling the #optionDisableAssert compiler option. e.g. class wide by setting on the class side in compiler ^super compiler options: #(+ optionDisableAssert). More magic is, of course, always possible later… I have some ideas. Marcus
|
Another option can be based on meta links like conditional breakpoints.
(Assertion with: [condition]) node: node; install And It can be integrated in editor like breakpoints |
In reply to this post by Marcus Denker-4
Havent tried but would that still compile #assert: as used in SUnit? Also remember discussion of this thread with similar topic: http://lists.pharo.org/pipermail/pharo-dev_lists.pharo.org/2015-June/111037.html Bye T. Gesendet: Donnerstag, 28. Januar 2016 um 15:36 Uhr Von: "Marcus Denker" <[hidden email]> An: "Pharo Development List" <[hidden email]> Betreff: Re: [Pharo-dev] Disable assertions (design by contract) Hello, Yes, we should experiment with that. A compiler option is very easy to add… and easy to understand. And trivial to do. 1) step one: add the following line at the start of OCASTTranslator>>emitMessageNode: self compilationContext optionDisableAssert ifTrue: [ aMessageNode selector == #assert: ifTrue: [ ^methodBuilder pushReceiver ] ]. 2) step 2. There is no step. 2 ;-). Maybe a better version would use plugin… changing the code generator like that is a bit a hack. But it works. You can now turn off all sends to #assert: by enabling the #optionDisableAssert compiler option. e.g. class wide by setting on the class side in compiler ^super compiler options: #(+ optionDisableAssert). More magic is, of course, always possible later… I have some ideas. Marcus On 28 Jan 2016, at 13:54, Aliaksei Syrel <[hidden email]> wrote: Hi Assertions play an important role in design by contract. It is great to have assertions in Pharo out of box (Object>>#assert:). However in projects with many post- and precondition as also class invariants heavy usage of assertions decreases performance... Would it be possible to have a compiler setting (in setting browser) to enable/disable assertions and not compile them to bytecode? Compiler should ignore the whole assertion statement with removed condition. For example:self assert: self hugeInvariant. with disabled assertion hugeInvariant must not be sent. Thanks, Alex |
> On 28 Jan 2016, at 17:32, Torsten Bergmann <[hidden email]> wrote: > > > > Havent tried but would that still compile #assert: as used in SUnit? > This very simplistic version would of course delete those, too. A real version needs to take this into account. Marcus |
I totally dislike these hacks: it means that the source code does not anymore determine the behavior. It's OK as long as it's just a hack,.. But it can't be serious. Copying all the bad features from C is not required to become a mainstream thing ;) Marcus, I definitely classify these fantastic super powers in evil category ! 2016-01-28 17:49 GMT+01:00 Marcus Denker <[hidden email]>:
|
> On 28 Jan 2016, at 20:59, Nicolas Cellier <[hidden email]> wrote: > > I totally dislike these hacks: it means that the source code does not anymore determine the behavior. > It's OK as long as it's just a hack,.. But it can't be serious. > Copying all the bad features from C is not required to become a mainstream thing ;) > Marcus, I definitely classify these fantastic super powers in evil category ! You are totally right, Nicolas. But, the compiler can be customised per class, if i am right, so then it is no longer global (which would be terrible indeed). > 2016-01-28 17:49 GMT+01:00 Marcus Denker <[hidden email]>: > > > On 28 Jan 2016, at 17:32, Torsten Bergmann <[hidden email]> wrote: > > > > > > > > Havent tried but would that still compile #assert: as used in SUnit? > > > > This very simplistic version would of course delete those, too. > > A real version needs to take this into account. > > Marcus > > > |
In reply to this post by Marcus Denker-4
Marcus
I do not really like that we get per class behavior. I would prefer to have a Compiler recompileAllForProductionAndNoAssert or at the level of the package. Stef Hello, |
I wonder if an override of assert/assert: with ^self in production will make a noticeable performance drop once inlining JIT is ready. Of course eliminating the send with compiler hack eliminates some work for inliner, but it sounds like manual optimization duplicating automatic optimizer work.2016-01-28 21:50 GMT+01:00 stepharo <[hidden email]>:
|
2016-01-28 22:12 GMT+01:00 Nicolas Cellier <[hidden email]>:
Is it common to use #assert: outside of unit tests? I always saw this as part of sunit and wondering why one would want to disable it. Sure, there are other language which uses some assert-like construct for runtime checks. But I would have thought smalltalk just does not use it like that or we would have another one, that is not used for sunit tests. nicolai |
Administrator
|
In reply to this post by Aliaksei Syrel
My concern with this is that this proposal requires certain selectors to become reserved. Most SUnit variations that I have seen entail several dozen methods for asserting and denying behaviours, block evaluation versus inline expressions, descriptive explanations, and so on. It seems to me that you would be better off sending messages to a global. Instead of: > self assert: self hugeInvariant. have something like: > Assert that: self hugeInvariant. If the global Assert is bound to a stub the message is sent and ignored. If bound to a real assertion mechanism, it gets evaluated. Use blocks when the argument evaluation is expensive or expensive enough. > Assert evaluationOf: [self hugeInvariant]. None of the names should be taken as suggestions. Just the concept. This also offers the benefit that assertions are practical everywhere, not just under a TestCase hierarchy. A second order effect is you aren't playing with the compiler to turn it on and off, nor to extend the controlled API. |
In reply to this post by Nicolai Hess-3-2
Hi Nicolai,
I picked up this style from Peter Deutch's HPS VM, the VW VM, written in C. I was introduced to preconditions and post conditions at college and asserts are very similar, and can subsume that style. But I am open to a compiler switch to turn them off. I'll answer why in a reply to the next message in thread.
_,,,^..^,,,_ (phone) |
In reply to this post by Richard Sargent
Hi Richard,
> On Jan 28, 2016, at 2:15 PM, Richard Sargent <[hidden email]> wrote: > > Aliaksei Syrel wrote >> Hi >> >> Assertions play an important role in design by contract. It is great to >> have assertions in Pharo out of box (Object>>#assert:). However in >> projects >> with many post- and precondition as also class invariants heavy usage of >> assertions decreases performance... >> >> Would it be possible to have a compiler setting (in setting browser) to >> enable/disable assertions and not compile them to bytecode? Compiler >> should >> ignore the whole assertion statement with removed condition. For example: >> >>> self assert: self hugeInvariant. >> >> with disabled assertion hugeInvariant must not be sent. >> >> Thanks, >> Alex > > My concern with this is that this proposal requires certain selectors to > become /reserved/. Most SUnit variations that I have seen entail several > dozen methods for asserting and denying behaviours, block evaluation versus > inline expressions, descriptive explanations, and so on. > > It seems to me that you would be better off sending messages to a global. > Instead of: >> self assert: self hugeInvariant. > have something like: >> Assert that: self hugeInvariant. > > If the global Assert is bound to a stub the message is sent and ignored. If > bound to a real assertion mechanism, it gets evaluated. Use blocks when the > argument evaluation is expensive or expensive enough. >> Assert evaluationOf: [self hugeInvariant]. > > None of the names should be taken as suggestions. Just the concept. It's a good concept, and is the object-oriented approach. It's just that in practice the costs of creating blocks as assert: arguments, while typically much cheaper than evaluating the assert and discarding its result, are still significant Hence I'm open to a compiler hack that elides the assert: or deny: and it's send altogether from the code. Open but not happy; it's something I hold my nose to do. But this is a style I've been using for twenty odd years and it is really nice to be able to write assert-laden code but not have to pay in production. There is a ray of hope. The Sista adaptive optimiser /will/ be able to elide all the cost of the block form: ... self assert: [self expr]. ... Foo methods for assertions assert: aBlockOrBoolean ^self because there are obviously no side effects. Whereas it will only be able to elide the entire thing depending on expr in the non-block form: ... self assert: self expr. ... But I wonder how any people would have the discipline or insight to use the block form. It looks unnecessarily verbose yes? > This also offers the benefit that assertions are practical everywhere, not > just under a TestCase hierarchy. Whether asserts are practicable everywhere IME depend on how useful they are in ongoing development. The fact that they cost a /lot/ and slow down the VM simulator for Cog doesn't change the fact that it would be much much slower to modify the code base. In another thread I was proposing to Gulle to use the VM simulator instead of a custom VM for his Pharo bootstrap. But in that case one would /have/ to find a way of eliding asserts. One approach would be a package-level rewrite tool that could produce a copy of a package in which asserts have been eliminated. One would always do development in the assert-laden version, but could make the assert-less version available to clients who treat the package as a black box, can therefore assume that no asserts ever fail (because the asserts prove they don't) and use as high-performance a version of the package as possible. With this approach there are no hacks in the compiler, although a derivative of the compiler might be a workhorse in the rewrite from assertful to assertless code. And the Monticello tools (& Metacello) could help automate things. > A second order effect is you aren't playing with the compiler to turn it on > and off, nor to extend the controlled API. > -- > View this message in context: http://forum.world.st/Disable-assertions-design-by-contract-tp4874499p4874621.html > Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com. > |
I tried to experiment with such behavior a while ago. I added an opal compiler extension here: http://smalltalkhub.com/mc/ClementBera/NeoCompiler/main . One needs to recompile the package after it is loaded as it uses a compiler extension. The idea was to introduce [ "some code" ] Cvalue, with Cvalue a message evaluated at compilation time depending on a class-side setting. I put examples in the package. This method: example ^ [ Smalltalk vm class ] Cvalue is compiled, depending on a class side setting, to: example ^ VirtualMachine or example ^ Smalltalk vm class I could have added similar things for assert: and maybe add the C++ IFDEF macro, but in the end I don't think this is a good idea in a Smalltalk system. The code becomes hard to read or you have to extend a lot Smalltalk (extend the syntax, etc.). If one really wants to do that, he can write it in his own DSL that compiles to Smalltalk. It is way easier and does not pollute the base Smalltalk. The user-designed compilation could happen with RB AST transformations, and honestly this is not very difficult and a good developer could do it without too many troubles. 2016-01-29 2:12 GMT+01:00 Eliot Miranda <[hidden email]>: Hi Richard, |
Administrator
|
In reply to this post by Eliot Miranda-2
Thanks for the feedback, Eliot. It's appreciated. If we have to hack, I would rather see the hack done differently. One of my goals would be the ability to restore a production database into a test environment without having to recompile all the methods. (Some of our customers have systems with 30-40,000 classes!) To that end, I was wondering about hacking the compiler to test the association with the reference I've named Assert (but probably in a general approach for any name). The code generator would send a specific message to the currently bound value (one would require it to be implemented by all objects bound to the name, just for honesty and clarity), to ask whether the code generator should emit code to test the named receiver and skip the whole statement if it answers true. The code would be generated in all cases, but it would not be evaluated when the stub mechanism is associated with Assert, since it would answer true to the skip question. Likewise, the real assertion mechanism would answer false and the whole statement would be evaluated. That preceding paragraph glosses over a lot, but I hope the gist is sufficiently clear.
|
On Sat, Jan 30, 2016 at 9:34 AM, Richard Sargent
<[hidden email]> wrote: > To that end, I was wondering about hacking the compiler to test the > association with the reference I've named Assert (but probably in a general > approach for any name). The code generator would send a specific message to > the currently bound value (one would require it to be implemented by all > objects bound to the name, just for honesty and clarity), to ask whether the > code generator should emit code to test the named receiver and skip the > whole statement if it answers true. The code would be generated in all > cases, but it would not be evaluated when the stub mechanism is associated > with Assert, since it would answer true to the skip question. Likewise, the > real assertion mechanism would answer false and the whole statement would be > evaluated. I wonder (in ignorance) if MetaLinks could be applied here? cheers -ben |
Free forum by Nabble | Edit this page |