Behaviour of clear function on dart List - dart

void main() {
int a=4;
var b=a;
var c=[1,2,3];
var d=c;
b.truncate();
d.clear();
print("$a,$b,$c,$d");
}
Output
4,4,[],[]
Anyone please explain it.
Why it is clearing c also?

Everything you can place in a variable is an object, and every object is an instance of a class. Even numbers, functions, and null are objects. All objects inherit from the Object class.
When you assign an object to another, dart makes a copy by reference, unlike for basic types (int, bool etc.) where it only copies the current value.
When you use var d=c d will point (refer) to whatever value stored at the memory address of list c. Any change in either c or d will impact both of them.
If you want to work with a deep copy (meaning that d takes values from c and then exists on its own) you will have to use ... : var d = [...c];
If you are interested about these behaviors I would suggest that you read more about "by reference or by value" and about pointers in C language.

On equating the 2 lists ,changes in one list will be reflectd in the other too. If you want the same values in d also then rather then equating them you can do:-
d.addAll(c);

Dart variables do not hold objects, they hold references to objects.
In object oriented programming, objects have identity. An object can be distinguished from a different object which otherwise has the same state (using the identical function, which checks whether two object references reference the same object). Having identity is why you can change an object's state - the object will maintain that change over time because the object exists over time. Objects exist independently of whether there are variables referencing them.
Two different variables can hold references to the same object.
That's what's happening here. The c and d variables reference the same single list object, and the clear method on lists change the state of the existing object, it doesn't create a new object.
Consider this:
void main() {
num a = 4.4; // Bind `a` to (a reference to) the double `4.4`
num b = a; // Bind `b` to the same (reference) value as `a`.
var c = [1,2,3]; // Bind `c` to (a reference to) a new list (call it List#1).
var d = c; // Bind `d` to the same (reference) value as `c` (List#1).
print(identical(a, b)); // "true". It's the same (reference) value.
b.truncate();
print(b); // "4.4", `truncate` doesn't change the object, it returns a new one.
b = b.truncate(); // Changes the (reference) value bound to `b`
print(identical(a, b)); // "false"
print(b); // "4"
print(a); // "4.4" - didn't change the (reference) value bound to `a`
print(identical(c, d)); // "true". It's the same object (reference).
d.clear();
print(identical(c, d)); // "true". It's still the same object (reference).
print(d); // "[]" - clear *changed* the (referenced) object's state.
print(c); // "[]" - and that *object* is now an empty list.
d = []; // Create (a reference to) a new empty list and bind `d` to it.
print("$c - $d"); // "[] - []". Now (references to) different empty lists
c.add(1);
print("$c - $d"); // "[1] - []". Now (references to) different lists
}
Technically: Objects exist and have identity independently of everything else. Objects are not values in the language in the sense that expressions evaluate to values and variables store values (they're neither expressible, denotable, nor storable). Instead references to objects are values that expressions evaluate to and which can be stored in variables. When you create a new object using new Foo(), the object starts existing, and the expression evaluates to a reference to the new object.
In most cases, this distinction between objects and references isn't important enough for people to say "reference to object" all the time, so most of the time the "reference to" is implicit when we talk about "objects". It's still necessary to understand the underlying distinction because it explains what happens when two variables contain references to the same object (aka. "aliasing"), and that an object referenced by a variable can change state even when accessed through a different variable.

The answer is simple d and c have same List Object. So if you do anything on d or c, it will affect the same List Object.
void main() {
int a=4;
var b=a;
var c=[1,2,3];
var d=c;
b.truncate();
d.clear(); // because d and c have same list object
d.add(8); //even if you add anything it will go to the same object
print("$a,$b,$c,$d");
}
This will be the output if you add a item to List d.
OUTPUT:
4,4,[8],[8]
If you want two List Object then use this :
var c = [1, 2, 3];
var d = List.from(c);
Now if you clear List d :
d.clear();
Only List d will get cleared as List c have another List Object
OUTPUT :
4,4,[1, 2, 3],[]

Related

Dart - Pass by value for int but reference for list?

In Dart, looking at the code below, does it 'pass by reference' for list and 'pass by value' for integers? If that's the case, what type of data will be passed by reference/value? If that isn't the case, what's the issue that causes such output?
void main() {
var foo = ['a','b'];
var bar = foo;
bar.add('c');
print(aoo); // [a, b, c]
print(bar); // [a, b, c]
var a = 3;
int b = a;
b += 2;
print(a); // 3
print(b); // 5
}
The question your asking can be answered by looking at the difference between a value and a reference type.
Dart like almost every other programming langue makes a distinction between the two. The reason for this is that you divide memory into the so called stack and the heap. The stack is fast but very limited so it cannot hold that much data. (By the way, if you have too much data stored in the stack you will get a Stack Overflow exception which is where the name of this site comes from ;) ). The heap on the other hand is slower but can hold nearly infinite data.
This is why you have value and reference types. The value types are all your primitive data types (in Dart all the data type that are written small like int, bool, double and so on). Their values are small enough to be stored directly in the stack. On the other hand you have all the other data types that may potentially be much bigger so they cannot be stored in the stack. This is why all the other so called reference types are basically stored in the heap and only an address or a reference is stored in the stack.
So when you are setting the reference type bar to foo you're essentially just copying the storage address from bar to foo. Therefore if you change the data stored under that reference it seems like your changing both values because both have the same reference. In contrast when you say b = a your not transferring the reference but the actual value instead so it is not effected if you make any changes to the original value.
I really hope I could help answering your question :)
In Dart, all type are reference types. All parameters are passed by value. The "value" of a reference type is its reference. (That's why it's possible to have two variables containing the "same object" - there is only one object, but both variables contain references to that object). You never ever make a copy of an object just by passing the reference around.
Dart does not have "pass by reference" where you pass a variable as an argument (so the called function can change the value bound to the variable, like C#'s ref parameters).
Dart does not have primitive types, at all. However (big caveat), numbers are always (pretending to be) canonicalized, so there is only ever one 1 object in the program. You can't create a different 1 object. In a way it acts similarly to other languages' primitive types, but it isn't one. You can use int as a type argument to List<int>, unlike in Java where you need to do List<Integer>, you can ask about the identity of an int like identical(1, 2), and you can call methods on integers like 1.hashCode.
If you want to clone or copy a list
var foo = ['a', 'b'];
var bar = [...foo];
bar.add('c');
print(bar); // [a, b, c]
print(foo); // [a, b]
var bar_two = []; //or init an empty list
bar_two.addAll([...bar]);
print(bar_two); // [a, b, c]
Reference link
Clone a List, Map or Set in Dart

Memory usage of pass by value vs. pass by reference

For the past few days am trying to learn if pass by value and pass by reference impact the memory differently. Googling this query, people kept repeating themselves about a copy being created in terms of pass by value and how the original value is affected in terms pass by reference. But I was wondering if someone could zero in on the memory part.
This question actually depends heavily on the particular language as some allow you to be explicit and define when you want to pass a variable by value and when by reference and some do it always the same way for different types of variables.
A quite popular type of behavior is to use passing by value (by default) for simple times: like int, string, long, float, double, bool etc.
Let us show the memory impact on a theoretical language:
int $myVariable = 5;
at this moment you have created a one variable in memory which takes the size required to store an integer (let us say 32 bits).
Now you want to pass it to a function:
function someFunction(int parameter)
{
printOnScreen(parameter);
}
so your code would look like:
function someFunction(int $parameter)
{
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
...rest of the code //Position C
Since simple types are passed by value the value is copied in memory to another storage place - therefore:
during Position A you have memory occupied by ONE int (with value 5);
during Position B you have memory occupied by TWO ints (with values of 5) as your $myVariable was copied in memory
during Position C you have again memory occupied by ONE int (with value of 5) as the second one was already destroyed as it was needed only for the time of execution of the function
This has some other implications: modifications on a variable passed by value DO NOT affect the original variable - for example:
function someFunction(int $parameter)
{
$parameter = $parameter + 1;
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
During position A you set value of 5 under variable $myVariable.
During position B you pass it BY VALUE to a function which adds 1 to your passed value. YET since it was a simple type, passed by value, it actually operates on a LOCAL variable, a COPY of your variable. Therefore position C will again write just 5 (your original variable as it was not modified).
Some languages allow you to be explicit and inform that you want to pass a reference and not the value itself using a special operator -for example &. So let us again follow the same example but with explicit info that we want a reference (in function's arguments
- note the &):
function someFunction(int &$parameter)
{
$parameter = $parameter + 1;
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
This time operation and memory implications will be different.
During Position A an int is created (every variable is always consisted of two elements: place in memory and a pointer, an identifier which place is it. For ease of the process let us say that pointer is always one byte). So whenever you create a variable you actually create two things:
reserved place in memory for the VALUE (in this case 32 bits as it was an int)
pointer (8 bits [1 byte])
Now during position B, the function expects A POINTER to a memory place. Which means that it will locally, for itself create only a copy of the pointer (1 byte) and not copy the actual reserved place as the new pointer WILLL POINT to the same place as the original one. This means that during operation of the function you have:
TWO POINTERS to an int in memory
ONE place reserved for VALUE of the int
Both of those pointer POINT to the same VALUE
Which means that any modification of the value will affect both.
So looking at the same example position C will not print out also 6 as inside the function we have modified the value under the SAME POINTER as $myVariable.
For COMPLEX TYPES (objects) the default action in most programming environments is to pass the reference (pointer).
So for example - if you have a class:
class Person {
public string $name;
}
and create an instance of it and set a value:
$john = new Person();
$john->name = "John Malkovic";
and later pass it to a function:
function printName(Person $instanceOfPerson)
{
printOnScreen($instanceOfPerson);
}
in terms of memory it will again create only a new POINTER in memory (1 byte) which points to the same value. So having a code like this:
function printName(Person $instanceOfPerson)
{
printOnScreen($instanceOfPerson);
}
$john = new Person(); // position A
printName($john); // position B
...rest of the code // position C
during position A you have: 1 Person (which means 1 pointer [1 byte] to a place in memory which has size to store an object of class person)
during position B you have: 2 pointers [2 bytes] but STILL one place in memory to store an object of class person's value [instance]
during position C you have again situation from position A
I hope that this clarifies the topic for you - generally there is more to cover and what I have mentioned above is just a general explanation.
Pass-by-value and pass-by-reference are language semantics concepts; they don't imply anything about the implementation. Usually, languages that have pass-by-reference implement it by passing a pointer by value, and then when you read or write to the variable inside the function, the compiler translates it into reading or writing from a dereference of the pointer. So you can imagine, for example, if you have a function that takes a parameter by reference in C++:
struct Foo { int x; }
void bar(Foo &f) {
f.x = 42;
}
Foo a;
bar(a);
it is really syntactic sugar for something like:
struct Foo { int x; }
void bar(Foo *f_ptr) {
(*f_ptr).x = 42;
}
Foo a;
bar(&a);
And so passing by reference has the same cost as passing a pointer by value, which does involve a "copy", but it's the copy of a pointer, which is a few bytes, regardless of the size of the thing pointed to.
When you talk about pass-by-value doing a "copy", that doesn't really tell you much unless you know what exactly the variable or value passed represents in the language. For example, Java only has pass-by-value. But every type in Java is either a primitive type or a reference type, and the values of reference types are "reference", i.e. pointers to objects. So you can never have a value in Java (what a variable holds or what an expression evaluates to) which "is" an "object"; objects in Java can only be manipulated through these "references" (pointers to objects). So when you ask the cost of passing a object in Java, it's actually wrong because you cannot "pass" an object in Java; you can only pass references (pointers to objects), and the copy the happens for pass-by-value, is the copy of the pointer, which is a few bytes.
So the only case where you would actually copy a big structure when passing, is if you have a language where objects or structs are values directly (not behind a reference), and you do pass-by-reference of that object/struct type. So for example, in C++, you can have objects which are values directly, or you can have pointers to them, and you can pass them by value or by reference:
struct Foo { int x; }
void bar1(Foo f1) { } // pass Foo by value; this copies the entire size of Foo
void bar2(Foo *f2) { } // pass pointer by value; this copies the size of a pointer
void bar3(Foo &f3) { } // pass Foo by reference; this copies the size of a pointer
void bar4(Foo *&f4) { } // pass pointer by reference; this copies the size of a pointer
(Of course, each of those have different semantic meanings; for example, the last one allows the code inside the function to modify the pointer variable passed to point to somewhere else. But if you are concerned about the amount copied. Only the first one is different. In Java, effectively only the second one is possible.)

defining a tuple data type of unknown length in Rascal

I was curious to know if one could define a data type that we know, should be a tuple, but whose length (or number of elements is indeterminable) currently. The application is as follows:
//I want to declare a data type, one of whose argument is a tuple,
public data MyType=fromListCartesianProduct(tuple<?> product)
//Later I want to instantiate a MyType data by using taking List-CartesianProduct
//instantiate some MyType data
foreach(aTuple in [1,2,3]*["a","b"])
someArr[i]=fromListCartesianProduct(aTuple)
The salient observation is that the number of elements in aTuple is indeterminable while declaring "MyType". Can I still declare such a type in a rascal script?
As an alternate, I would declare MyType as:
public data MyType=fromListCartesianProduct(list[] product)
and convert each tuple from taking the cartesian product into a list before constructing the specific instances. For reasons of clarity and others, I would like to define MyType as I previously did.
In principe the answer is no. Tuples have fixed length and we do not (yet) have row polymorphism.
Having said that, data constructors do support different kinds of polymorphism which might help:
row polymorphism using keyword parameters, you can always add more keyword parameters to a data-type, as in
data MyType = myCons(int j = 0); // initial decl
data MyType(int k = 1); // extension with another field
overloading, you can always add more constructors with more parameters
data MyType = f(int i); // initial declaration
data MyType = f(int i, int j); // overloaded declaration with more fields
You might use the make function from Type to dynamically construct such constructors based on argument lists. At the risk of run-time type exceptions of course.
Another way of dealing with data of unpredictable type is to go up one level in the type hierarchy (let it be value), and later pattern match your way out again:
list[value] myListRelationOfUnknownType = ...;
for (<int i, int j> <- myListRelationOfUnknownType)
println("printing only pairs of ints: <i> - <j>");
for (<int i, int j, int k> <- myListRelationOfUnknownType)
println("printing only the triples of ints: <i> - <j> - <k>");
That's a statically more safe way.

lua_unref on object being used in Lua

In the Lua manual we read:
A reference is a unique integer key.
As long as you do not manually add
integer keys into table t, luaL_ref
ensures the uniqueness of the key it
returns. You can retrieve an object
referred by reference r by calling
lua_rawgeti(L, t, r). Function
luaL_unref frees a reference and its
associated object.
Suppose I create a reference to an object, push it onto the API stack, save it under a global variable, and then call luaL_unref.... does it get freed despite being pointed to in Lua?
Example code:
lua_newtable( L );
int index = luaL_ref( L, LUA_REGISTRYINDEX );
lua_rawgeti( L, LUA_REGISTRYINDEX, index );
lua_setglobal( L, "test" );
luaL_unref( L, LUA_REGISTRYINDEX, index );
lua_getglobal( L, "test" ); // ...?
It would be.
Lua Registry is merely a table. No magic here.
So, your code is roughly equivalent to following (with exception of how lua_ref works with indices):
local t = { }
local index = #_R + 1 -- Assume that fictional _R is registry
_R[index] = t
_G["test"] = t -- Non-fictional _G is a global environment
_R[index] = nil
Also, note that your example does not make much sense. (I assume that it is oversimplified.) You don't need to put table into a registry before saving it as a global variable.
For your "unreferenced" table to be destroyed, you need GC to kick in. It cannot kick in between lua_newtable and lua_setglobal, if you call them one after another without returning control to Lua inbetween. Until you return control to Lua, your table is "referenced" in the Lua stack.
No, it is not explicitly freed.
I think there may be some confusion between the question and the previous answer.
The luaL_unref function merely unreferences the object, it does not actually perform a free operation. So if a variable still references the object it remains alive and is not freed.
The problem is with the wording of the reference. The associated object is "freed from the registry" but it is not "freed from the memory system".

Linked-list representation of disjoint sets - omission in Intro to Algorithms text?

Having had success with my last CLRS question, here's another:
In Introduction to Algorithms, Second Edition, p. 501-502, a linked-list representation of disjoint sets is described, wherein each list member the following three fields are maintained:
set member
pointer to next object
pointer back to first object (the set representative).
Although linked lists could be implemented by using only a single "Link" object type, the textbook shows an auxiliary "Linked List" object that contains a pointer to the "head" link and the "tail" link. Having a pointer to the "tail" facilitates the Union(x, y) operation, so that one need not traverse all of the links in a larger set x in order to start appending the links of the smaller set y to it.
However, to obtain a reference to the tail link, it would seem that each link object needs to maintain a fourth field: a reference to the Linked List auxiliary object itself. In that case, why not drop the Linked List object entirely and use that fourth field to point directly to the tail?
Would you consider this an omission in the text?
I just opened the text and the textbook description seems fine to me.
From what I understand the data-structure is something like:
struct Set {
LinkedListObject * head;
LinkedListObject * tail;
};
struct LinkedListObject {
Value set_member;
Set *representative;
LinkedListObject * next;
};
The textbook does not talk of any "auxillary" linked list structure in the book I have (second edition). Can you post the relevant paragraph?
Doing a Union would be something like:
// No error checks.
Set * Union(Set *x, Set *y) {
x->tail->next = y->head;
x->tail = y->tail;
LinkedListObject *tmp = y->head;
while (tmp) {
tmp->representative = x;
tmp = tmp->next;
}
return x;
}
why not drop the Linked List object entirely and use that fourth field to point directly to the tail?
An insight can be taken from path compression. There all the elements are supposed to point to head of list. If it doesn't happen then the find-set operation does that (by changing p[x] and returning that). You talk similarly of tail. So if such function is implemented only then can we use that.

Resources