I've mentioned that binding might be helped by a dialect, and it turns out there is some precedent in hiiamboris's WITH:
USAGE SUMMARY
with x [..] == bind [..] x with 'x [..] == bind [..] 'x with :fun [..] == bind [..] :fun with [:fun] [..] == bind [..] :fun with [x y 'z] [..] == bind bind bind [..] 'z y x with [x: 1 y: 2] [..] == bind [..] context [x: 1 y: 2]EXAMPLES
omit the path to an object, but work inside it's context:
do with face/parent/pane/1 [ color: red text: mold color visible?: yes ] if true with system/view/fonts [print [serif size]] f: func [/- /+ /*] [ ;-- redefines important globals locally (do something with local flags) foreach x [set..] with system/words [ (do something with global * + -) ] ]create static storage for functions where existing literal forms don't allow you to:
factorial: func [x] with [cache: make hash! [0 1]] [ any [ select/skip cache x 2 put cache x x * factorial x - 1 ] ]anonymize words used during initialization of the program:
first item in the block should be of set-word! type do with [x: 1 y: 2] [ z: x * y ... other code that uses x or y ... ]bind a block to multiple contexts at once (in the list order):
First item in the block should be of word!/get-word!, path!/get-path! or lit-word! type
words and paths values are fetched, while lit-words are converted into words
get-words and get-paths should be used for function context, otherwise they get evaluatedif resulting value is a context, block is bound to it
if resulting value is a word, block is bound to the context of this wordthe following example illustrates usage of words and lit-words:
a: b: x: y: none c: context [ a: 1 b: 2 f: func [x y] [ ; calls `with` internally print composite [self 'x] "a=(a) b=(b) x*y=(x * y)" ; equivalent print composite [self :f] "a=(a) b=(b) x*y=(x * y)" ] ]Thus,
with [c]is equivalent towith c, whilewith ['c]- towith 'c.WHY IS IT DESIGNED LIKE THIS?
It does not evaluate
withdoes not evaluate the block, so:
- it can be used after
contexts,ifs,loops,funcs, etc.- it can be chained
with x with y ...I've found that this makes code much more readable than it would be with
bind.
Prefix it withdoif you want immediate evaluation.It accepts blocks
Design question here was - if we allow block! for
ctx, how should we treat it?
convert it to a context?
ctx: context ctxthat shortens the
with context [locals...] [code]idiomlist multiple contexts in a block as a sequence and bind to each one?
that shortens
with this with that [code]idiomPersonally, I've used the 1st at least a few times, but 2nd - never, though I admit there are use cases.
This can be solved by checking type of the 1st item in the block is a set-word or not
But still ambiguous! Whenwithgets aword!argument it can:
- get the value of this word, which should be an
object!, and bind to this object- get the context of this word, and bind to this context
When inside a context, 2nd option is nice:
context [ a: 1 f: func [x y] [ with [self x] [x * y * a] ] ]..where the alternative would be:
context [ a: 1 f: func [x y] [ with context? 'x with self [x * y * a] ] ]When outside of it, 1st option is better:
x: context [x: 10] y: context [y: 20] do with [x y] [x * y]..where the alternative would be:
x: context [x: 10] y: context [y: 20] do with in x 'x with in y 'y [x * y]But this still can be solved: let
word!s evaluate to contexts andlit-word!s, same as we havebind code ctxvsbind code 'ctx:context [ a: 1 f: func [x y] [ with [self 'x] [x * y * a] ] ] x: context [x: 10] y: context [y: 20] do with [x y] [x * y]