r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[I'm new] Ask any question, and a helpful person will try to answer.

mhinson
30-Apr-2009
[1928]
I was expecting 
funcA to be passed the values 2 & 3 
funcA refer to them as argZ & argY

FuncA to use local variables argA & argB & these variables to be 
given the content of argZ & argY
funcA calls func1 and passes it values in argZ & argY
func1 recieves values passed and refers to them as arg3 & arg4

func1 uses local vars arg1 & arg2 which are given the content of 
arg3 & arg4

func1 swaps position of values in arg1 & arg2 (so we know the function 
has worked)
arg3 & arg4 are given the values of arg1 & arg2

func1 ends and passes the changed content of argZ & argY back to 
funcA that called it, but as argA & argB
The end part of my code is wrong..  it should be 
argZ: argA argY: argB 
reduce [argZ argY]

so expecting argZ & argY to takeon the content of argA & argB

finaly passes the content of argZ & argY back to where it was called 
so the probe shows the swapped values.
Izkata
30-Apr-2009
[1929x2]
Both functions use pass-by-value, so they can't affect the variables 
outside of themselves using internal references.
And, nothing is being done with what func1 returns:
>> func1 2 3
== [3 2]

Try this:
funcA: func [argZ argY /local argA argB][
    argA: argZ                               
    argB: argY                               
    probe Retval: func1 argA argB            
    argA: Retval/1                           
    argB: Retval/2                           
    reduce [argA argB]                       
]
>> funcA 1 2                                
[2 1]  ;printed by the "probe"
== [2 1] ;returned from the function
(Also, I just copy/pasted without adding Retval to the local variable 
list)
mhinson
30-Apr-2009
[1931x2]
Thanks, the key to my understanding this time was that

Both functions use pass-by-value, so they can't affect the variables 
outside of themselves using internal references

I was under the mistaken impression that all the variables unless 
explicitly made local, would be global.   Thanks for putting me on 
the right path again.
ah, I can see why I was confused.. this function
dat2: "-"
f2: func [dat2] ["operating on the global"
	append dat2 "+"
	return "added"
]
print f2 dat2
print dat2
print f2 dat2
print dat2


keeps adding a "+" to dat2, but if only the value of dat2 is passed 
to the function I cant see why is is not just doing 
append "-" "+"

which would not seem to have any effect on dat2..  so in this case 
dat2 seems to be global.   ~~confused~~
Izkata
30-Apr-2009
[1933]
In this case, the value passed into f2 is a string!, a subset of 
series! (block!, file!, and a couple others are also series!).  Series! 
values are the equivalent of pass-by-reference, like how passing 
an array as an argument in C is pass-by-reference (or similar to 
it...  I forget the exact terminology).

Append works by modifying a series! without creating a new one.
Henrik
30-Apr-2009
[1934]
the value is not copied, which is why it keeps appending.
mhinson
30-Apr-2009
[1935]
Now I have seen references to this behaviour & the need to use "copy" 
in some contexts, but I have not managed to understand it yet.
I suspect it is a very fundemental thing to grasp.
Henrik
30-Apr-2009
[1936x2]
It is very fundamental yes. You must see it as such: REBOL is very 
economical. It will aggresively reuse blocks and strings when it 
can.
And so if you specifically want to keep a series from being changed 
by some operation, you must copy it.
mhinson
30-Apr-2009
[1938]
ah. so this is for variables containing series types only? numbers 
get passed as values (which is in effect a copy?)
Henrik
30-Apr-2009
[1939x4]
If you type:

>> ""


in the console. A string is allocated. You can't reuse it here, because 
you haven't referenced it to get back to it. But it would stay in 
memory until it's garbage collected.

But in this code:

>> loop 10 [append "" 1]
== "1111111111"


The string can be obtained again by the code itself. REBOL reuses 
the string.
Series, yes. You can also reference objects this way.


Another trap is that series within series are also reused. This is 
why COPY/DEEP exists.
If you know when REBOL reuses series, you can make quite memory efficient 
and fast code.
If you don't know, then you can get some strange bugs. If a series 
changes without an apparent reason, then it's likely due to whether 
it's copied or not.
mhinson
30-Apr-2009
[1943]
ah.. this is good stuff.. And this (as expected) does NOT add 1 to 
dat5 each time it is called.
dat5: 5
f5: func [dat5][
	dat5: dat5 + 1
	return dat5
]
print f5 dat5
print f5 dat5


I get it now, I just need to know how to recognise my types accurately.
Henrik
30-Apr-2009
[1944]
Another important point: In the context of your function above, it 
doesn't actually matter whether the input is global. This is because 
REBOL works more on a basis of context rather than locals and globals. 
Locals and globals are probably what you are used to from other languages, 
but in REBOL that functionality is achieved through contexts. If 
the content of the context is allowed to survive, the content will 
survive. 

Try:

boo: func [/local pond] [
  pond: []
  append pond 'fish
]

>> boo boo
== [fish fish]
>> boo
== [fish fish fish]

No globals. :-)
Maxim
30-Apr-2009
[1945]
other languages are like that too mind you... pointers allocated 
on the heap will do the same thing...

default values for python, for example do the same thing exactly.
mhinson
30-Apr-2009
[1946x3]
I get it now I think...  as expected the code below returns 6 every 
time it is called.  I need to make sure I can recognise what types 
I am dealing with. Thanks.
dat5: 5
f5: func [dat5][
	dat5: dat5 + 1
	return dat5
]
print f5 dat5
print f5 dat5
sorry for multiple posts.. client seemed to have lost my first post.
I can't see why that would work that way.
Why does 
pond:[] 
not make pond be []  each time the function is called?   

This is close to one of the first questions I wrote myself in my 
notebook, but not been able to find the answer to.  I read the words 
here
http://www.rebol.com/docs/core23/rebolcore-9.html#section-3.6

which seems to be very closly related.   Is this just a Rebolish 
thing it does because it can be useful in some other context? or 
is there a logical reason that I am not appreciating.   Sorry, I 
am not good at just doing as I am told, I find it helps me remeber 
if I have better understanding.  Thanks.
Henrik
30-Apr-2009
[1949x2]
Because the contents of a function is really a context, and once 
that function is created, it doesn't disappear, including the blocks 
and series that are existing in that function. (We have to be careful 
here about using the word "context" to describe what we say, and 
the concept of "contexts" in REBOL. Don't mix it up.)
The document you link to is exactly that phenomenon. It's both fundamental 
and very useful in REBOL for many things.
mhinson
30-Apr-2009
[1951]
to store a dynamic value called by several parts of the code perhaps?
Henrik
30-Apr-2009
[1952]
It's not a unique phenomenon. It's everywhere in REBOL.
Sunanda
30-Apr-2009
[1953]
It is initially confusing, because the apparent strange behaviour 
is limited to series, not (not sure what the official term is) numbers.

If you try this:
f: func [a /local b c] [b: [] c: 0 append b a c: c + a]
f 1
f 2
source f


You can see that (quite literally, in a metaphorical sense) the in-memory 
copy of function f has been changed:
f: func [a /local b c] [b: [] c: 0 append b a c: c + a]
f 1
f 2
source f


To not have it change in that way (or to re-initialise b, if you 
like):
f: func [a /local b c] [b: COPY [] c: 0 append b a c: c + a]
f 1
f 2
source f

But 'c has not changed in either case:
  c: 0
means exactly what it says.
mhinson
1-May-2009
[1954]
I have a reasonable understanding of functions now thanks to all 
your help. 


Now I have decided to have another go at understanding parsing & 
what I have picked up in more general terms seems to have helped 
my understanding of the documentation a bit better.  The question 
I am trying to solve at the moment is: Is there a straight forward 
way to extract the string "two.txt" from the following string {randomXXXrandom.log 
XXXrandom.txtrandom}  

My limited skills let me extract from the first XXX to .txt, but 
not from the XXX that preceeds the .txt alone.
Pekr
1-May-2009
[1955]
what do you mean by "two.txt"? I can't see it in your string ...
mhinson
1-May-2009
[1956]
I changed my string... doh...  it is "random.txt" now
Graham
1-May-2009
[1957]
what's a sample of what you are trying to do ?
mhinson
1-May-2009
[1958x4]
{randomXXXrandom.log XXXrandom.txtrandom}   is the testing string 
& I am trying to extract only the string after XXX which ends with 
.txt
using parse ... as a learning exercise.   so the only way I can identify 
the string I want is by what comes after it, but it must be before 
the next occurance of XXX
if it was a regular expression it would be something like XXX[a-z]*\.txt
I cant see a way to make the parse function be non-greedy, perhaps 
I just need to look at this in a different way all together? This 
is the sort of thing I have been trying that dosen't work.
spacer: charset reduce [tab newline #" "]
non-space: complement spacer

probe parse/all {randomXXXrandom.log XXXrandom.txtrandom} any [to 
"XXX" copy result thru non-space to ".txt"]
print result
Maxim
1-May-2009
[1962]
parse is entirely different from regexp.  it works by supplying grammar, 
where as regexp thinks in terms of patterns.. this may sound similar, 
but in detail its very different.
Gregg
1-May-2009
[1963]
If you want to be non-greedy, you may need to use alternate rules 
and skip. e.g.

s: {randomXXXrandom.log XXXrandom.txtrandom}
parse/all s [
    any [
        "XXX" mark-1:
        | [mark-2: ".txt"] (
           if all [mark-1 mark-2] [print copy/part mark-1 mark-2]
        )
        | skip
    ]
]
Maxim
1-May-2009
[1964]
I was used to regexp, when I used to program in python in particular, 
and that probably is one of the reasons I had soooo much of a hard 
time grasping parse (even after years of trying)
Gregg
1-May-2009
[1965]
Yes, parse and regex are more different than alike. Parse is not 
designed to be concise. :-)
Maxim
1-May-2009
[1966]
no its designed to be understandable beyond the second rule   ;-)
Gregg
1-May-2009
[1967]
:-)
Maxim
1-May-2009
[1968]
mike: the best tip I can give you is to picture a cursor in your 
head when you type your rules.  parse really is about iterating over 
a series on byte at a time and matching the next expected characetr.
Gregg
1-May-2009
[1969]
My example above may not be exactly what you want. e.g. you might 
want to clear mark-1: in the skip rule.
Maxim
1-May-2009
[1970x6]
whenever it doesn't find what it expects, it "rolls back" to the 
last complete finished rule and tries the next one, if an alternative 
was given.  this is hiercharchical.  so if youre inside the 15th 
depth of parse ans suddenly an unexpected character is encountered, 
you might roll back up to the very first rule!
if that is the first alternative given within the parse rules.
since it only moves forward, its very fast.  in order to do look 
ahead assertion and things like that (which are slow in regexp anyways) 
you must learn a few tricks in order to manually set and retrieve 
the "current" character index.
also note that when there is a "roll back", the cursor and rules 
rolls back together.  (unless you are doing manual cursor manipulation 
tricks)
so if your first rule only matched 2 characters, the second one fails, 
and other alternative is given... the alternative effectively starts 
checking at character 3
even if the second rule failed 15 rules deep at character 3000
Graham
1-May-2009
[1976x2]
I presume that .txt is not going to appear in the 'random' text?? 
 And XXX is really a fixed set of characters?
this is a cheat ...

>> s: {randomXXXrandom.log XXXrandom.txtrandom}
== "randomXXXrandom.log XXXrandom.txtrandom"

>> parse/all reverse s [ to "txt." copy txt to "XXX" ( reverse txt 
) to end ]
== true
>> txt
== "random.txt"