| Factor Fun (Part 2) » |
Attack Of The Clone
Hi everyone, it has been a bit crazy over here so I didn't have time to blog for a while
.
This article will cover the word clone and its uses and why it exists. clone is used very often and it is good to know what it does.
eq?
Before we start, I want to introduce you to another Factor word called eq?. This word checks if 2 elements on the stack point to the same data (if the stack elements reference the same object). In Factor, when we say:
"123" dup eq?
the result is t, which indicates that dup makes a copy of the reference to the "123" object, so on the stack you have 2 references which point to the string "123".
Data Allocation In Words
In Factor, a word allocates storage for its data and always returns the same reference to the data. For example:
: foo ( -- x )
V{ } ;
allocates storage for the empty vector, and when foo is called, it will always refer to that vector instance. To test this, here is a little code example:
3 foo push ! add a new element to the vector defined in word foo foo . ! print the contents of the vector in foo
The above code prints V{ 3 }. So why is this important? Because if you don't know about the effects of defining data inside words, it can lead to some bugs that are hard to solve.
Introducing clone
Ok, now how do i get a new instance of V{ } every time I call foo? We use the clone word. So we can change our
foo word as follows:
: foo ( -- x )
V{ } clone ;
now if we execute the following code again:
3 foo push ! add a new element to the vector defined in word foo foo . ! print the contents of the vector in foo
it prints V{ } instead of V{ 3 }, because clone ensures that we always get a new, fresh copy of the vector defined in foo. clone creates a new instance of an object only if the object being cloned is a mutable object (its value can be changed). If the object being cloned is immutable (its value cannot be changed) then clone does nothing.
Factor Fun (part 2)
This article relates to the Factor Fun (part 2) post. The code in it suffers from not using clone in the right places. I have also changed the code a bit because there were some improvements that could be made (thanks slava, erg). So the updated code looks like this:
USING: new-slots accessors math io prettyprint combinators.cleave ;
! we are using NEW-SLOTS for this program because they will be replacing the old-style
! slots
! create a tuple to hold information for each room
TUPLE: room name start-num end-num files ;
C: <room> room
: show-room-info ( tuple -- )
[ files>> ] [ name>> ] bi
"Files for room [" swap "]:" 3append print
[ . ] each ;
: sort-files ( seq -- )
! seq is a sequence of file numbers that need to be put back in their place.
! This word then calculates what files go to what room and displays the output.
! ---
V{ } clone
"A" 1 20000 V{ } clone <room> add
"B" 20001 40000 V{ } clone <room> add
"C" 40001 70000 V{ } clone <room> add
[
over
[
dup pick [ start-num>> ] [ end-num>> ] bi between?
[ over files>> push ] [ drop ] if
] each
show-room-info
] each drop ;
Notice the clone words that were added. Also I used cleave combinators to remove some stack shuffling and clean up the code a bit. This code could still be made clearer by using curry, but i'm still figuring that out
.
For more info, check out the Factor documentation for Vectors and the clone word.