Taking a Thrilling Tour Through the DUMP

DUMP is a vastly enhanced variation of the ?? operator in R3-Alpha. If you weren't familiar with that, it was a simple spin on PROBE that quoted its argument and would GET it. Like PROBE, it would return that same result for chaining. There's not much to it, and its only "power user" feature was the ability to take a BLOCK!, and for some reason return that block unevaluated:

r3-alpha>> x: 10 y: 20

r3-alpha>> ?? x
x: 10
== 10

r3-alpha>> ?? [x y] 
x: 10  y: 20  
== [x y]

Now before you keep reading, you better sit down... 'cause Ren-C's gonna knock you off your feet. :mans_shoe: :mans_shoe:

English Name, and a Convenient Symbol Name

The DUMP service routine is also exposed as --, as part of the "repurposing of jarring symbols". This makes it even easier to type than ??, yet still easy to see once typed in. But ?? isn't going to waste...it's now a shorter way to say PROBE.

(And you're going to want to use DUMP a lot, so not having to hit shift to get those ?-marks is going to be ideal.)

As the forum post linked above explains, the shorthands are for use when what you're doing is not supposed to be checked in with the code. They're standing out for a reason, to help you notice temporary stuff you threw in to help you debug. So hopefully you won't accidentally commit them. If you are writing test code which intends to leave the operations in for the long term, then use the full words.

Note that there's no reason to shed a tear over the loss of -- as a decrement operator! It's been leapfrogged by the super cool ME and MY operators, which are more general. (They're slated to get even cooler, once the mechanisms they use are rethought as fully userspace)

Doesn't Interfere with Surrounding Logic

DUMP in Ren-C is a hard-quoting variadic invisible. It has no return result whatsoever, meaning you can use it anywhere...like in the middle of an ANY or ALL statement, and not disrupt them:

>> x: 10
>> any [
       -- "string literals just print labels!"
       -- variable

That gives:

-- "string literals just print labels!"
-- variable: 10
== 30

While running, the output actually includes the -- at the beginning of the line, to help connect the dumped output to the statements in your code. This prefix is customizable, so when you make a dump specialization you can change it to whatever you like.

So it works in ANY, but it also works in ALL...and supports BLOCK! (in a fancier way, explained later):

>> variable: 10 x: <foo> y: <bar>
>> all [
       -- variable
       -- [x y]
-- variable: 10
-- x: <foo>
-- y: <bar>
== 20

If it erred on the side of being either truthy or falsey, you'd have to worry about how your debugging was disrupting matters.

It Quotes, but Can Run an Assignment!

Though DUMP quotes the first thing it sees on its right hand side, it has a special behavior for SET-WORD!s. If it sees a SET-WORD! it will go ahead and let the evaluator process one unit of work before dumping the symbol.

>> -- summation: 100 + 200
-- summation: 300

This means that you don't have to repeat yourself the way you would have to in R3-Alpha, e.g.

r3-alpha>> summation: 100 + 200
r3-alpha>> ?? summation
summation: 300
== 300

While specializing variadics can be irritating, this is actually easy, because DUMP always knows it's going to want at least one quoted parameter. So you can specialize that, and leave the variadic part unspecialized:

>> --setx: specialize '-- [value: quote x:]

>> --setx 1 + 2
-- x: 3

>> --setx 3 + 4
-- x: 7

You'd have to understand how hard it is to make it all "just work" to appreciate it. :slight_smile:

Also Supports GROUP!, PATH!, REFINEMENT!...

You can use expressions in a group:

>> -- (1 + 2 + 3)
-- (1 + 2 + 3): 6

Plus, you can mix and match...things you can use individually will work in a block! Might as well demo a PATH! and SET-PATH! in there too, huh?

>> x: 10 y: 20 obj: make object! [z: _]

>> -- ["some things" x y obj/z (x + y) obj/z: x * y]
-- "some things"
-- x: 10
-- y: 20
-- obj/z: _
-- (x + y): 30
-- obj/z: 200

This shows a test of the idea that if you have a SET-WORD! or SET-PATH! it will carry over behavior as if it was variadic. It breaks the pattern in the block and maybe makes it harder to grok, but it's at least consistent with the quirk.

Also, since @IngoHohmann wanted a quick way to type "I got here" solution, REFINEMENT! is supported:

>> all [(-- /a) true (-- /b) false (-- /c)] print "^ didn't make it to /c"
-- /a
-- /b
^ didn't make it to /c

It doesn't get too much more expedient than that... no SHIFTing and full invisibility. (INTEGER! is for the moment reserved, for a possible verbosity application, but for better or worse, /1 and /2 are legal refinements also.)

Make Your Own Dumpers With DUMPS

This is a "just invented today" idea, but it's still fairly cool. Let's say you have a subsystem and want to make something with DUMP's functionality, but just for it:

--net: dumps #on

You pass it a refinement to say whether it is on or off by default, but you can call it with #on or #off later:

>> --net ["testing..." /1 /2]
--net "testing"
--net /1
--net /2

>> --net #off

>> --net ["testing" /1 /2]

Note that it picked up the name from the SET-WORD! on the left it was assigned to, and uses that to mark its output. Also, if your block runs any code it will run regardless of the enablement. (So we might want better names like #silent and #loud?)

In any case, as it happens, plain old -- will respond to #off and #on too... but raw DUMP will not, it cannot be disabled (except by hijacking or similar).

DUMPS Lets You Make Full Specializations As Well

Whether you have a block with a bunch of variables you want to repeatedly examine, or just one variable with a really long name, DUMPS specializes with it:

>> variable-one: 10 variable-two: 20
>> --dv: dumps [variable-one variable-two]

>> --dv (variable-one: variable-two: <overwrite> 1000) --dv
--dv variable-one: 10
--dv variable-two: 20
--dv variable-one: <overwrite>
--dv variable-two: <overwrite>
== 1000

DUMPS even goes one better on this, by letting you declare a dumper and assign a variable in one step:

>> --v: dumps long-variable-name: 10 * 20

>> --v
--v long-variable-name: 200

>> long-variable-name: 80
== 80

>> --v
--v long-variable-name: 80

If you contrast this with SPECIALIZE w.r.t. a SET-WORD! shown earlier, this doesn't actually specialize with a SET-WORD! or SET-PATH!. If it did, each call would try and get more arguments. Instead, it uses its own variadic information, and then wordifies or pathifies the argument for the specialization. Tres cool, huh?

(Note: One problem here is that since you specialized out the parameter, you have no way to turn --dv #on or #off any more! There's actually a fair number of complex issues involved with this, but they're being looked at...in the meantime, if you need to turn off a full specialization, do it in two steps...make a non-fully specialized version, then specialize it, and disable it through the non-specialized one.)

Glad You Sat Down, Aren't You? :slight_smile:

This is a great missing piece for anyone who is upset that PRINT has gotten more picky and only takes TEXT! and BLOCK!. If you wanted easy debugging of values, you can't get much easier than -- foo...giving you what you'd otherwise have to do as elide print ["foo is" mold foo]. The kinds of casual scenarios that would have wanted an "easy" print almost always fit this pattern, while the more rigorous ones that produce output are going to prefer the new PRINT.

But the real punch line is how accessible it is getting to write and design these features in userspace. %mezz-dump.r is relatively easy to understand, and is a work in progress. Most of the weird code is DUMP-OBJ from R3-Alpha (it's used by HELP). I think DUMP itself is pretty obvious.

There's no shortage of open questions; I've run up against a bunch tonight, but when you start tallying things like the FizzBuzz success with the cleverness of these designs, it's looking pretty upbeat.

1 Like

Wow, that looks incredible.


Glad you like it, but hopefully it's just a start.

One question that I've been wondering about is if -- should be variadic and pay attention to end of line markers...and group things on the same line if you do, e.g.

x: 10 y: 20
-- "values are" x y

Having that output:

-- "values are" x: 10 y: 20

Might be interesting. Note the concept of a "line" can be fluid, e.g. it might be a div in a browser output.

This would break things like the all [-- /a true -- /b false -- /c] cases, so if you didn't want the "reads until end of line behavior" that might call for another construct. Perhaps ++ or ** would be the alternative if you didn't want to go to the end of the line? Or maybe special exceptions could be made if the argument were a REFINEMENT! or a BLOCK! and it would assume that ended it.

I don't think DUMP itself should be reading end of line markers, this would be something specific to the -- family of dumpers. e.g. what they would do is MAKE BLOCK! by collecting the varargs to the newline marker, and pass the block to DUMP.

What do you think?

I like the idea of -- going to end of line. I try to put debug output on a line all by itself, anyway.
It could read until end of line or bar!
or if the first parameter is a literal block, it could just take the block not read to end of line.
This would help for the case where you want to use it inside of a line or expression.

Had to fix a few things to get that working, but... done! It seems like a good idea not necessarily so much from a typing perspective (-- isn't so hard to type) but just in terms of taking up less screen space.

I think it's better to put the whole thing in a group, looks nicer and coheres what should be together:

 any [... -- [/label1 var var] ... -- [/label2] ...]

 any [... (-- /label1 var var) ... (-- /label2) ...]

Beyond looking better, it parallels how ** as to-end-of-line comment works. Means less quirks to remember.

The cool just keeps getting cooler!

1 Like

So the -- to end of line seems like the most generally useful case. If you don't want that you can put it in a GROUP!.

But with Sea of Words, I'm wondering if we should take it to where we actually treat the words literally, by default. Basically a fast ECHO that takes the word ECHO out of the equation:

-- i got here and value is @x

So we start with that...the invisible generic echoer, that prepends the output with "--" so you know it's debug output. But then have it kick over into shorthand if it recognizes patterns.

Today there's even opportunistic invisibility. So it can switch out of invisibility mode if it sees something like:

-- x: 1 + 2

That could also take away the end of line behavior. It would switch to running the evaluation, and then getting the evaluated variable and dumping it for you.

You could ask for a variable to be dumped with a GET-WORD!

-- :x

Or maybe it just notices when there's only one thing after it, and assumes if you had more to say as a sentence you wouldn't have written one word.

-- x  ; dumps variable x
-- this looks more like a sentence  ; dumps the text

We could use COMMA! to keep it in dumping mode:

-- x, y, z  ; dump three individual variables

Or even weirder, look and see if the last thing ends in a period and assume it's a sentence :slight_smile:

-- ends in a period, must be a sentence.  ; dumps the text

GROUP! could be evaluated, and if you use an @ that could be the "circling" of the value:

>> var: "hello"

>> 1 + 2 -- the variable value is (var)
-- the variable value is "hello"
== 3

>> 1 + 2 -- the variable value is @var
-- the variable value is "hello"
== "hello"

Sky's The Limit...

...and of course whatever we pick, someone else could come up with something they like better.