Limiting PRINT to BLOCK!, TEXT! (perhaps BLANK! to opt-out?)


I’ve been uncomfortable with PRINT taking ANY-VALUE! for some time.

The reasoning–as I explained–is that BLOCK!s are evaluated. So if you try to use PRINT in a generic way, such as print value to do debug output, you don’t know if that is going to do a single or double evaluation. Code that appears to work fine outputting all other values will one day get a BLOCK!, and suddenly you have confusion and/or a serious security problem.

my-routine: func [value [any-value!]] [
    print value

;-- Day 1
x: <a tag>
my-routine x ;-- no problem

;-- Day 2
y: 6.28
my-routine y ;-- yup, fine

;-- Day 304
z: [format hard drive]
my-routine z ;-- uh oh 

(Note: This strongly parallels why there was backpedaling on non-block branches.)

I think that having it accept TEXT! and BLOCK! probably strikes a fair compromise. This way, it’s not treated as a fully generic “any-value!” routine, but it still covers the most common non-block case. If people want to print a generic value they’d have to say print [value]…and I think this makes a lot of sense. (Though I can’t say we’re fully resolved on understanding what that should do, e.g. for instance when value is a BLOCK! itself, at least this is a step forward.)

Bolstering this idea is the strong encouragement of using symbolic routines to dump (!!) and probe (??). This is the proper way to get your debug output, and coverage for ANY-VALUE! with no surprise evaluations. Plus, !! gives evaluator invisibility, which is excellent.

A kind-of-weird idea would be to also allow CHAR!, and have it print the character without a newline. Reason would be to be able to say print newline and have that mean just print literally one newline (not a newline and then a newline). It comes up kind of often, and seems a shame to have to say write-stdout newline or something more drawn out. But also worth pointing out you could get the same effect idiomatically with print [] or print {} and avoid bringing in the extra type and “curious” behavior (that would really only ever be used with newline). Or just print-newline: specialize 'print [line: []]

The rule for accepting blank-in, and having null-out, generally applies only to functions without side-effects. But a “display side-effect” is somewhat different from a data structure side effect. It seems pretty useful here, to have print of blank! be a no-op…and also to be able to throw a THEN or ELSE clause onto that.

Taking a Thrilling Tour Through the DUMP