REBOL3 tracker
  0.9.12 beta
Ticket #0002147 User: anonymous

Project:

Previous Next
rss
TypeWish Statusreviewed Date10-May-2014 03:16
Versionr3 master CategoryNative Submitted byfork
PlatformAll Severityminor Prioritynormal

Summary ALSO should evaluate block arguments
Description The sensible purpose of ALSO is that you have two code paths...and you want both to run, but the first code path is the one with the result you want. You are trying to avoid a temporary variable, so basically a nicer form of this pattern:

tmp: do [some various stuff]
some other stuff
tmp

I thought it was a nifty idea when I found out about it. But when I tried to actually use it for the first time in a Rebmu program, I found ALSO does not evaluate its arguments:

>> also [print "Hi" 10] [print "There" 20]
== [print "Hi" 10]

That seems like a job for an ALSO/ONLY (which I imagine would rarely be used). A block argument should be evaluated by default.
Example code
;-- Current behavior

>> also [print "Hi" 10] [print "There" 20]
== [print "Hi" 10]

;-- Desired behavior

>> also [print "Hi" 10] [print "There" 20]
Hi
There
== 10

>> also/only [print "Hi" 10] [print "There" 20]
== [print "Hi" 10]

Assigned ton/a Fixed in- Last Update22-Jun-2014 23:46


Comments
(0004422)
Gregg
12-May-2014 19:25

That makes sense to me, at a glance.
(0004450)
BrianH
21-Jun-2014 22:12

Fork, there are a few things you need to remember:
- Block values are usually data, not code. We only use them as code for dialects or deferred execution.
- Function calls though path expressions are expensive compared to direct function calls.
- We have a paren type.

Here is the most common use of ALSO: also reduce [a b c] (a: b: c: none)

You might notice that the result of REDUCE is a block. With your change, that wouldn't work, you'd have to use also/only. You don't use /only for the most common case, especially for a function that doesn't normally have path decoding or option processing overhead. What's more, this change is completely unnecessary. Here is how you do your desired behavior now:
>> also (print "Hi" 10) (print "There" 20)
Hi
There
== 10

Did you forget that parens are more than just for expression grouping in Rebol? That's perfectly normal code.

ALSO is an interesting function. It seems like it would be simple enough to just do this:
set/any 'tmp (print "Hi" 10)
(print "There" 20)
:tmp

The only reason ALSO exists is speed, and the only reason ALSO is fast is that it's entire source is this:
REBNATIVE(also)
{
    return R_ARG1;
}

That's it. It's fast to call because it isn't called with path syntax. It's fast to run because it doesn't process any function options, it's just a return statement. If you add more behavior, even a function option that is completely ignored, it loses the speed that is its only reason for existence. And it seems ill-advised to do so for something that you can do already.
(0004472)
fork
22-Jun-2014 23:06

I wrote a longer response, but CureCode ate it. To recap, your case of:

>> also reduce [a b c] (a: b: c: none)

Could be rewritten as:

>> also [reduce [a b c]] [a: b: c: none]

Pretend this were a much longer response, and I explained why I feel that it's a bit of a stretch to introduce primitives like this as being there for performance... and that having them fit nicely into a family of functions like IF, UNLESS, EITHER which do not (by default) require you to DO their arguments if they are blocks is good.

While the parentheses trick is useful, I'm not certain that the claim that the only purpose of this is efficiency is fitting. It seems like it's useful for expression; especially when you wish to express that you don't want to name and declare a temporary variable.

For ergonomic purposes and teaching this as anything other than an evaluative black-sheep, I think it should run the blocks and need an extra block to suppress that. That is if we are to think of this as something taught and used in compiled and non-compiled contexts. As for how it works today, I'd be interested to tackle the performance scenarios in which it is used today if you feel those are very important.
(0004473)
BrianH
22-Jun-2014 23:46

Well, originally ALSO was intended to clean up after Rebol 2 local variable references before the function returned, since otherwise they persisted (memory and sometimes security leak), but when I told Carl that was my motivation, he changed Rebol 3's function calling model so that didn't happen anymore (and in a few other beneficial ways). For Rebol 2, assuming ALSO was widely used so its own arguments got cleared (it's mezzanine there) or if it were converted to native, it would allow you to clean up safely.

In Rebol 3 though, that need isn't relevant. It's just a nicer way to write cleanup code. However, we hand-optimize our code so if it weren't fast it wouldn't be used, no matter how nice it was (see most of the loop functions in Rebol 2 for an example). Using block syntax means that we can't rely on normal evaluation to do our work, it has to internally evaluate the block arguments separately, and if they're not mandatory then it also has to have conditional code to detect the blocks. Pretty soon we'd start optimizing ALSO away.

The speed of ALSO is its primary feature. You don't even necessarily need to put the arguments in parens, you can just have them there inline in many cases, and the function itself does almost nothing. Even the name isn't the primary feature, it's just the best of a bad set of choices.

The only advantage that you would get from this proposal would be if you made the block arguments mandatory, rather than optional. One of the main issues ALSO has now is that it's hard to tell the two arguments apart in the commonly complex usage case. Putting those two arguments in blocks would improve readability, and it only adds one layer of recursion in the C code, basically the same overhead it would have if the arguments are in parens, but all the time. It's not that different a tradeoff from the IF/only change, but its only value would be aesthetic.

You'd have to break all existing code, because making the blocks optional and autodetected would be a cause for grief. This isn't like IF or EITHER, for ALSO returning block values is the norm, not the exception. There would be no point in adding an /only option to get the old behavior, since it wouldn't be compatible with existing code and the overhead of path decoding would more than erase any savings we would get back from losing the blocks, and add overhead to the non-/only case as well to detect the lack of the /only option. So even having an explicit /only option would be a bad idea - it's mandatory blocks or not at all.

Date User Field Action Change
23-Jun-2014 00:05 BrianH Comment : 0004473 Modified -
23-Jun-2014 00:03 BrianH Comment : 0004473 Modified -
23-Jun-2014 00:01 BrianH Comment : 0004473 Modified -
22-Jun-2014 23:46 BrianH Comment : 0004473 Added -
22-Jun-2014 23:06 Fork Comment : 0004472 Added -
21-Jun-2014 22:15 BrianH Description Modified -
21-Jun-2014 22:15 BrianH Code Modified -
21-Jun-2014 22:15 BrianH Category Modified Unspecified => Native
21-Jun-2014 22:15 BrianH Status Modified submitted => reviewed
21-Jun-2014 22:12 BrianH Comment : 0004450 Added -
12-May-2014 19:25 Gregg Comment : 0004422 Added -
10-May-2014 03:16 Fork Ticket Added -