Do not use typedef for signatures
With all but very few exceptions, the ControlSignature
s and ExecutionSignature
s are defined with a typedef
similar to this
typedef void ControlSignature(FieldIn, FieldOut);
typedef _2 ExecutionSignature(_1);
However, now that we are moving our coding style to using using
instead of typedef
, we should no longer use this method of declaration. We had a talk at our last code sprint and opinion was that we should not continue to do this. There was not, however, agreement on what the replacement should be.
This issue lists some alternatives and provides a place to talk about it.
Convert to using
A straightforward approach is to simply use the using
syntax for declaring functional types. So the previous example would like something like this.
using ControlSignature = void(FieldIn, FieldOut);
using ExecutionSignature = _2(_1);
Pros
- A straightforward change for anyone already familiar with signatures.
- Some users have expressed a liking for having the symbol name and its definition distinct from each other (rather than have the symbol name embedded in the middle).
Cons
- The syntax is confusing for those not familiar with defining functional types (and this is rare for most programmers). This would be an added barrier to an interface that already has a steep learning curve.
- I, for one, find the syntax less natural for defining the functional interface to a worklet.
Make a function modifier macro
Another option would be to make a macro named something like VTKM_SIGNATURE
that turns a function declaration into a signature. In this case, the examples would look something like this.
VTKM_SIGNATURE
void ControlSignature(FieldIn, FieldOut);
VTKM_SIGNATURE
_2 ExecutionSignature(_1);
The implementation for VTKM_SIGNATURE
is actually pretty easy. Just convert it to typedef
. Yes, that would mean that technically we are still defining signatures with typedef
, but it's not exposed in the code and I think that would be OK.
Pros
- Uses a convention that users are already familiar with and makes these signatures look more like function definitions than ever.
Cons
- Might be too cleaver for its own good. If users cannot distinguish a signature from a function definition, I expect they would try doing invalid things. For example, mixing with other modifiers (e.g.
VTKM_EXEC
) or add a function definition block. The compile errors would be confusing.
Wrap entire signature in a macro
Another approach would be make macros that define the signature for users rather than have the user define them directly. In this case, you would define signatures with something like this
VTKM_CONTROL_SIGNATURE(FieldIn, FieldOut);
VTKM_EXECUTION_SIGNATURE(_1, _2);
Pros
- Simplifies the definition of the signatures and lowers the learning curve for making worklets a bit.
- Can tie this to creating other macros such as
VTKM_INPUT_DOMAIN
to make those easier as well. (Technically, we can do this anyway, but it makes things tie together nicely.)
Cons
- Return values are no longer supported. This is not a huge deal since return values can and often have to be returned in arguments. But it does make returning values nicer and less error prone in the special cases it can be used.
- Macro arguments tend to be sensitive to containing template arguments (e.g.
MACRO(vtkm::Vec<int,3>)
could get split into two arguments for the macro). Probably won't be an issue, but it could be. - Although the level of indirection is helpful for learning and defining, it could cause confusion when compiler error happen because the actual definitions are now buried in the macro.