Since PRINT doesn't have an interesting return value, we might ask what the harm would be in making it return HEAVY VOID (the empty antiform PACK! containing no values).
Canonizing To Void Has Misleading Opt-Out Properties
The evolution of none results is such that it's part of the ghost-in-null-out strategy, as well a way of doing things like opting out of an APPEND without raising an error.
So consider this (I'm demoing HEAVY VOID's protection against vanishing results in multi-step processes with non-ghostable functions, too...)
>> if 10 > 20 [<d>] else []
== \~,~\ ; antiform (ghost!) "void"
>> print "safety vest", if 10 > 20 [<d>] else []
safety vest
== \~[]~\ ; antiform (pack!) "heavy void"
>> if 10 < 20 [<d>]
== <d>
>> append [a b c] (print "safety vest", if 10 > 20 [<d>] else [])
safety vest
== [a b c]
>> append [a b c] (print "safety vest", if 10 > 20 [<d>] else [])
safety vest
== [a b c <d>]
That feels like a purposeful application of a HEAVY VOID state. But if we were to say that PRINT returned HEAVY VOID, we'd be condoning things like:
>> append [a b c] print "does this seem right?"
does this seem right?
== [a b c]
Somehow a function with an uninteresting result has been elevated to one that people might start assuming has an interesting, void result. It seems to me that having PRINT return an "ornery" value is a safer and saner strategy:
>> trash? print "this makes more sense"
this makes more sense
== ~okay~ ; anti
>> append [a b c] print "I like this error"
I like this error
** Error: APPEND does not accept ~ antiform for its VALUE argument
General Argument: Limiting Interface Flexibility
Let's generalize the question to SOME-FUNCTION where the key point is that at the time you write it, you haven't thought of a meaningful result for it.
If at the time of writing a function you know that it doesn't have a meaningful return value, then making it return HEAVY VOID--instead of returning a trash value--ties your hands in changing it.
People will start writing things like:
all [
...
some-function ... ; user assumes no effect, because of void
...
]
But if SOME-FUNCTION had returned a TRASH value, then they could have gotten the same effect more obviously with:
all [
...
elide some-function ...
...
]
This also gives more freedom to change the interface later, if you think of an interesting value to return. You can progressively add more return types after the fact. But once people assume you always return a void, this trap will happen...you're locked in forever in a way that was pretty much completely avoidable.