Using References¶
In this chapter we will learn about using references.
This feature is added to the Ring language starting from Ring 1.18.
Contents:
Introduction
Ref()/Reference() function
Refcount() function
Circular references
The Tree class
Linked list
Dependency injection
Passing lists to functions
Ref() and temp. lists
Nested Ref()
Ref() in left side
Ref() and sub lists
Introduction¶
In Ring, Using the Assignment (=) operator copy variables by value. Also, Adding a List/Object to another List create a new copy. To change this behavior, We can use the Ref()/Reference() function. This function doesn’t create the reference directly. It’s a flag setter, And Ring VM will decide when to create the reference.
Once we have more than one reference, No need to use the Ref() again with the same list/object Because Ring will use Copy by Reference with this list/object. If the reference count drop to one again then Ring will change the behavior and will use the default rule (copy lists/objects by value).
In general Ring as a language is designed to reduce references usage. This feature is added to be used in special cases like teaching data structures and implementing specific design patterns.
ref()/reference() function¶
Syntax:
ref(aList|oObject) ---> aList|oObject (Enable Reference Flag) # Short name
reference(aList|oObject) ---> aList|oObject (Enable Reference Flag) # Long name
Example:
aList = [1,2,3]
aListCopy = aList # Copy by Value
aList2 = ref(aList) # Copy by Reference (RC: 2)
aList3 = aList # Copy by Reference (RC: 3)
for item in aList
item *= 10
next
? aList3 # 10 20 30
? aListCopy # 1 2 3
aList2 = NULL
aList3 = NULL
aList2 = aList # Copy by Value
for item in aList2
item /= 10
next
? aList # 10 20 30
? aList2 # 1 2 3
Output:
10
20
30
1
2
3
10
20
30
1
2
3
refcount() function¶
Using the refcount() function we can know how many references exist.
Syntax:
refcount(variable) ---> Number (References Count)
Example:
aList = 1:10
aList2 = ref(aList)
? refcount(aList) # 2
? refcount(aList2) # 2
aList3 = aList2
aList4 = aList
aList5 = aList4
? refcount(aList) # 5
? refcount(aList2) # 5
? refcount(aList3) # 5
? refcount(aList4) # 5
? refcount(aList5) # 5
aList5 = NULL
aList4 = []
aList3 = [10]
? refcount(aList) # 2
? refcount(aList2) # 2
Output:
2
2
5
5
5
5
5
2
2
Circular References¶
Using Ref() we can create circular references
Ring VM can detect them and free memory when the variable is deleted.
Example:
aList = [ 10,20,30, ref(aList) ]
? aList[4][1]
? aList[4][4][4][4][4][2]
? refcount(aList)
Output:
10
20
2
The Tree Class¶
The Tree class is a good example about using the Ref() function.
In this class each object contains a group of objects and these objects have a reference to the parent object.
Example:
Class tree
data parent
children = []
func set x
data = x
func value
return data
func add x
children + new tree
nMax = len(children)
children[nMax].parent = ref(self)
children[nMax].data = x
return children[nMax]
func parent
if ! isObject(parent)
raise("This node is the root!")
return
ok
return parent
func print
for x in children
? x.data
x.print()
next
Tip
The Tree class already exist in the StdLib
Linked list¶
The next example demonstrates how to create a linked list using the Ref() function.
Tip
In practice we don’t need to do this since Ring comes with lists
Example:
func main
n1 = new node(:one)
n2 = new node(:two)
n3 = new node(:three)
n4 = new node(:four)
n5 = new node(:five)
n1 { pNext = ref(n2) "No Previous Node" }
n2 { pNext = ref(n3) pPrev = ref(n1) }
n3 { pNext = ref(n4) pPrev = ref(n2) }
n4 { pNext = ref(n5) pPrev = ref(n3) }
n5 { "No Next Node" pPrev = ref(n4) }
n3 {
toTheEnd()
? Copy("=",20)
toTheStart()
}
class node
pPrev pNext
func init value
data = value
func toTheEnd
print()
pCurrent = pNext
while isObject(pCurrent)
pCurrent.print()
pCurrent = pCurrent.pNext
end
func toTheStart
print()
pCurrent = pPrev
while isObject(pCurrent)
pCurrent.print()
pCurrent = pCurrent.pPrev
end
func print
? data
private
data pCurrent
Output:
three
four
five
====================
three
two
one
Dependency injection¶
The next example demonstrates how to apply dependency injection using the Ref() function
Example:
func main
v1 = new MyClass1 v2 = new MyClass2
oCont = new Controller(v1,v2)
v1.value = "one" v2.value = "two"
oCont.test()
v1 = 10 v2 = 20 ? v1 ? v2
oCont.test()
class MyClass1 value func test ? :myclass1
class MyClass2 value func test ? :myclass2
class Controller o1 o2
func init myo1,myo2
o1=ref(myo1) o2=ref(myo2)
func test
o1.test() o2.test()
? o1.value ? o2.value
Output:
myclass1
myclass2
one
two
10
20
myclass1
myclass2
one
two
Passing lists to functions¶
In Ring, when we pass a list/object to a function, This function will have full ownership on the list/object variable.
This means it can delete it and change the variable type.
Example:
func main
? "Hello from Main() function"
aList = [1,2,3]
? aList
sub(aList)
? "Hello from Main() function (Again)"
if ! isList(aList)
? "We don't have a list!"
ok
func sub aList
? "Hello from Sub() function"
aList = NULL
Output:
Hello from Main() function
1
2
3
Hello from Sub() function
Hello from Main() function (Again)
We don't have a list!
Using Ref() function we can change this behavior and pass a reference to the list/object instead of sharing it.
Example:
func main
? "Hello from Main() function"
aList = [1,2,3]
? aList
sub(Ref(aList))
? "Hello from Main() function (Again)"
if ! isList(aList)
? "We don't have a list!"
else
? "We still have our list!"
? aList
ok
func sub aList
? "Hello from Sub() function"
aList = NULL
Output:
Hello from Main() function
1
2
3
Hello from Sub() function
Hello from Main() function (Again)
We still have our list!
1
2
3
Ref() and temp. lists¶
Using Ref() and temp. lists/objects does nothing.
Example:
aList = ref([1,2,3]) # The same as aList = [1,2,3]
? refcount(aList) # 1
aList = ref(1:10) # The same as aList = 1:10
? refcount(aList) # 1
aList = ref(list(10)) # The same as aList = list(10)
? refcount(aList) # 1
myobj = ref(new point) # The same as myobj = new point
? refcount(myobj) # 1
class point x y z
Nested Ref()¶
Since Ref() function is a flag setter, nested Ref() usage is not useful.
Example:
aList = [1,2,3]
aList2 = ref(ref(ref(ref(aList)))) # The same as aList2 = ref(aList)
? refcount(aList) # 2
Ref() in left side¶
Using Ref() in left side of an assignment is not useful and will disable the assignment i.e. will not change the value.
Example:
aList = [1,2,3]
ref(aList) = [4,5]
? aList
Output:
1
2
3
Ref() and sub lists¶
Using Ref() with a sub list will create a strong reference to this sub list
Tip
if the sub list contains other references, we will get weak references to them.
Example:
a = [[ref(a),ref(a),3],[4,5,6]]
? a
b = ref(a[1]) # Get Weak references to References inside a[1]
? b
b = NULL
? a
c = a[1] # Get Strong references to References inside a[1]
? c
c = NULL
? a
? :done
Output:
[...] (RC:3)
[...] (RC:3)
3
4
5
6
[...] (RC:3)
[...] (RC:3)
3
[...] (RC:3)
[...] (RC:3)
3
4
5
6
[...] (RC:5)
[...] (RC:5)
3
[...] (RC:3)
[...] (RC:3)
3
4
5
6
done