Skip to content

Instantly share code, notes, and snippets.

@x8x
Created August 4, 2018 18:28
Show Gist options
  • Save x8x/e0af4637838f020e0673f854a9f6e261 to your computer and use it in GitHub Desktop.
Save x8x/e0af4637838f020e0673f854a9f6e261 to your computer and use it in GitHub Desktop.
@x8x
Copy link
Author

x8x commented Aug 4, 2018

1) This doesn't work, path is looking for 'a in global space

Why? I wrongly assumed that do would execute in the current context which in this case would be inside the function where a is defined. Explanation welcome!
Rebol:

f: func [/local a][
	a: context [b: context [c: 'ok]]
	print do load {a/b/c}
] f
** Script Error: a has no value
** Where: f
** Near: a/b/c

Red:

f: func [/local a][
	a: context [b: context [c: 'ok]]
	print do load {a/b/c}
] f
*** Script Error: a has no value
*** Where: do
*** Stack: f

2) Works in Rebol, Red returns path instead

Rebol:

f: func [/local a][
	a: context [b: context [c: 'ok]]
	print do bind reduce [load {a/b/c}] 'a
] f
>> ok

Red:

f: func [/local a][
	a: context [b: context [c: 'ok]]
	print do bind reduce [load {a/b/c}] 'a
] f
>> a/b/c

3) Same as previous one, works in Rebol, Red returns path instead

Rebol:

f: func [/local a][
	a: context [b: context [c: 'ok]]
	print do join to path! 'a load {b/c}
] f
>> ok

Red:

f: func [/local a][
	a: context [b: context [c: 'ok]]
	print do join to path! 'a load {b/c}
] f
>> a/b/c

Any better solution in Rebol than 2 and 3?

4) Note that in Red, even in global space it returns the path instead of the value

This is the same example @dockimbel provided here for Rebol:
https://stackoverflow.com/questions/15093642/how-do-i-pick-elements-from-a-block-using-a-string-in-rebol
Thought, in Red, doing without loading does work, why?
Rebol:

a: context [b: context [c: 'ok]]
do load {a/b/c}
>> ok

Red:

a: context [b: context [c: 'ok]]
do load {a/b/c}
>> a/b/c
do {a/b/c}
>> ok

5) This is wired

Red:

a: context [b: context [c: 'ok]]
print do 'a/b/c
>> make typeset! [datatype! unset! none! logic! block! paren! string! file! url! char! integer! float! word! set-word! lit-word! get-word! refinement! issue! native! action! op! function! path! lit-path! set-path! get-path! routine! bitset! object! typeset! error! vector! hash! pair! percent! tuple! map! binary! time! tag! email! handle! date! image! event!]

6) Why does this returns false?

Red:

a: context [b: context [c: 'ok]]
do 'a/b/c
>> false

Conclusion: I couldn't find a way to solve this inside a function in Red. 300RED for who does find a solution in Red interpreted and not in global space! (valid until 2018/08/10 UTC) 😃

@toomasv
Copy link

toomasv commented Aug 4, 2018

You should bind a to functions' context, which is provided by :f:

f: func [/local a][a: context [b: context [c: 'ok]] print do bind [a/b/c] :f] f
ok

If you need to load it for some reason:

f: func [/local a][a: context [b: context [c: 'ok]] print do bind reduce [load {a/b/c}] :f] f
ok

@x8x
Copy link
Author

x8x commented Aug 4, 2018

@toomasv Oh well! That works! Thank you! Guess you win the bounty! Please send me your address on Gitter, so I can transfer the REDs!
..btw, always impressed by your Red productivity!! 👍

Now for some details about how/why that works:

  • magic :f, when defining function f, the body block is just that, a block! not executed yet, hence no complain about :f not being defined yet. While when calling f, :f gets its value from the global space, where function f is defined. Correct?
  • Why is that not the same as bind [] 'a ? Binding to a word! should execute the block! in the context where that word! is defined, which in this case would be the f function body.
  • Why do load, inside the function body, execute in the global space and I need to bind it in the first place?

Still curious about Rebol/Red different behaviours, is that wanted, enhancement, regression?

@x8x
Copy link
Author

x8x commented Aug 4, 2018

For reference, this doesn't work in Rebol:

  f: func [/local a][a: context [b: context [c: 'ok]] print do bind reduce [load {a/b/c}] :f] f
** Script Error: bind expected known-word argument of type: any-word object port
** Where: f
** Near: print do bind reduce [load "a/b/c"]

@toomasv
Copy link

toomasv commented Aug 5, 2018

@x8x I can't answer all the questions, as I don't know the implementation internals of Red, but I think you are correct on first point.
About the third point, I think it is because the a resulting from loading the string is bound to default global context. I may hypothesize that a-s in function's body are bound to local context at definition time, but loading happens in runtime, and a resulting from loading in runtime is not bound to functions context.

BTW, in my first snippet bind isn't needed actually, because a is bound in this case:

f: func [/local a][a: context [b: context [c: 'ok]] print do [a/b/c]] f
; or 
f: func [/local a][a: context [b: context [c: 'ok]] print reduce 'a/b/c] f
; or
f: func [/local a][a: context [b: context [c: 'ok]] print a/b/c] f
ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment