REBOL3 tracker
  0.9.12 beta
Ticket #0002248 User: anonymous

Project:

Previous Next
Short URL: http://issue.cc/r3/2248
rss
TypeIssue Statussubmitted Date18-Aug-2015 07:24
Versionr3 master CategoryEvaluation Submitted byfork
PlatformAll Severitymajor Priorityhigh

Summary Should "interstitial" UNSET!s be ignored in "evaluative" contexts? (...Yes..I think.)
Description The title of this "discussion issue" is vague. But it's about how unsets that appear "between" expressions should be handled across the language. Obviously, DO itself has a necessity to ignore these interstitial UNSET!s. Otherwise you couldn't (for instance) call print at all in a sequence of statements without getting an error. But what about other constructs?

To pick one that is currently tolerant (and surprises some) we can look at how ALL deals with UNSET! in #564:

>> a: b: c: true
>> all [a b print "Got here" c]
Got here
== true

PRINT returns UNSET! which is not a "truthy" value, and yet it does not disrupt the train of evaluations. This is not strictly necessary. ALL could require the "interstitial" expression to evaluate to a true value in order to keep from disrupting the ALL's other logic tests, and give an error otherwise:

>> a: b: c: true
>> all [a b (print "Got here" true) c]
Got here
== true

While it's a little bit more typing, it's worth pointing out that the example it's being compared with is rigged a bit. I say "rigged" because the interstitial expression you wanted to run in mid-ALL was PRINT, which returned an UNSET!. That return value made it uniquely able to avoid participation in the surrounding logic. BUT... had the function returned a value (for instance, if PRINT gave back the string it had printed, or the port it output to) then it would require suppression as above with the TRUE.

A more compelling case for the ignoring of unsets is seen with COMPOSE (note that a pair of empty parens is a way of making an UNSET!):

>> condition: false
>> compose/only [a b ( either condition ["Inserted???"] () ) c]
== [a b c]

Being uncommonly inserted as values in blocks, UNSET! is used in COMPOSE/ONLY to signal a desire to insert nothing. When values like even a NONE! are considered as meaningful, leveraging UNSET! in this way makes sense. On the whole, it's much more valuable to have a way out of inserting something vs. inserting an UNSET!.

Moving to another construct, the same issues can be considered with something like a CASE statement. Let's examine its evaluative slots:

case [
(print "Slot One")
1 < 2 (print "Slot Two") [print "Should Happen"]
(print "Slot Three")
1 > 2 (print "Slot Four") [print "Shouldn't Happen"]
(print "Slot Five")
]

I'd argue that slots One/Three/Five are materially different from Two/Four. Two and Four resemble:

>> if condition (print "Interstitial? No.") [print "True Branch"]
Interstitial? No.
[print "True Branch"]

The paren doesn't represent an interstitial position. Nor do Two/Four in the CASE. Hence they should be taken as the body of the condition instead of the block.

Yet One/Three/Five are effectively "interstitials". Given that there is no way to act on an UNSET! condition, the choice is either to ignore them or give an error.

Besides the not-valueless-but-worth-questioning desire to print "Got Here" in debugging scenarios, there is another (stronger) argument for ignoring unsets in *any* interstitial position...be it these in CASE or in ALL, or ANY or SWITCH, or wherever. That argument is to facilitate the so-called "expression barrier".

Currently the expression barrier is modeled as a single backslash character which is the literal form of an UNSET!. It looks like a separator without taking away vertical pipe from optioning in PARSE or elsewhere. It provides a kind of low-cost punctuation that helps show where expressions end. So the following would function *almost* equivalently:

any [a b c \ d e \ f g h i \ j k]
any [(a b c) (d e) (f g h i) (j k)]

The way in which they would not be equivalent is that any quoting operations that are willing to take an UNSET! would be able to eat an expression barrier, as it isn't a special type of value but just UNSET! itself. PAREN doesn't have this issue.

On expression barrier's side is being fewer characters in source, with lower space and faster speed of evaluation. An UNSET! can be skipped almost instantaneously by the evaluator, while additional parentheses groups entail both separate series memory allocations and a recursion of DO, starting a new evaluation stack each time. So light and literate, expression barriers help those wanting to use the "most freeform programming language ever invented" in a way that suits the form of those who want to call out intended arity...with a lower cost than parens

Yet the expression barrier relies precisely on the property described...that unsets in interstitial positions are skipped over. When applied to CASE or SWITCH, this permits interesting alternatives of how to put things on one line. Compare:

case [a > 10 ["a"] b < 20 ["b"]]

to...

case [(a > 10) "a" \ (b < 20) "b"]

That lets you spend your "grouping series points" in a way that makes this case clearer, and still separates it well. To my view, this is a much more powerful and interesting application of the principle than (print "Got Here"). It seems to deepen the Deep Lake.

If this principle is applied, the good news is that it will make decisions flow easier. If not, the bad news is that expression barriers won't work.
Example code

			

Assigned ton/a Fixed in- Last Update19-Aug-2015 01:46


Comments
(0004660)
fork
19-Aug-2015 01:46

CureCode ate my comment and now it doesn't offer me an "Edit Ticket" button. I will wait for the GitHub migration before dealing with this any more CureCode this:

Thought #1: This is actually does not have to be tied up with expression barrier...because there is no hard and fast rule that [a \ b] needs to be handled the same way as [a (expression returning unset) b] would be handled.

Thought #2: The variabilities introduced by allowing interstitial unsets, such as in CASE, can be seen as a parallel to #2245. Except instead of making the "shape" of the case depend on whether a condition is true or false, it's depending on whether an evaluation yields an unset or not. This variability can be bad for both humans and machines, in the sense that a compiled variant of the language (such as Red) can't say ahead of time what the structure is.

So this leans me to think that the answer may actually be no on this, and instead that the way to expression barriers is for these constructs to merely skip over *unset literals*, as distinctly considered from an expression that evaluates and then returns an UNSET!.

Date User Field Action Change
19-Aug-2015 01:46 Fork Comment : 0004660 Added -
18-Aug-2015 07:55 Fork Description Modified -
18-Aug-2015 07:27 Fork Description Modified -
18-Aug-2015 07:24 Fork Ticket Added -