The code below produces ObjectAssignmentError, as far as I understand it's because the sequence defined as seq[Doc] and not as seq[TextDoc].
But aren't such errors supposed to be caught at compile time, by compiler and not leak into runtime?
type
Doc = object of RootObj
TextDoc* = object of Doc
title*: string
text*: string
TodoDoc* = object of Doc
todo*: string
var all_docs*: seq[Doc] = #[]
all_docs.add TextDoc(title: "", text: "")
The reason this isn't caught at compile time is because it's possible in general to add a TextDoc to an array of Doc, as long as they've been declared sensibly, i.e. heterogenous arrays have to be ref objects or Variants (otherwise they can't all fit in the same space)
to put it another way: inheritance means any procedure that accepts a Doc will also accept a TextDoc, including the procedure
proc add(s:var seq[Doc],d:Doc)
Nim supports value semantics, which are important for cache-friendliness, but that freedom can be unsettling to those used to e.g. Java where everything is passed by reference.
with reference semantics the above code runs with no errors:
type
Doc = ref object of RootObj
TextDoc* = ref object of Doc
title*: string
text*: string
TodoDoc* = ref object of Doc
todo*: string
var all_docs*: seq[Doc] = #[]
all_docs.add TextDoc(title: "", text: "blah")
assert TextDoc(all_docs[0]).text == "blah"
Related
I am reading the Groovy closure documentation in https://groovy-lang.org/closures.html#this. Having a question regarding with GString behavior.
Closures in GStrings
The document mentioned the following:
Take the following code:
def x = 1
def gs = "x = ${x}"
assert gs == 'x = 1'
The code behaves as you would expect, but what happens if you add:
x = 2
assert gs == 'x = 2'
You will see that the assert fails! There are two reasons for this:
a GString only evaluates lazily the toString representation of values
the syntax ${x} in a GString does not represent a closure but an expression to $x, evaluated when the GString is created.
In our example, the GString is created with an expression referencing x. When the GString is created, the value of x is 1, so the GString is created with a value of 1. When the assert is triggered, the GString is evaluated and 1 is converted to a String using toString. When we change x to 2, we did change the value of x, but it is a different object, and the GString still references the old one.
A GString will only change its toString representation if the values it references are mutating. If the references change, nothing will happen.
My question is regarding the above-quoted explanation, in the example code, 1 is obviously a value, not a reference type, then if this statement is true, it should update to 2 in the GString right?
The next example listed below I feel also a bit confusing for me (the last part)
why if we mutate Sam to change his name to Lucy, this time the GString is correctly mutated??
I am expecting it won't mutate?? why the behavior is so different in the two examples?
class Person {
String name
String toString() { name }
}
def sam = new Person(name:'Sam')
def lucy = new Person(name:'Lucy')
def p = sam
def gs = "Name: ${p}"
assert gs == 'Name: Sam'
p = Lucy. //if we change p to Lucy
assert gs == 'Name: Sam' // the string still evaluates to Sam because it was the value of p when the GString was created
/* I would expect below to be 'Name: Sam' as well
* if previous example is true. According to the
* explanation mentioned previously.
*/
sam.name = 'Lucy' // so if we mutate Sam to change his name to Lucy
assert gs == 'Name: Lucy' // this time the GString is correctly mutated
Why the comment says 'this time the GString is correctly mutated? In previous comments it just metioned
the string still evaluates to Sam because it was the value of p when the GString was created, the value of p is 'Sam' when the String was created
thus I think it should not change here??
Thanks for kind help.
These two examples explain two different use cases. In the first example, the expression "x = ${x}" creates a GString object that internally stores strings = ['x = '] and values = [1]. You can check internals of this particular GString with println gs.dump():
<org.codehaus.groovy.runtime.GStringImpl#6aa798b strings=[x = , ] values=[1]>
Both objects, a String one in the strings array, and an Integer one in the values array are immutable. (Values are immutable, not arrays.) When the x variable is assigned to a new value, it creates a new object in the memory that is not associated with the 1 stored in the GString.values array. x = 2 is not a mutation. This is new object creation. This is not a Groovy specific thing, this is how Java works. You can try the following pure Java example to see how it works:
List<Integer> list = new ArrayList<>();
Integer number = 2;
list.add(number);
number = 4;
System.out.println(list); // prints: [2]
The use case with a Person class is different. Here you can see how mutation of an object works. When you change sam.name to Lucy, you mutate an internal stage of an object stored in the GString.values array. If you, instead, create a new object and assigned it to sam variable (e.g. sam = new Person(name:"Adam")), it would not affect internals of the existing GString object. The object that was stored internally in the GString did not mutate. The variable sam in this case just refers to a different object in the memory. When you do sam.name = "Lucy", you mutate the object in the memory, thus GString (which uses a reference to the same object) sees this change. It is similar to the following plain Java use case:
List<List<Integer>> list2 = new ArrayList<>();
List<Integer> nested = new ArrayList<>();
nested.add(1);
list2.add(nested);
System.out.println(list2); // prints: [[1]]
nested.add(3);
System.out.println(list2); // prints: [[1,3]]
nested = new ArrayList<>();
System.out.println(list2); // prints: [[1,3]]
You can see that list2 stores the reference to the object in the memory represented by nested variable at the time when nested was added to list2. When you mutated nested list by adding new numbers to it, those changes are reflected in list2, because you mutate an object in the memory that list2 has access to. But when you override nested with a new list, you create a new object, and list2 has no connection with this new object in the memory. You could add integers to this new nested list and list2 won't be affected - it stores a reference to a different object in the memory. (The object that previously could be referred to using nested variable, but this reference was overridden later in the code with a new object.)
GString in this case behaves similarly to the examples with lists I shown you above. If you mutate the state of the interpolated object (e.g. sam.name, or adding integers to nested list), this change is reflected in the GString.toString() that produces a string when the method is called. (The string that is created uses the current state of values stored in the values internal array.) On the other hand, if you override a variable with a new object (e.g. x = 2, sam = new Person(name:"Adam"), or nested = new ArrayList()), it won't change what GString.toString() method produces, because it still uses an object (or objects) that is stored in the memory, and that was previously associated with the variable name you assigned to a new object.
That's almost the whole story, as you can use a Closure for your GString evaluation, so in place of just using the variable:
def gs = "x = ${x}"
You can use a closure that returns the variable:
def gs = "x = ${-> x}"
This means that the value x is evaluated at the time the GString is changed to a String, so this then works (from the original question)
def x = 1
def gs = "x = ${-> x}"
assert gs == 'x = 1'
x = 2
assert gs == 'x = 2'
Consider a type hierarchy, where the base object is non-generic, but sub-types are:
type
TestBase = ref object of RootObj
DerivedA = ref object of TestBase
DerivedB[T] = ref object of TestBase
field: T
proc testProc(x: TestBase) =
if x of DerivedB: # <= what to do here
echo "it's a B!"
else:
echo "not a B"
Using the of operator like this won't compile, because it expects object types. What does work is e.g. to match for specific types like DerivedB[int], or making the proc itself generic in T, which is meaningless when passing in a DerivedA.
Is there a way to solve this problem generically without resorting to methods and dynamic dispatch?
The easiest solution here is to introduce a dummy base type for all of the generic derived types, with the only purpose of assisting in such checks. Here is an example:
type
TestBase = ref object of RootObj
DerivedA = ref object of TestBase
# I'm using illustrative names here
# You can choose something more sensible
DerivedDetector = ref object of TestBase
DerivedB[T] = ref object of DerivedDetector
field: T
proc testProc(x: TestBase) =
if x of DerivedDetector: # This will be true for all derived types
echo "it's a B!"
else:
echo "not a B"
testProc DerivedB[int](field: 10)
testProc DerivedA()
This solution won't increase the size of the objects and it doesn't introduce any run-time overhead in typical code.
If you can't modify the inheritance hierarchy (it may be part of a third-party library), there is a much more complicated solution based on the getTypeInfo proc from the system module. This proc returns an opaque pointer that can be used as an identifier for the type. You'll have to register all derived types with their identifiers in a hash table (you can do this at the start of the program) and then use that to make run-time checks against the type-info pointers of the input values in the proc.
There are various libraries in nim that return actual objects, rather than references. Sometimes I want an object on the heap (regardless of efficiency) -- for instance when I have a generic procedure that expects a ref to an object.
The only way to construct an IntSet on the heap I have found is:
proc newIntSet() : ref IntSet =
new(result)
assign(result[], initIntSet())
This seems to work, but feels like a hack. I worry if it only seems to work. (Are the structures copied by "assign" properly cleaned up?) Is there a better way? Is there a more generic way that will work with other objects?
Your code is perfectly valid. The resulting reference will be subject to garbage collection as any other referefence.
If you find yourself doing this often, you can define the following makeRef template to get rid of the code repetition:
template makeRef(initExp: typed): expr =
var heapValue = new(type(initExp))
heapValue[] = initExp
heapValue
Here is an example usage:
import typetraits
type Foo = object
str: string
proc createFoo(s: string): Foo =
result.str = s
let x = makeRef createFoo("bar")
let y = makeRef Foo(str: "baz")
echo "x: ", x.type.name, " with x.str = ", x.str
Which will output:
x: ref Foo with x.str = bar
When I declare a String using:
String a = new String("Hello");
2 objects are created. 1 object resides in heap and another in String literal pool.
So when I do:
String b = "Hello";
Is a new object created or is "Hello" from String pool referenced to b?
A new object is created.
Explanation
new String("Hello") creates one object on the heap. It is not stored in the String literal pool. More information here.
String b = "Hello" first wants to reuse String "Hello" from the pool, but there is none. So, it will create a new "Hello" String object in the pool and assign your reference to it.
You can read more about String literals in Java Language Specification 3.10.5.
Test
We can test that the references are pointing to different objects:
String a = new String("Hello");
String b = "Hello";
System.out.println(a == b);
Prints false, as expected.
I am talking about Java language. I have read in many places that
String a = new String("Hello")
creates 2 objects. One is in Heap. Could you please let me know where is the other object created?
I have two statements:
String aStr = new String("ABC");
String bStr = "ABC";
I read in book that in first statement JVM creates two bjects and one reference variable, whereas second statement creates one reference variable and one object.
How is that? When I say new String("ABC") then It's pretty clear that object is created.
Now my question is that for "ABC" value to we do create another object?
Please clarify a bit more here.
Thank you
You will end up with two Strings.
1) the literal "ABC", used to construct aStr and assigned to bStr. The compiler makes sure that this is the same single instance.
2) a newly constructed String aStr (because you forced it to be new'ed, which is really pretty much non-sensical)
Using a string literal will only create a single object for the lifetime of the JVM - or possibly the classloader. (I can't remember the exact details, but it's almost never important.)
That means it's hard to say that the second statement in your code sample really "creates" an object - a certain object has to be present, but if you run the same code in a loop 100 times, it won't create any more objects... whereas the first statement would. (It would require that the object referred to by the "ABC" literal is present and create a new instance on each iteration, by virtue of calling the constructor.)
In particular, if you have:
Object x = "ABC";
Object y = "ABC";
then it's guaranteed (by the language specification) than x and y will refer to the same object. This extends to other constant expressions equal to the same string too:
private static final String A = "a";
Object z = A + "BC"; // x, y and z are still the same reference...
The only time I ever use the String(String) constructor is if I've got a string which may well be backed by a rather larger character array which I don't otherwise need:
String x = readSomeVeryLargeString();
String y = x.substring(5, 10);
String z = new String(y); // Copies the contents
Now if the strings that y and x refer to are eligible for collection but the string that z refers to isn't (e.g. it's passed on to other methods etc) then we don't end up holding all of the original long string in memory, which we would otherwise.