Compile time safety for Around

14 views
Skip to first unread message

Nimrod Argov

unread,
Aug 15, 2016, 4:43:01 AM8/15/16
to specs2-users
Hi,

I'm writing code that provides behavior around examples.
I wanted to have two traits, that provide this functionality. 
One to mix in at the class level, and one to mix in at the Context (Scope) level.

The class level trait uses AroundEach to provide the required functionality for every example.
The context level trait uses Around for the same purpose.
However, I wanted to have the compiler issue an error if a user used the wrong trait at the wrong place. 
For example, mixing in the context level trait at the class declaration.

The solution for the class level trait was easy : self type with Specification forces the user to mix in at the class level.
The context level trait, however, was harder to solve, since Around extends Scope, and therefore can be mixed in anywhere.
Eventually, the only solution I could think of was to copy the Around code, and remove the Scope, adding a Scope self-type at my trait level, 
which forces the user to mix-in the trait to something which extends Scope.

I was wondering if this was the best approach possible or if there is a better way to accomplish this.
Also, I was wondering about the decision to mix in Scope with "specification.Around", 
since while it prevents the user from having to mix in Scope in her code, it doesn't provide compile time protection
from someone who would try to mix it in an inappropriate place (such as the class declaration). 

etorreborre

unread,
Aug 15, 2016, 5:04:14 AM8/15/16
to specs2-users
Hi,

The Scope trait was introduced as a marker trait to convert the block passed to "my example is" >>.
Then there is only one conversion from the various `Before`, `Around`, `After` mutable traits to a Result.

There is however a runtime protection to prevent you to use Scope with expectations which don't throw exceptions.
This is necessary because you could mix-in MustMatchers instead of MustThrowMatchers for example.

We could add an additional runtime-check to make sure that you are not mixing Scope with a Specification.

However I think your solution is good. I tried to make specs2 a *library* where you can reuse block at different levels to achieve what you want.
Defining your own Around type to enforce Scope presence looks ok to me.

In all of this I am more worried by the fact that DelayedInit will be removed from future ScalaVersions and the Before/Around/After mutable implementations rely on it.

Eric.
Reply all
Reply to author
Forward
0 new messages