I'm doing some refactoring to bring more consistency between the behavior of SET of a group and a SET-XXX!:
set var expression
; vs.
(var): expression
; vs.
eval compose [(var): expression]
Ideally these should be interchangeable and have the same properties.
Raised Error Propagation
One of those interesting properties is that definitional errors will skip the assignment and propagate one step, vs be promoted to abrupt failure at the moment you try to SET. This allows you to write things like:
>> item: <whatever>
>> block: []
>> error: trap [item: take block]
== make error! [
type: 'Script
id: 'nothing-to-take
message: "Can't TAKE, no value available (consider TRY TAKE)"
near: '[item: take block **]
where: '[take entrap trap enrescue console]
file: ~null~
line: 1
]
>> item
== <whatever>
This has turned out to be quite useful, because without it you'd basically not be able to use TRAP with assignments. The only way to deal with them would be EXCEPT:
var: (...) except e -> [...]
And that's not always what you want--it could be putting the exception logic in an awkward position, and it also often makes you parenthesize complex expressions on the left of the except.
Another Cool Feature... Opting Out
I've actually had cases where this is useful! Let's say you have a variable that's sometimes null, but something you want to set:
var: case [
condition1 [$word1]
condition1 [$word2]
] ; if none of the cases match, CASE returns null
Okay, now let's say you want to call SOME-FUNCTION with an expression, and if VAR is not null you want to assign the expression to var too.
Like this:
if var [
some-function (var): expression
] else [
some-function expression
]
You could factor that out a bit:
some-function if var [
(var): expression
] else [
expression
]
If your expression is complex you'd probably wind up needing to factor it out vs. repeating it:
let e: expression
some-function either var [(var): e] else [e]
BUT SET-GROUP! of a VOID variable will just propagate the value out!
some-function (maybe var): expression
Cool, huh? Anyway, I'm making sure these things work the same with SET the native.
some-function set maybe var expression
You Can't Do That With COMPOSE, Though
eval compose [some-function (maybe var): expression]
It could perhaps be argued that would produce either of:
some-function []: expression
some-function (): expression
Which we might envision working the same way. But I think if you want that, you need to ask for it.
eval compose [some-function (any [var []]): expression]