Type | Wish | Status | built | Date | 19-Sep-2013 22:05 |
---|---|---|---|---|---|
Version | r3 master | Category | Native | Submitted by | fork |
Platform | All | Severity | minor | Priority | normal |
Summary | Permit non-block values in the THEN/ELSE slots of IF, EITHER, UNLESS |
---|---|
Description |
Currently the conditionals require the branched code to be evaluated to be inside a block. This prohibits writing code of this form: >> print either a > b {Greater} {Less Or Equal} ** Script error: either does not allow string! for its true-block argument To do this, you instead write: >> a: 10 b: 20 print either a > b [{Greater}] [{Less Or Equal}] Less Or Equal The rationale for this is that if the value were not in a block, it would be "live" in the interpreter and run regardless of whether the condition was met or not. So this is what would happen if you were allowed to pass non-BLOCK! arguments, e.g. values, coming from paren! evaluation or otherwise... >> a: 10 b: 20 either a > b (print "Greater" 3) (print "Less Or Equal" 4) Greater Less Or Equal == 4 At first glance it's a little scary. Then again, this is logically consistent with the rest of the way Rebol works... even if people aren't used to seeing *conditionals* that do this. It lays bare that IF, THEN, and ELSE are just functions like others and can process their arguments in the same way. You can even do something cool with it... in this case, running both branches yet picking the result based on a condition. Still, the likely most common case would not run any code, but rather just pick values. Currently the idiom for this is: >> a: 10 b: 20 pick [3 4] a > b == 4 Which I've always found rather crazy, as here TRUE maps to 1 and FALSE to 2 in order to let it act like IF when you only provide one element in the block. :-/ (Note that pursuant to #2056, people should generally not think of Rebol as mapping booleans to *any* specific integers, given all integers are TRUE...) Early on I would have thought not enforcing the blocks was a bad idea, due to seeming to encourage writing hard-to-read code. But I've been bitten a lot by forgetting to toggle whether I had a block on my condition, based on it transitioning from an IF to a WHILE (or vice versa). And given the code pipelines I've seen people write, I don't think allowing the option of using this feature is going to create any great catastrophe. No one is being forced to use it, and in the cases where you might use it, it's clean and handy. Rebol's language philosophy is to encourage omission of "boilerplate" constructions (such as calling out function calls, and writing code in a way that it doesn't need parenthesization is also encouraged to allow for COMPOSE). Letting the block be the suppressor of evaluation--and teaching it as such from the beginning--would make Rebol a little more Reboly and cool. In fact, I'd argue that it would be easier to teach the difference between evaluative contexts and unevaluative ones precisely with this example. Right off the bat, the difference could be demonstrated with parentheses vs. blocks... As an added bonus, this is one change that wouldn't break any existing code. |
Example code |
Assigned to | n/a | Fixed in | r3 master | Last Update | 17-Feb-2014 23:45 |
---|
Comments | |
---|---|
(0003994)
BrianH 19-Sep-2013 23:26 |
It wouldn't break everything, but it would definitely break stuff. This proposal only changes how these functions behave when passed non-block values.
This would have exactly the same behavior that IF, UNLESS or EITHER have when passed block parameters - they would still be delay-evaluated, as they are now. However, this would break some semi-significant features that these functions have now:
It's a tradeoff, increased functionality for decreased debuggability in some cases. On the other hand, the pick ["a" "b"] true? condition expressions can be replaced by the much more readable either condition "a" "b" format, which would also be faster. That gives us readability benefits, one of the benefits of the tradeoff. |
(0003995)
BrianH 19-Sep-2013 23:30 |
Fork, PICK series logic! doesn't map booleans to integers, it uses booleans as an indexer. It's not a conversion, it's a different operation. In some cases you can pick based on entirely non-numeric indexers, like strings or words, it all depends on how the type can be indexed. Rebol is a powerful language. |
(0003996)
fork 19-Sep-2013 23:44 |
@BrianH I know, hence why we're talking about MAKE LOGIC! 0 producing false while MAKE LOGIC! 1 makes true. However, I still think it's a pretty poor primitive, and more likely to confuse or cause bugs. While Rebol *can* do it, I don't think in this case it *should* do it because of how weird and counterintuitive it is, to support a head-scratching (on first glance) idiom. |
(0004038)
abolka 5-Oct-2013 01:28 |
Sounds like a good idea to me; but I don't have a strong opinion on this. |
(0004042)
Ladislav 6-Oct-2013 10:24 |
Yes, actually it is a clever and sound idea. It can make code writing more comfortable, making debugging slightly harder, probably (there is no free lunch).
In my opinion the decision should be left to a user poll or to Carl. I would probably vote for the change exactly because it removes punctuation where I do not find it necessary. |
(0004043)
Gregg 7-Oct-2013 07:49 |
I'm OK with it. As Ladislav said, it's a tradeoff. |
(0004048)
endo 7-Oct-2013 13:25 |
It looks OK to me. Actually I sometimes think about it, would be nice especially for EITHER in PRINT EITHER value "yes" "no" case.
But I don't know if there are any BINDing issues for functions that return block! values. Or any performance issues. |
(0004050)
adrians 7-Oct-2013 19:21 |
I like it. The paren evaluation of both clauses seems odd at first, but doesn't detract from the overall idea. |
(0004052)
maxim 7-Oct-2013 20:44 |
As long as there are no measurable speed impacts on such high-use functions It's probably a good idea (it can even be back-ported to R2).
Using this allows us to merge conditional ops and conditional statements into the same concept, based solely on what is provided to the conditional. Much cleaner than other languages which have two redundant syntax. IMHO the only real caveat, is that allowing any value after a condition will make some bugs extremely hard to track. Currently, when we have a missing block, we know exactly what is wrong and can fix it. With this changed... it may be quite a marathon to understand what went wrong. ex: compose [ either a > b [ ] ( data ) ] ; this could be horrendously complicated to figure out, cause no error would be raised unless data is empty. |
(0004214)
fork 12-Jan-2014 17:10 |
@Sgeo in StackOverflow chat suggested that in order to provide for a true replacement of:
PICK [x y] condition There would have to be a refinement to IF, EITHER, and UNLESS which would tell it not to evaluate the branch. >> pick [[1 + 2] [3 + 4]] 1 < 2 == [1 + 2] >> either 1 < 2 [1 + 2] [3 + 4] == 3 This suggests that perhaps an /ONLY refinement would be needed for this intention. >> either/only 1 < 2 [1 + 2] [3 + 4] == [1 + 2] It is not likely something you would use unless the branches were not literals in the source >> either/only (1 < 2) a b |
Date | User | Field | Action | Change |
---|---|---|---|---|
17-Feb-2014 23:45 | BrianH | Status | Modified | submitted => built |
17-Feb-2014 23:45 | BrianH | Fixedin | Modified | => r3 master |
12-Jan-2014 17:23 | fork | Comment : 0004214 | Modified | - |
12-Jan-2014 17:10 | fork | Comment : 0004214 | Added | - |
7-Oct-2013 20:44 | maxim | Comment : 0004052 | Added | - |
7-Oct-2013 19:21 | adrians | Comment : 0004050 | Added | - |
7-Oct-2013 13:25 | endo | Comment : 0004048 | Added | - |
7-Oct-2013 07:49 | Gregg | Comment : 0004043 | Added | - |
6-Oct-2013 10:32 | Ladislav | Comment : 0004042 | Modified | - |
6-Oct-2013 10:28 | Ladislav | Comment : 0004042 | Modified | - |
6-Oct-2013 10:24 | Ladislav | Comment : 0004042 | Modified | - |
6-Oct-2013 10:24 | Ladislav | Comment : 0004042 | Added | - |
5-Oct-2013 01:28 | abolka | Comment : 0004038 | Added | - |
19-Sep-2013 23:44 | fork | Comment : 0003996 | Added | - |
19-Sep-2013 23:30 | BrianH | Comment : 0003995 | Added | - |
19-Sep-2013 23:26 | BrianH | Comment : 0003994 | Added | - |
19-Sep-2013 23:03 | Ladislav | Comment : 0003993 | Removed | - |
19-Sep-2013 22:47 | BrianH | Category | Modified | Unspecified => Native |
19-Sep-2013 22:44 | Ladislav | Comment : 0003993 | Added | - |
19-Sep-2013 22:16 | fork | Description | Modified | - |
19-Sep-2013 22:15 | fork | Description | Modified | - |
19-Sep-2013 22:09 | fork | Description | Modified | - |
19-Sep-2013 22:08 | fork | Description | Modified | - |
19-Sep-2013 22:07 | fork | Description | Modified | - |
19-Sep-2013 22:06 | fork | Description | Modified | - |
19-Sep-2013 22:05 | fork | Ticket | Added | - |