AltME groups: search
Help · search scripts · search articles · search mailing listresults summary
world | hits |
r4wp | 64 |
r3wp | 928 |
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 / 992 | 1 | 2 | 3 | 4 | 5 | [6] | 7 | 8 | 9 | 10 |