2

Any idea why the following doesn't work? (R3)

o: make object! [
    foo: does [do "bar"]
    bar: does [print "hello from bar"]
]

o/foo
** Script error: bar has no value
** Where: catch either -apply- do foo
** Near: catch/quit either var [[do/next data var]] [data]
Sunder
  • 1,445
  • 2
  • 12
  • 22

3 Answers3

3

Try this:

o: make object! [
    foo: does [do get bind load "bar" self]
    bar: does [print "hello from bar"]
]
o/foo ;this will work

You need that BINDing because your "bar" lives in the object, not in global scope.

Check this out as well:

my-func: does [print "ok"]
o: make object! [
    foo: does [do "my-func"]
    bar: does [print "hello from bar"]
]
o/foo ;this will work too

You need to LOAD it because it is a string, but it has to be a word to be BINDed. So these will work too (put them in your object):

do get bind to-word "bar" self

or

do get bind 'bar self
endo64
  • 2,269
  • 2
  • 27
  • 34
  • You may already know, SELF points (references) to the object itself. o: context [a: 1 b: self] probe o ;so you could bind the word to the object you are in. – endo64 Feb 10 '12 at 08:21
  • Yes, I understand that. What I don't understand though is if a do "bar" works by looking at the global scope, why doesn't a do "self/bar" look in the current context and just work? – Sunder Feb 10 '12 at 15:38
3

No Scope!!!?

The reason do "self/bar" cannot know where to find 'BAR is because there is no scope in Rebol (not in the traditional CS meaning at least).

Words in Rebol only have meaning once they have been statically bound to a context. This automagically occurs when you 'MAKE an object, so many people don't even realize it even after years of use.

Here are the steps (loosely) when an object (a.k.a. context) is created.

  • It picks up all the root set words in its spec (in this case [FOO: BAR:] )

  • Adds them to its current internal words (SELF: by default, more if you are using an object as basis)

  • Then binds all the words in the block (hierarchicaly) to those set-words it added to its spec.

  • Executes the block.

So you see, once you execute the block its too late, the words already got assigned their meaning, which allows the interpreter to ask for their values (which could trigger an expression evaluation, hence the E in REBOL).

Global, cause that all there really is once executing.

DO and LOAD cannot automatically bind to anything but the global context... because there is no such thing as the "current context" like you'd have in traditional OOP and imperative languages (remember, no scope). Really, once its executing, that information doesn't exist anymore, unless you bound the "current" context to a word... which is what 'SELF does, but to be bound it has to already be loaded, which, when executing a string, never occured.

clueless functions

I'll finish by adding that it may not be obvious at first sight, but while it was binding the Object spec block, it still didn't know what FOO and BAR really were. in fact, the only way FOO and BAR could access the 'O object, is because their function block, when it was run thru 'MAKE, got bound to the object... yep, before it even knew it was a function. then if the function defined its own locals, it would re-bind its body block to those new locals.. because you guessed it... a function creates its own inner context, which gets the same MAKE treatment (but without the internal SELF word).

I hope this helps clear things in a more obvious light.

here is a proof that code isn't scoped:

a: make object! [
    data: "HAHAHAAAAA!!!"
    action: does [print self/data]
]


b: make object! [
    data: "BUMBLING BEHEMOT"
    action: does [print self/data]
]

b/action: get in a 'action

; this will print HAHAHAAAAA!!!
b/action
moliad
  • 1,503
  • 8
  • 13
1

To explain moliad's answer a bit more, see the following explanation:

REBOL words carry a reference to their context with them. It’s not where a word is evaluated that makes the difference, but where it’s declared.

from http://blog.revolucent.net/2009/07/deep-rebol-bindology.html

Here is a very good example:

x: 0
b: [] loop 3 [use [x] [x: random 100 append b 'x]]
;== [x x x]   <-- there are three X which looks same words (and they are same actually)

reduce b
;== [95 52 80]  <-- but they have different values in their contexts

probe x
;== 0     <-- in global context, it has another value as well

This looks weird at first look, but actually it is not. USE creates a new context each time in the LOOP, we set X (in the context the USE created) to a value, then APPEND the WORD (not the value!) to a block. All the words that we append to the block carries their own contexts with them, but they look same word.

When we REDUCE (or PRINT etc.), when we GET their values in their own contexts, we see that they all have different values!

endo64
  • 2,269
  • 2
  • 27
  • 34