It's tricky to think of what to do to print out things that don't have representation.
For example, antiforms don't have representations and cannot be molded. (For a proposal of the exception of MOLD of splices, see MOLD:ONLY vs mold spread)
So what's traditionally been done is just render it as a quasiform (so the tilde at the beginning hints something its up), and then add a comment at the end of the rendering.
>> anti 'null
== ~null~ ; anti
The representational issue is a bit of a thorn in the console, but you have to print something. (Well, unless it's TRASH!, where printing nothing is the design.)
Could it perhaps work to just print anti 'null? (Or unlift '~null~, as the case may be.) After all, they don’t really have a syntactic representation to print out in the first place.
For prior art, Haskell often does this kind of thing:
Avoiding that direction and having the console endorsing giving back things that evaluate to the result is another idea:
>> first [a b c]
== 'a
>> any [1 > 2, 3 > 4]
== ~null~
But would be confusing if you didn't do it systemically, e.g. left the quote off of inert things:
>> first [[a b] c d]
== [a b]
>> first ['[a b] c d]
== ''[a b]
So I think the quote would probably need to always be there... and maybe people would get used to it to the point it would be acceptable. Generic quoting opens the door to it being an option.
>> print "Void outputs should still be skipped, probably?"
Void outputs should still be skipped, probably?
== '
>>
This could work if done systematically… but then, you have to consider that you’re no longer looking at the result of your evaluation, but something which evaluates to the result. That feels confusing.
I think there’s a reasonable compromise similar to what is done now: show the literal form of the value if it has one, otherwise give back code which evaluates to that value. That would be unambiguous and consistent, but still easy to read.
To "be accurate", the molding has to show a ^err: vs. err: if what's encoded in the field is an unstable antiform. But if there's not a way to say "suppress" then what it's showing doesn't line up with executable code.
An arbitrary GETTER could have side effects... such as printing out "Field accessed". That means the molding or debug display either has to avoid calling the getter and say "can't display" or suffer the potential side-effect that reading the value will produce some output.
>> obj: make object! [fake: getter [print "HI!" 10 + 20]]
HI!
== &[object! [
fake: 30 ; or avoid the call, e.g. "fake: ...calculated..."
]]
In an interactive UI, you could more easily offer a choice, that if someone wanted to perform the calculation they could click a button or somesuch.
These problems aren't new... and asking AI it says "yeah, that happens".
This seems like a good argument for having a "cache state" of the variable in the getter/setter. e.g. an accessor works in tandem with a value slot that it may ignore (or not), and what debug views show is this value... not the result of the calculation.
; Instead of this:
getter: func [] [compute something dynamic]
setter: func [value] [mutate system using value]
; I propose:
getter: func [last-value] [maybe return it, or recompute]
setter: func [last-value new-value] [decide what to do]
More implications still... e.g. what to show for the "true unset" state.
Now that: (^x: ~) and (x: ~) mean the same thing, and you have to use (tweak $x ~) to go to the "truly, truly unset level"... it works, but since it doesn't use assignment, how to display it?
>> f: make frame! negate/
== &[frame! [
?number?: ...???... ; initialized to "true unset"
]
>> tweak f.number null ; passing NULL just peeks the value (should it be PEEK?)
== \~\ ; antiform
>> f.number: ~ ; normal trash/tripwire
== \~\ ; antiform
>> f
== &[frame! [
number: ~
]
>> tweak f.number null ; passing NULL just peeks the value, again
== ~ ; tweak speaks in lifted band for "normal values"
I don't want to make it overblown that displaying the states of objects may not correspond to patterns as we might have known them...
...what's important is that the representation is coherent and queryable and that the system works. These are display issues which have a long history. How to show cyclic structures, etc. etc. is not going to sort out now... or really ever. We just need a casual answer that "works" for day-to-day.
There's no such thing as that. But that's what it would be, if there was such a thing as that.
e.g. if you could put an antiform into a block (you can't) and if you could evaluate antiforms to produce another state (you can't), we might imagine them producing anti-antiforms.
Bordering on nonsense, but enough to have something to display for now. All I care is that the design works.