The point of a reporter is to report a value, it's in the name! Plus, what are you doing with reporters that don't report? That job should be reserved for command blocks.
It does sound to me like you're fighting the basic design of Snap! for some reason.
To have a convincing case for this, you'd have to show a block with a sensible purpose -- something you could put in its help screen to explain it to users -- that requires a reported value only sometimes.
This isn't the only possible design. In Scheme, for example, all procedures are reporters. They can all be embedded in a larger expression, but they also can all be put in a stack, in which case the return value from all but the last one in the stack is ignored.
But in the design we inherited from Scratch, they decided we could take advantage of block shapes to show how they connect. So, command blocks have those tabs at the bottom that fit into notches at the top. (Hat and cap blocks are constrained to the top and bottom of stacks respectively because they are missing the notch or the tab respectively.) On the other hand, the round or hexagonal shape of reporters or predicates suggest that they drop into holes in other blocks.
This use of shapes to represent syntax means that a whole family of syntax errors is visually ruled out; you just can't drop the block in the wrong place.
There is a cost, as you suggest. Sometimes we have two versions of the same block, one for commands and one for reporters/predicates. RUN versus CALL. Two shapes of IF-THEN-ELSE. FOR EACH versus MAP. Those are the only unavoidable ones I can think of. There are a couple of others in which Scratch made something a command because they didn't really believe in first class objects so we had to add a reporter: CREATE A CLONE OF versus A NEW CLONE OF. And occasionally in user code you'll run across an IGNORE block for the case in which the user doesn't care about the value reported by a reporter.
So yeah, every once in a while I wish we had intermediate blocks looking sort of like those pro-evolution bumper stickers: oval, but with feet. But only rarely.
but if you wanna create a reporter that does something else than report, you will be forced to add a report block to not make the error happen, just put the report block's input as empty
For what it’s worth … some fairly modern programming languages, like Haskell and Rust, have a construct for functions that may or may not produce a value. The construct is typically called maybe or “option”. The caller is supposed to take both cases (value / no value) into account, so specify how they must be handled.
An example function is division: if the denominator is zero, division is not possible, so no value can be reported. Another example (category) are functions that are a series of two or more consecutive operations, where at least one is a condition determining whether an intermediate result will be further processed.
I happen to have recently built a (rather trivial) mechanism for this in Snap!:
if a value is to be reported, it is represented by a list with the value as its only item.
in the other case, the function reports an empty list.
A bonus of this approach is that it is also conveniently used where multiple values are a possibility, and / or multiple functions are used to try and find any value at all: just append all answers and you get the list of values, which may be empty, have exactly 1 element, or multiple elements.
RUNRESULT instructionlist
runs the instructions in the input; outputs an empty list if
those instructions produce no output, or a list whose only
member is the output from running the input instructionlist.
Useful for inventing command-or-operation control structures:
local "result
make "result runresult [something]
if emptyp :result [stop]
output first :result
.MAYBEOUTPUT value (special form)
works like OUTPUT except that the expression that provides the
input value might not, in fact, output a value, in which case
the effect is like STOP. This is intended for use in control
structure definitions, for cases in which you don't know whether
or not some expression produces a value. Example:
to invoke :function [:inputs] 2
.maybeoutput apply :function :inputs
end
? (invoke "print "a "b "c)
a b c
? print (invoke "word "a "b "c)
abc
This is an alternative to RUNRESULT. It's fast and easy to use,
at the cost of being an exception to Logo's evaluation rules.
(Ordinarily, it should be an error if the expression that's
supposed to provide an input to something doesn't have a value.)