• Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

AltME groups: search

Help · search scripts · search articles · search mailing list

results summary

worldhits
r4wp64
r3wp928
total:992

results window for this page: [start: 501 end: 600]

world-name: r3wp

Group: Core ... Discuss core issues [web-public]
BrianH:
27-May-2009
FORALL and FORSKIP are faster than FOREACH in R3 because they don't 
have a local word that requires a BIND/copy of the code.
Dockimbel:
27-May-2009
Wouldn't it be more efficient to just BIND instead of BIND/copy body 
blocks in loops by default, and additionnally provide a /copy refinement 
in the (very) rare cases where you don't want the body block to be 
modified? Is it a design decision or did I missed some obvious reason?
BrianH:
27-May-2009
You have to BIND/copy or *EACH would not be recursion-safe (or task-safe 
in R3).
Pekr:
15-Jun-2009
How do I bind foreach word value to external block? I want to do 
this:

rec: [name last-name adress streeet]

foreach rec data [print [name last-name address street]]

I need to somehow "bind it" :-)
Steeve:
16-Jun-2009
in R2, that should work
>> set bind first a a none
Gregg:
1-Jul-2009
Didier, assuming you can't preface the markup fields with the context 
name, e.g. 

  markup: "my script with <%ctx/val1%> and <%ctx/val2%>"


either manually or programmatically, hacking build-markup may be 
best. e.g., add a /with refinement that takes the object and bind 
to that.
Geomol:
19-Aug-2009
REPEAT is a native. Can it be made as a mezzanine using WHILE? It 
takes 3 arguments:
'word value body


The first is seen as a lit-word by the function. This should be bound 
to body and only be used as a local variable in the function context. 
My first attemp to make a REPEAT mezzanine didn't go well:

my-repeat: func [
	'word value body
][
	bind/copy body word
	word: 0
	while [(word: word + 1) <= value] body
]

>> my-repeat i 10 [print i]
** Script Error: i has no value

Suggestions?
Geomol:
20-Aug-2009
This version without COMPOSE seems to work:

my-repeat: func [
	'word value body
][
	use reduce [word] reduce [
		to set-word! word 0

  'while reduce ['value to word! ">=" to set-word! word word '+ 1]
			body
	]
]


I'm not quite sure, why it works without using BIND to connect body 
with word?
Ladislav:
20-Aug-2009
...why it works without using BIND to connect body with word?
 - of course it binds the body, USE takes care of that
Geomol:
21-Aug-2009
Chris wrote: "G: re. confused - try stepping through the function 
in the order it is interpreted.  Should be clear by the time 'use 
evaluates the two blocks..."


What I find a bit confusing is, when I have to BIND and when I don't. 
It's the context binding rules in REBOL, that is not 100% clear to 
me. Let me give a simple example:

>> b: [print i]
== [print i]
>> f: has [i] [i: 1 do b]
>> f
** Script Error: i has no value


This doesn't work, because the b block is defined outside the f function, 
outside f's function context. Therefore I have to bind b to f's context, 
like this:

>> f: has [i] [i: 1 bind b 'i do b]
>> f
1


That is clear, and I would expect USE to work by the same rules, 
but it doesn't quite, it seems to me:

>> f: does [use [i] [i: 1 do b]]
>> f
1


By some magic, this works without the need to BIND. I'm a bit confused 
by that.
Geomol:
21-Aug-2009
ARGH! It only works, because I first made the f function using BIND. 
So b was already bound to f, when I changed f to include USE. If 
I try to USE version from a fresh REBOL, it doesn't work. (More confusion!) 
:-p
Anton:
21-Aug-2009
BIND recurses into blocks, eg. 'b will be bound in the nested block 
[[b]],

but if 'b happens to currently have a value that is a block with 
words in it, that doesn't matter to BIND, BIND won't go in there.
Anton:
21-Aug-2009
Let me say that again, to be clear.

eg. Binding [[b]] somewhere will cause 'b to be bound (as long as 
'b exists in the "somewhere" context).

but if, before this bind occurs, b has a block value eg.  b: [some 
words] , then the bind will not touch 'some and 'words,

because it won't look to recurse into word values that happen to 
be blocks.
james_nak:
28-Aug-2009
Bind. I often use blocks of field (column) names from a db table 
in functions. Trouble is when I add a field I have to go back and 
add that field name to every place where I am using my fields.  I 
was thinking of just creating a block at the beginning of my code 
and then using "bind" to create a local context. I just can't seem 
to make it local. It behaves as a global. Is there some trick?
james_nak:
28-Aug-2009
Looking at "bind" it appears it should work. It even describes an 
example which is what I want to do:


Binds meaning to words in a block. That is, it gives words a context 
in which they can be interpreted. This allows blocks to be exchanged 
between different contexts, which permits their words to be understood. 
For instance a function may want to treat words in a global database 
as being local to that function. 
Graham:
28-Aug-2009
well, you still have to bind either using 'use or 'bind
Maxim:
17-Oct-2009
pekr it aint. if to-block doesn't bind words... it just shouldn't 
.  how am I going to manage loading data from disk and hope it doesn't 
collide with some stray global word
Steeve:
17-Oct-2009
well, just bind yout rules in a specific context.
con: context [
	any: 'any
	some: 'some
	opt: 'op
	...
]
Maxim:
17-Oct-2009
so what I'll do is follow parse's functioning.  if a word maps to 
a function or a native, ignore it... I know my rules don't bind functions, 
cause they'd fail anyways.
BrianH:
17-Oct-2009
Maxim, BOUND? doesn't bind words to the global context - that was 
done by LOAD. Try this:
>> bound? first to-block "a"
== none
Chris:
20-Nov-2009
Bind the loaded text to a global word first ('system ?) then to your 
local context.
Chris:
20-Nov-2009
test: func [ /local lo ][ lo:  {button "test" [ alert "hello" ]} 
view layout bind to-block lo 'all]
Chris:
20-Nov-2009
Bind to 'all first, then your local word(s)
Graham:
20-Nov-2009
this is user written gui code which is why I bind to the local context 
to prevent them doing stuff that I think might be dangerous.  But 
I want to allow some exceptions.
Graham:
20-Nov-2009
this doesn't work ...


 test: func [ /local lo alert] compose/deep [alert: (:alert) dummy: 
 none lo:  {button "test" [ alert "hello" ]} view layout bind to-block 
 lo 'dummy]
Chris:
20-Nov-2009
do-protected: use [alert][
	alert: get in system/words 'alert
	func [txt][do bind to-block txt 'alert]
]

do-protected {alert "Foo"}
do-protected {print "Foo"}
Graham:
20-Nov-2009
this works 


test: func [ /local lo alert dummy] compose/deep [alert: get in system/words 
'alert dummy: none lo:  {button "test" [ alert "hello" ]}    view 
layout bind to-block lo 'dummy ]

just not working in my script though
Chris:
20-Nov-2009
isolate: func [words [block!]][
	use words compose/only [
		set (copy words) forall words [change/only words get words/1]
		first (copy words)
	]
]


do-protected: func [txt allowed][do bind to-block txt isolate allowed]
Gabriele:
18-Dec-2009
i was just thinking again about the idea of IF (etc.) keeping a reference 
to the condition argument for you, that is, so that instead of writing:

    if x: select block value [do-something-with x]

you can write:

    if select block value [do-something-with it]


The reason people say it's not worth it is usually that of having 
to bind/copy the block - you don't want that in every IF call and 
probably not even in the ones where it would be useful (and, there's 
really no other name you could use for the function).
Gabriele:
18-Dec-2009
so, I thought, can we avoid the bind/copy in any way?


actually, i think we can. some people would run in horror maybe, 
and Brian will complain about it not being thread safe (we still 
have no threads though), but what about the native was changed to 
do something like:

    func [condition block /local it*] [
        set/any 'it* get/any 'it
        it: :condition
        also
            if :condition block
            set/any 'it get/any 'it*
    ]
Gregg:
18-Dec-2009
I have an old IF-IT function, which just does a bind/copy. I used 
it a bit when I first wrote it, but it hasn't become a part of my 
daily life.
Janko:
8-Jan-2010
hm.. if rebol binds hidden ctx to function body then it really can't 
do anything to trigger warning on global words. (if I understand 
things aroung bind correctly)
Janko:
8-Jan-2010
if function uses objects and bind internally or something like that, 
then objects in rebol and bind should be cheap right? and then an 
object is cheaper than function ?
Dockimbel:
8-Jan-2010
if rebol binds hidden ctx to function body

 => It's the other way around, "binds body to ctx". BIND will only 
 link the words that match those defined in the target context, to 
 that same context, nothing more.
Dockimbel:
8-Jan-2010
BIND on a block! does a full recursive traversal of the block! and 
for each word! found, does a fast lookup in the target context (probably 
hashed). So the cost is directly proportional to the size and depth 
of the argument block!.
Gregg:
27-Jan-2010
forskip+: func [
        "Like FORSKIP, but with local FIRST? and LAST? support."
        [throw catch]

        'word [word!] {Word set to each position in series and changed as 
        a result}
        skip-num [integer!] "Number of values to skip each time"
        body [block!] "Block to evaluate each time"
        /local orig result
    ][

        if not positive? skip-num [throw make error! join [script invalid-arg] 
        skip-num]
        if not any [
            series? get word
            port? get word
        ] [

            throw make error! {forskip/forall expected word argument to refer 
            to a series or port!}
        ]
        orig: get word
        use [first? last?] [
            first?: true
            last?:  false
            body: bind/copy body 'first?

            while [any [not tail? get word (set word orig false)]] [
                if tail? skip get word skip-num [last?: true]
                set/any 'result do body
                set word skip get word skip-num
                first?: false
                get/any 'result
            ]
        ]
    ]
BrianH:
30-Jan-2010
resolve: func [

 "Copy context by setting values in the target from those in the source."
	[catch]
	target [object! port!]
	source [object! port!]

 /only from [block! integer!] "Only specific words (exports) or new 
 words in target (index to tail)"

 /all "Set all words, even those in the target that already have a 
 value"
][
	either only [
		from: either integer? from [

   ; Only set words in the target positioned at the number from or later
			unless positive? from [throw-error 'script 'out-of-range from]
			intersect words-of source at words-of target from
		] [

   ; Only set the words in the target that are also in the from block
			intersect words-of source intersect words-of target from
		]
		foreach word from pick [

   [unless value? in target word [error? set/any in target word get/any 
   word]]
			[error? set/any in target word get/any word]
		] not all ; See below for what this means
	] [

  either all [ ; Override all target words even if they have values
			error? set/any bind words-of source target get/any source
		] [ ; Only set target words if they aren't yet set
			foreach word intersect words-of source words-of target [

    unless value? in target word [error? set/any in target word get/any 
    word]
			]
		]
	]
	also target set [source target from] none
]
; Note: This is native in R3 and supports module! too.

; Implementation note: INTERSECT returns the values from its first 
argument,

; and WORDS-OF returns a block of words that are bound to its argument, 
so
;     intersect words-of source words-of target
; returns a block of words bound to source.
Ladislav:
31-Mar-2010
>> a: context [b: context [c: 1]]
>> do bind [b/c] a
== 1
Pekr:
31-Mar-2010
my line of thoughts was .... hmm, I would somehow have to bind b/c 
into 'a's context, but  .... then I never know, how to use bind :-) 
Cool solutions, both from Ladislav and Steeve ....
Group: View ... discuss view related issues [web-public]
Anton:
6-Oct-2006
So if I
	bind [caret: "hello"] system/view

then the first word in the block gets the same context as this word:
	in system/view 'caret

and thus it also references the same value, because it is the context 
which determines what value a word has.
Pekr:
6-Oct-2006
now I seem to understand, just did some small example myself:

block: [print a]
do block ; 'a is not known
my-context: context [a: 1]
do bind block my-context ; now 1 is printed
Anton:
6-Oct-2006
And note that it works also for sub-blocks:
	do bind [print [a]] context [a: 1]
Pekr:
6-Oct-2006
I don't use bind, as it is more guru stuff, but is the bind as it 
is sufficient for you? e.g. wouldn't you prefer bind not binding 
for sub-blocks by default, and e.g. having bind/deep for such thing?
Pekr:
6-Oct-2006
hehe, I can rebind whatever, even functions? do bind [print a] context 
[a: 1 print: :probe]
Pekr:
6-Oct-2006
'bind offers whole level of interesting low level (or high level, 
it depends how you look at it :-) magic ...
Ladislav:
6-Oct-2006
actually, you "borrow" variables, when using BIND
Ladislav:
6-Oct-2006
Confusion for Pekr:

    f: func [x] [x]
    g: func [x] [x]
    var1: first second :f
    var2: first second :g
    bind second :f var2
    bind second :g var1
    f 1
    g 2
    f 3
    g 4
Anton:
10-Nov-2006
Well, it seems easy to patch layout. Just bind the body to system/view/vid
Anton:
18-Feb-2007
A style a day keeps the doctor away:

New idea for a style: A "FLATTEN-PANEL" is a PANEL which "explodes" 
its
pane directly into the parent face's pane. eg:

A normal PANEL and resultant face hierarchy:

	layout [
		panel [
			label
			field
			check
		]
	]

	window
		panel
			label
			field
			check
	
A FLATTEN-PANEL and resultant face hierarchy:

	layout [
		flatten-panel [
			label
			field
			check
		]
	]
	
	window
		label
		field
		check

Implementation and test:

	view window: layout [
		style flatten-panel PANEL with [
			append init [
				foreach face pane compose [

     face/offset: face/offset + (do bind [where] first find second :layout 
     [new-face:])
				]

    append get in get first find second :layout [new-face:] 'pane pane
				clear pane
			]
		]
		
		at 500x200
		flatten-panel [
			label "hello"
			field
			check
		]
	]
Anton:
7-Mar-2007
Maxim, FIELD's FEEL is not so obscure. You need to bind to CTX-TEXT 
and SYSTEM/VIEW, that's all.
Anton:
29-Jun-2007
There will be a bit of trouble if you want to make that 300 a function 
of the face/size or something like that. You might have to bind the 
code so that 'face is taken from the right context. Let us know.
amacleod:
2-Apr-2008
sorry the actual error is:

** Script Error: dragger has no value
** Where: init-code
** Near: make dragger [
    edge: make edge []
    feel: make svvf/drag bind [
        engage: func [face action event] [
      ...
Fork:
2-Apr-2008
In any case, thanks for listening... again, I'm just trying to understand 
the direction.  It sounds like you're suggesting a distribution of 
REBOL could be made which did not include bind to the host's native 
GUI but targeted the browser/server/UI and had dialects for that.
Anton:
20-Aug-2008
amacleod, do you mean adding a TEXT like this:
	scroll-panel [
		text "hello"
	]
and clicking on the text?

The TEXT gains the focus (and can be selected and copied etc.), but 
since the scroll-panel no longer has the focus it doesn't get arrow 
keys etc.
You could make the TEXT inactive by setting its FEEL to none:
	scroll-panel [
		text "hello" feel none
	]

or you could modify its feel to route particular keys such as page-up/page-down 
and arrow keys to the scroll-panel it's in.
	text "hello" feel [
		append last last second :engage bind [
			if find [up down page-up page-down] event/key [

    face/parent-face/parent-face/parent-face/feel/engage face/parent-face/parent-face/parent-face 
    act event
			]
		] first find second :engage 'act
	]
Not particularly easy, but there you go.

I have thought about this issue before, but didn't come up with a 
clear vision of how to handle it properly yet, I think.
Anton:
17-Nov-2008
Nicolas, you could modify the area's engage function, as in this 
patch.

append blk: select select second get in a/feel 'engage [switch act][key] 
bind [print face/text] blk/2
Nicolas:
21-Nov-2008
REBOL []

index: func [dir list /local files] [
	files: sort load dir
	foreach file files [append list join dir file]

 foreach file files [attempt [if find file "/" [index dir/:file list]]]
] index %/c/ files: []

l: layout [
	f: field 600 [call t/picked]
	t: text-list 600x400 data copy files] 

search: func [f-string] [
	t/data: copy files  

 foreach s parse f-string none [remove-each f t/data [not find f s]]
	show t]


append blk: select select second get in f/feel 'engage [switch act][key] 
bind [search f/text] blk/2

focus f view l



if I type something into the field, then I click the slider, it calls 
t/picked. Why? i can't figure it out.
Nicolas:
21-Nov-2008
index: func [dir list /local files] [
	files: sort load dir
	foreach file files [append list join dir file]

 foreach file files [attempt [if find file "/" [index dir/:file list]]]
] index %/c/ files: []

l: layout [
	f: field 600 [call t/picked]
	t: text-list 600x400 data copy files] 

search: func [f-string] [
	t/data: copy files  

 foreach s parse f-string none [remove-each f t/data [not find f s]]
	append clear t/picked t/data/1
	show t]


append blk: select select second get in f/feel 'engage [switch act][key] 
bind [search f/text] blk/2

append clear t/picked t/data/1
focus f view l



if I type something into the field, then I click the slider, it calls 
t/picked.
Anton:
20-Dec-2008
system/view/wake-event: func [port /local event no-btn] bind [
    event: pick port 1
    if none? event [

        if debug [print "Event port awoke, but no event was present."]
        return false
    ]

 if all [pop-face not find pop-list pop-face][pop-face: none] ; <--- 
 Added by Anton. Fix POP-FACE when it's not found in POP-LIST (eg. 
 HIDE-POPUP was done at the escaped console, not by WAKE-EVENT DO 
 EVENT, as usual, here).
    either pop-face [

        if in pop-face/feel 'pop-detect [event: pop-face/feel/pop-detect 
        pop-face event]
        do event
        found? all [
            pop-face <> pick pop-list length? pop-list
            (pop-face: pick pop-list length? pop-list true)
        ]
    ] [
        do event
		empty? screen-face/pane
    ]
] system/view
Anton:
22-Dec-2008
To track it down, I patched all functions (and relevant, nested helper 
functions) involved in Sunanda's example code: VIEW REQUEST-LIST 
INFORM SHOW-POPUP HIDE-POPUP and finally WAKE-EVENT. I added 30 print 
statements to all those function bodies (making sure to bind them 
correctly etc), tracking the control flow, then compared the output 
before and after escape was pressed. Eventually I found the difference 
in control flow in wake-event (EITHER POP-FACE ...).
Steeve:
23-Mar-2009
layout [a: text b: button]
v1: context [a: b: none]
set bind copy next first v1 v1 reduce [a b]

now you can construct v2, v3, V4 using the same layout
Dockimbel:
21-Apr-2009
You can try hacking system/view/window-feel to process events from 
system/view/screen-face/feel like that (quick hack, untested) : 

svwf: second get in system/view/window-feel 'detect 

insert svwf bind [system/view/screen-face/feel face event] first 
pick svwf 5
Maxim:
12-May-2009
just remember to bind the func block to *view before submitting it 
to func

ex:  

view*: system/view
view*/wake-event: func [port ] bind [ 
	.... your wake event redefinition code ...
] in view* 'self


obviously you can mold/all + load  the wake-event func body directly 
or copy it from sdk code if you want.
Maxim:
12-May-2009
rebol []


view*: system/view
; code taken with [probe second get in system/view 'wake-event]
view*/wake-event: func [port ] bind [
    event: pick port 1
    if none? event [

        if debug [print "Event port awoke, but no event was present."]
        return false
    ]
    either pop-face [

        if in pop-face/feel 'pop-detect [event: pop-face/feel/pop-detect 
        pop-face event]
        do event
        found? all [
            pop-face <> pick pop-list length? pop-list
            (pop-face: pick pop-list length? pop-list true)
        ]
    ] [
        do event
        ; OUR HACK >>
        if event/type = 'resize [
        	event/face/feel/after-resize event/face event
        ]
        ; <<
        empty? screen-face/pane
    ]
] in view* 'self

window: view/new/options layout [bt: button "ok" ] [resize]

window/feel: make window/feel [
	after-resize: func [face event ][
		;probe event/type
		;probe "AFTER RESIZE"
		if event/type = 'resize [
			bt/offset/x: face/size/x / 2 - (bt/size/x / 2)
			show bt
		]
		event
	]
]
do-events
Steeve:
16-Sep-2010
If my I'm not doing a wrong guess, your WITH function bind its block 
each time it's called. That may be quite slow.
Endo:
2-Nov-2011
Or write your own:
>> win: layout [bt: button 30x20 "Hello" label "Test" led red]
>> foreach p win/pane [print bind [var text style offset size] p]
bt Hello button 20x20 30x20
none Test label 20x48 32x19
none none led 20x75 12x12
Group: !RebGUI ... A lightweight alternative to VID [web-public]
Anton:
20-May-2007
Scrolling is achieved by modifying face/para/scroll, where FACE is 
your AREA face.

I am sure you can pick the parts you need from the above code, to 
create a nice little function which only appends text.
Note also the definition of LINEY, from further up in EDIT-TEXT: 
        textinfo face line-info 0 
        liney: line-info/size/y 
This depends on LINE-INFO, which is in system/view/line-info

So you will need to either bind your code to system/view and ctx-text, 
or refer to line-info and unlight-text using paths, eg:
	system/view/line-info
	ctx-text/unlight-text
Pekr:
15-Jun-2007
well, but will it bind those variables to those one in 'fields object?
Pekr:
15-Jun-2007
it is just not clear, how to-set-word could bind it to o's 'a
Group: !REBOL3-OLD1 ... [web-public]
BrianH:
17-Apr-2008
Jerry, R2 just had one kind of context (2 if you include the autoexpand 
context used by system/words). Functions, objects and USE all used 
this type of context, and words were bound to this kind of context. 
A function! in R2 is bound to one of these contexts, which gets reused 
when the function is called. When the function is called recursively, 
the value block of the context is pushed on a stack but the context 
is reused - this is the main reason R2 could never be thread-safe. 
The only difference that object! contexts have over function! or 
USE contexts is that the word 'self is added to them.


In R3, there is at least one more context type: stack-relative, which 
is used by the function! type. All of the words bound to a function! 
resolve their bindings relative to the context in the executing stack 
frame, rather than directly. When a function! starts it allocates 
a context on the stack; when it ends it deallocates the context. 
This means that the context of words bound to a function only exists 
when the function is running, so there is no point to referring to 
these words outside of the function. Although this slows down word 
references, it speeds up function! calls and reduces potential memory 
leaks due to word references in functions after they have returned. 
This slowdown in word references is the reason that R2-style rebcode 
doesn't make sense to add to R3 without some changes to its semantic 
model to make up for the difference.


A closure! in R3 is like a USE call in R2 (USE in R3 is implemented 
using closure!). The words are direct-bound to a context (so word 
references are faster), but it creates a new context and bind/copy's 
the code block at the beginning of each closure! call. There is still 
no point to bind a word to a closure's context when the closure isn't 
running, since the next time the closure runs it will create a new 
context, but it does make sense to use a context created by a closure 
call after the closure has returned since it is a regular context 
like a R2 USE context. In general, it is better to use function! 
unless you need to refer to the context after the closure! returns 
- mostly useful for generators, currying and other functional programming 
tricks.


In R3, object! contexts are like the R2 system/words context: they 
can expand, but not shrink; closure! and function! contexts can't 
expand though. There will be further changes to the way object! contexts 
work, and module! contexts will behave the same way.
Joe:
29-May-2008
I  use this for html blocks that have layout information (tags, strings, 
...) and bind them to a local value of the function creating the 
layout but I don't want to have to declare multiple variables
Joe:
29-May-2008
inside the function you do bind/copy blk 'local-var
Joe:
29-May-2008
the bind should probably give an error for variables that are not 
set
BrianH:
29-May-2008
All referenced variables would include ones like 'for, 'if and 'and. 
It seems to me that you want an object, not function local variables. 
That would be much easier to do in R3 with the improvements to bind 
but you can do it in R2 as well.
BrianH:
15-Jul-2008
Much easier to fake class-based or other inheritance structures with 
the recend changes to BIND and IN that came out of Carl's VID work 
recently.
Pekr:
5-Sep-2008
Brian - it is not correct that no work was done. Carl told me few 
months ago, that plugins are some 80-90% done. They have forma API, 
they are just disabled. The plugin simply exports some info for REBOL 
to load and bind or something like that ...
BrianH:
8-Oct-2008
For instance, Steeve's question about the dynamic inheritance of 
styles can be answered by looking at the docs and the blogs Carl 
wrote about the extensions to BIND and IN. IN could handle dynamic 
inheritance, BIND handles static inheritance.
Henrik:
24-Oct-2008
I thought you might be curious to see how FUNCT works. It's very 
useful:

>> source funct
funct: make function! [[
    {Defines a user function assuming all set-words are locals.}

    spec [block!] {Help string (opt) followed by arg words (and opt type 
    and string)}
    body [block!] "The body block of the function"
    /local ctx
][
    spec: copy/deep spec
    body: copy/deep body
    ctx: make object! 4
    bind/set body ctx
    unless find spec /local [append spec /local]
    append spec words-of ctx
    make function! reduce [spec body]
]]
BrianH:
24-Oct-2008
For instance, that funct function above doesn't work as-is without 
changes to make function!, and the underlying "search for set-words" 
ability may be extracted from the internals of bind/set for general 
use. Once that is done I know how to back-port the whole lot to R2.
Henrik:
26-Oct-2008
>> source make-panel
make-panel: make function! [[
    {Create a panel from layout dialect block and options block.}
    style [word! none!]
    content [block! none!] "Contents of the panel"

    options [object! block! map! none!] "Options of the panel" /local 
    options face
][
    if content [
        unless options [options: copy []]
        extend options 'content content
    ]
    face: make-face style options
    init-panel face
    bind-faces face
    do-style-all face 'on-init none
    do-triggers face 'load
    face
]]
BrianH:
7-Jan-2009
Here's the current source for LOAD:

load: func [
	{Loads a file, URL, or string.}
	source [file! url! string! any-block! binary!]

 /header  {Includes REBOL header object if present. Preempts /all.}

;	/next    {Load the next value only. Return block with value and 
new position.}

;	/library {Force file to be a dynamic library. (Command version)}
;	/markup  {Convert HTML and XML to a block of tags and strings.}
	/all     {Load all values. Does not evaluate REBOL header.}
	/unbound {Do not bind the block.}
	/local data tmp
][
	; Note: Avoid use of ALL func, because of /all option
	if any-block? :source [return :source]

	data: case [
		string? source [to-binary source]
		binary? source [source]
		; Check for special media load cases: (temporary code)
		find [%.jpg %.jpeg %.jpe] suffix? source [
			return load-jpeg read/binary source
		]

  url? source [read source] ; can this possibly return not binary! 
  ?
		file? source [read source] ; binary! or block of file!
	]

 ; At this point, data is binary!, a block of file!, or something 
 weird.

	if binary? :data [
		unless find [0 8] tmp: utf? data [
			cause-error 'script 'no-decode ajoin ['UTF tmp]
		]

		; Only load script data:
		if any [header not all] [ ; Note: refinement /all
			if tmp: script? data [data: tmp]
		]
	]

	unless block? :data [data: to block! :data] ; reduce overhead

 ; data is a block! here, unless something really weird is going on
	tmp: none
	
	; Is there a REBOL script header:
	if any [header not all] [ ; /header preempts /all
		tmp: unless any [

   ;not any [file? source url? source] ; removed: hdr in string is same
			unset? first data ; because <> doesn't work with unset!
			'rebol <> first data
			not block? second data
		][ ; Process header:
			attempt [construct/with second data system/standard/script]
		]
		; tmp is header object or none here
		case [
			tmp [
				remove data
				either header [change data tmp][remove data]
				tmp: tmp/type = 'module ; tmp true if module
			]
			header [cause-error 'syntax 'no-header data]
		]
	]
	; tmp is true if module, false or none if not

 ; data is a block!, with possible header object in first position

	; Bind to current global context if not a module:
	unless any [
		unbound
		tmp ; not a module
	][
		bind/new data system/contexts/current
	]

 ; data is a block! here, unless something really weird is going on

	; If appropriate and possible, return singular data value:
	unless any [ ; avoid use of ALL
		all
		header ; This fixes a design flaw in R2's LOAD
		;not block? :data ; can this ever happen?
		empty? data ; R2 compatibility
		not tail? next data
	][data: first data]
	; If /all or /header, data is a block here

	:data
]
Pekr:
15-Jan-2009
this would go against REBOL principles - copy only if needed. There 
was some change in regards to functions in relation to bind or something 
like that, but ...
BrianH:
15-Jan-2009
I'll check. It should just do a bind/copy, not a copy/deep.
Steeve:
9-Feb-2009
something related, in the past i made some tests to simulate hashs 
with integer keys in R2. I used a bitset as an index, mixed with 
block of blocks to store data.

my tests show that for 10000 records,  finding data is near as fast 
as with hashs. 
actually it's incomplete but you have the idea with this:

REBOL []
f: fast-dic: context [
	size: 100000

 hash: 128 - 1	;** hash size speed up the search, must be a power 
 of 2 - 1 (ie. 15, 31, 63, 127, 257 ...)
	master: copy/deep head insert/dup/only [] [] hash + 1
	index: make bitset! size
	flag: func [idx [integer!]][
		unless find index idx [
			insert index idx

   insert/only insert tail pick master idx and hash + 1 idx copy []
		]
	]
	flag?: func [idx [integer!]][find index idx]
	deflag: func [idx [integer!]][
		remove/part index idx
		remove/part find pick master idx and hash + 1 idx 2
	]
] 

t: now/time/precise
loop 10000 bind [flag random 99999] f
print now/time/precise - t
t: now/time/precise
loop 10000 bind [flag? random 99999] f
print now/time/precise - t
BrianH:
13-Feb-2009
FOREACH does a BIND/copy of its code block, but you might have a 
point in this case because the 3 paths are N*3.
Geomol:
2-Apr-2009
There are ways to make private data with object in R2 aswell, using 
BIND, if I remember.
Maxim:
2-Apr-2009
yes you can bind code to two different objects, its quite easy in 
fact.
Steeve:
2-Apr-2009
but you can't bind properties of one object into another one
Anton:
3-Apr-2009
[ This whole post is mainly in the R2 mindset, but is somewhat relevant 
also to R3. ]


The technique of setting words directly into the global context like 
this:

	context [
		set 'o ...
	]


I do not like, because this code is modifying its environment - it 
has side-effects - thus, it is non-modular, and does not scale.

Being non-modular means large software systems can't be built up 
reliably, because the cumulative effect of all those side-effects 
will eventually cause name-clashes in the global context, so that 
some word exported from one context will be overwritten by the same 
word exported from another context.

For example, suppose I've seen two graphics demos by two different 
authors. They each have an awesome graphics processing routine and 
I decide that I would like to combine both routines into a single 
program. They each wrapped their code up in a context and exported 
a word 'process-image, like so:

	; From author #1
	context [
		set 'process-image does ...
	]

	; From author #2
	context [
		set 'process-image func ...
	]


You can imagine that each of these "modules" also has a large amount 
of supporting code, local variables and functions, and each is in 
a large file on the respective author's website. Somewhere in the 
middle of each of these files, in the CONTEXT body code, are the 
SET lines which export the words into the global context.

When I write my program to combine both of these "modules", I will 
probably write code like:

	; Acquire all dependencies
	do %image-processor.r  ; By author #1
	do %super-gfx.r  ; By author #2

	; Create an image and manipulate it.
	my-image: make image! 400x400
	process-image my-image ...


and here I realise that there is a name-clash with the 'process-image 
word, which is set only to the value exported by the second author.
So what do I do?

Here are some theoretical approaches, which have their own problems.

1) I could reload each file just before use:

	do %image-processor.r  ; By author #1
	process-image my-image ...
	do %super-gfx.r
	process-image my-image ...


  Each "module" is not expecting to be used this way, so this has problems 
  like:

  - "Static" locals which are intended to remain in memory will be 
  lost each time the file is reloaded.

  - Performance could suffer; each file could be large, and many calls 
  to 'process-image might be done.


2) I could set the first imported word to my own chosen word before 
importing the second "module". eg

	do %image-processor.r  ; By author #1

 process-image2: :process-image  ; Create an alias, as 'process-image 
 will be overwritten next line.
	do %super-gfx.r  ; By author #2

	; Now use
	process-image2 my-image ...
	process-image my-image ...


  But this means that a line of code has been created in the dependency 
  acquisition stage which has a complex interdependence between the 
  two "modules". They are not independent, and so individual dependency 
  acquisition lines can't be easily copied from this code and pasted 
  into a new script and expected to work right away. If copy/pasted, 
  the code will have to be examined, probably in great detail, to discover 
  what's going on and how to make it work. This will lead right back 
  into each source file, where the SET lines which export words to 
  the global context must be found. What great fun that will be in 
  a large software system built using many modules.


Another approach could be to try to bind each module code to a new 
context which contains the exported words, so they are isolated from 
each other... but this is complex.


All the above approaches are attempting to work around a single problem: 
that each "module" is exporting words where and when it likes, without 
consideration for the environment (other "modules", other global 
words etc.) This is "global namespace pollution" and the approaches 
above just introduce more problems in trying to work around it.


The solution to all this, is, in my view, for modules to declare, 
in the script header, the words that are intended to be exported, 
but for the module code not to actually perform the exports. This 
should be done by the user code, at its option. If a large module 
provides an API of 10 functions, then those function words should 
not be forced into the global context. The user script should be 
able to choose which, if any, of those words to import, and into 
which context it would like to import them. Additionally, the exported 
word value should be importable to a differently-named word, which 
can solve the name-clash problem we have above.

If modules do not use SET, but instead declare their "export" words 
in the script header, then digging through code to find side-effects 
should no longer be necessary. In R2, this requires that all module 
authors adhere to this type of module system, and declare their "export" 
words in a standard fashion.


In R3, I'm hoping the module system will develop into one which can 
enforce the modularity of modules, so that a user script can be sure 
that there were no side-effects introduced by loading any module.
BrianH:
3-Apr-2009
The word!, LOAD and BIND changes in R3 make it *much* easier to catch 
stuff.
BrianH:
3-Apr-2009
load: func [
	{Loads a file, URL, or string.}

 source [file! url! string! binary! block!] {Source or block of sources}

 /header  {Includes REBOL header object if present. Preempts /all.}

 /next    {Load the next value only. Return block with value and new 
 position.}

;	/library {Force file to be a dynamic library. (Command version)}
;	/markup  {Convert HTML and XML to a block of tags and strings.}
	/all     {Load all values. Does not evaluate REBOL header.}
	/unbound {Do not bind the block.}
	/local data content val rst tmp

][  ; Note: Avoid use of ALL and NEXT funcs, because of /all and 
/next options
	content: val: rst: tmp: none ; In case people call LOAD/local
	
	; Retrieve the script data
	data: case [
		block? source [ ; Load all in block
			return map x source [apply :load [:x header next all unbound]]
		]
		string? source [source] ; Will convert to binary! later
		binary? source [source]
		; Otherwise source is file or url
		'else [
			; See if a codec exists for this file type
			tmp: find find system/catalog/file-types suffix? source word!
			; Get the data, script required if /header
			content: read source  ; Must be a value, not unset
			case [
				binary? :content [content] ; Assumed script or decodable
				string? :content [content] ; Assumed script or decodable
				header [cause-error 'syntax 'no-header source]
				block? :content [content]
				'else [content: reduce [:content]]
			] ; Don't LOAD/header non-script data from urls and files.

  ] ; content is data if content doesn't need copying, or none if it 
  does
	]
	;print [1 "data type?" type? :data 'content true? :content]
	if string? :data [data: to-binary data] ; REBOL script is UTF-8

 assert/type [data [binary! block!] content [binary! string! block! 
 none!]]
	assert [any [binary? :data not header]]
	if tmp [ ; Use a codec if found earlier
		set/any 'data decode first tmp :data

  ; See if we can shortcut return the value, or fake a script if we 
  can't
		case [

   block? :data [if header [insert data val: make system/standard/script 
   []]]

   header [data: reduce [val: make system/standard/script [] :data]]

   (to logic! unbound) and not next [return :data] ; Shortcut return

   any [next any-block? :data any-word? :data] [data: reduce [:data]]
			'else [return :data] ; No binding needed, shortcut return
		]
		assert/type [data block!] ; If we get this far
	]
	;print [2 'data mold to-string :data]
	
	if binary? :data [ ; It's a script
		unless find [0 8] tmp: utf? data [ ; Not UTF-8
			cause-error 'script 'no-decode ajoin ["UTF-" abs tmp]
		]
		; Process the header if necessary
		either any [header not all] [
			if tmp: script? data [data: tmp] ; Load script data
			; Check for a REBOL header
			set/any [val rst] transcode/only data
			unless case [
				:val = [rebol] [ ; Possible script-in-a-block
					set/any [val rst] transcode/next/error rst
					if block? :val [ ; Is script-in-a-block
						data: first transcode/next data
						rst: skip data 2
					] ; If true, val is header spec
				]
				:val = 'rebol [ ; Possible REBOL header
					set/any [val rst] transcode/next/error rst
					block? :val ; If true, val is header spec
				]
			] [ ; No REBOL header, use default
				val: [] rst: data
			]
			; val is the header spec block, rst the position afterwards

   assert/type [val block! rst [binary! block!] data [binary! block!]]
			assert [same? head data head rst]
			; Make the header object

   either val: attempt [construct/with :val system/standard/script] 
   [
				if (select val 'content) = true [
					val/content: any [:content copy source]
				]
			] [cause-error 'syntax 'no-header data]
			; val is correct header object! here, or you don't get here
			; Convert the rest of the data if necessary and not /next
			unless any [next block? data] [data: rst: to block! rst]
			if block? data [ ; Script-in-a-block or not /next
				case [

     header [change/part data val rst] ; Replace the header with the object

     not all [remove/part data rst]	; Remove the header from the data
				]
				rst: none ; Determined later
			]
		] [rst: data] ; /all and not /header
	]

 ; val is the header object or none, rst is the binary position after 
 or none

 assert/type [val [object! none!] rst [binary! none!] data [binary! 
 block!]]

 assert [any [none? rst same? head data head rst] any [val not header]]

 ;print [3 'val mold/all :val 'data mold/all :data "type?" type? :data]
	
	; LOAD/next or convert data to block - block either way
	assert [block? data: case [
		not next [ ; Not /next
			unless any [block? data not binary? rst] [data: to block! rst]
			data
		]
		; Otherwise /next

  block? data [reduce pick [[data] [first+ data data]] empty? data]
		header [reduce [val rst]] ; Already transcoded above
		binary? rst [transcode/next rst]
	]]
	
	; Bind to current global context if not a module
	unless any [ ; Note: NOT ANY instead of ALL because of /all
		unbound
		(select val 'type) = 'module
	][
		bind/new data system/contexts/current
	]
	;print [6 'data mold/all :data 'tmp mold/all :tmp]
	
	; If appropriate and possible, return singular data value
	unless any [
		all header next  ; /all /header /next
		empty? data
		1 < length? data
	][set/any 'data first data]
	;print [7 'data mold/all :data]
	
	:data
]
BrianH:
3-Apr-2009
If you read the source you might notice that if you don't specify 
/unbound, the code has to *explicitly* bind the loaded code.
Maxim:
3-Apr-2009
wrt "If you read the source you might notice that if you don't specify 
/unbound, the code has to *explicitly* bind the loaded code."  

didn't you mean IF you specify /unbound   ?
BrianH:
3-Apr-2009
No, to-block and transcode make unbound words. If you *don't* specify 
LOAD/unbound, LOAD won't bind the words, which it actually has to 
do explicitly with that BIND/new statement.
BrianH:
10-Apr-2009
Here's the R2 version of RESOLVE:

resolve: funco [
	"Set known values in target from those given by the source."
	target [object! port!]
	source [object! port!]
	/only from [block!] "Only set words listed here (exports)"
][

 set/any bind either only [bind/copy from] [words-of source] target 
 get/any source
	also target set [source target] none
]
BrianH:
10-Apr-2009
I think. The /only changes are still being tested. Here's the pre-/only 
version:

resolve: funco [
	"Set known values in target from those given by the source."
	target [object! port!]
	source [object! port!]
][
	set/any bind words-of source target get/any source
	also target set [source target] none
]
Ammon:
20-Apr-2009
This looks like a bug to me...

>> obj: context []
== make object! [
]

>> bind 'a obj
== a

>> obj
== make object! [
    a: unset!
]

>> obj: context []
== make object! [
]

>> bind [a] obj
== [a]

>> obj
== make object! [
]
BrianH:
23-Apr-2009
functor: func [

   "Defines a user function with all set-words collected into a persistent 
   object (self)."

    spec [block!] "Help string (opt) followed by arg words (and opt type 
    and string)"
    init [block!] "Initialization block of the persistent object"
    body [block!] "The body block of the function"
][

    make function! reduce [copy/deep spec bind/set/copy body make object! 
    init]
]


We decided to not use the term "static locals" since it would be 
confusing to people not familiar with C languages.
BrianH:
27-Apr-2009
Same with exposing COLLECT-WORDS so it can be used instead of BIND/set 
into a temporary object.
Steeve:
27-Apr-2009
not anymore  bind/copy with FOREACH ?
BrianH:
27-Apr-2009
The BIND/copy overhead is still there, but being able to use FOREACH 
on map!, object!, module!, port! and error! means that you don't 
have to generate a block! copy of those types in order to work on 
them. Plus you don't need the EITHER or CASE to screen for those 
cases.
501 / 99212345[6] 78910