From 748a7b866f509db8d89a37b30abc5965964ddb07 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 25 Mar 2015 23:38:58 +0100 Subject: [PATCH 1/4] Use ref objects with inheritance in Tut2 (fixes #1817) --- doc/tut2.txt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/tut2.txt b/doc/tut2.txt index 4d30b1445e..f5089566c6 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -56,12 +56,12 @@ Objects have access to their type at runtime. There is an .. code-block:: nim type - Person = object of RootObj + Person = ref object of RootObj name*: string # the * means that `name` is accessible from other modules age: int # no * means that the field is hidden from other modules - Student = object of Person # Student inherits from Person - id: int # with an id field + Student = ref object of Person # Student inherits from Person + id: int # with an id field var student: Student @@ -69,6 +69,7 @@ Objects have access to their type at runtime. There is an assert(student of Student) # is true # object construction: student = Student(name: "Anton", age: 5, id: 2) + echo student[] Object fields that should be visible from outside the defining module have to be marked by ``*``. In contrast to tuples, different object types are @@ -228,7 +229,7 @@ is needed: .. code-block:: nim type - Socket* = object of RootObj + Socket* = ref object of RootObj FHost: int # cannot be accessed from the outside of the module # the `F` prefix is a convention to avoid clashes since # the accessors are named `host` @@ -241,8 +242,8 @@ is needed: ## getter of hostAddr s.FHost - var - s: Socket + var s: Socket + new s s.host = 34 # same as `host=`(s, 34) (The example also shows ``inline`` procedures.) @@ -313,8 +314,8 @@ dispatching: .. code-block:: nim type - Thing = object of RootObj - Unit = object of Thing + Thing = ref object of RootObj + Unit = ref object of Thing x: int method collide(a, b: Thing) {.inline.} = @@ -326,8 +327,9 @@ dispatching: method collide(a: Unit, b: Thing) {.inline.} = echo "2" - var - a, b: Unit + var a, b: Unit + new a + new b collide(a, b) # output: 2 From 91708bb21dfea35e178186f8820c7972d3832a67 Mon Sep 17 00:00:00 2001 From: def Date: Thu, 26 Mar 2015 15:59:26 +0100 Subject: [PATCH 2/4] Add explanation why we use ref objects --- doc/tut2.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/tut2.txt b/doc/tut2.txt index f5089566c6..7440036850 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -83,6 +83,9 @@ no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma to introduce new object roots apart from ``system.RootObj``. (This is used in the GTK wrapper for instance.) +We always use ref objects for inheritance in this tutorial. When you store a +non-ref object in a variable of a parent type, the additional fields are cut +off. **Note**: Composition (*has-a* relation) is often preferable to inheritance (*is-a* relation) for simple code reuse. Since objects are value types in From 91ed170523093c17119af674666263ff0ab69b7b Mon Sep 17 00:00:00 2001 From: def Date: Thu, 26 Mar 2015 18:08:58 +0100 Subject: [PATCH 3/4] Rework explanation a bit (thanks flaviu) --- doc/tut2.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/tut2.txt b/doc/tut2.txt index 7440036850..e1ac200741 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -83,9 +83,9 @@ no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma to introduce new object roots apart from ``system.RootObj``. (This is used in the GTK wrapper for instance.) -We always use ref objects for inheritance in this tutorial. When you store a -non-ref object in a variable of a parent type, the additional fields are cut -off. +Ref objects should be used whenever inheritance is used. It isn't strictly +necessary, but with non-ref objects assignments such as ``let person: Person = +Student(id: 123)`` will truncate subclass fields. **Note**: Composition (*has-a* relation) is often preferable to inheritance (*is-a* relation) for simple code reuse. Since objects are value types in From f8472402d501126122780c7e998516fd6863bbd3 Mon Sep 17 00:00:00 2001 From: def Date: Thu, 26 Mar 2015 18:14:18 +0100 Subject: [PATCH 4/4] Also use ref objects with inheritance in manual --- doc/manual/procs.txt | 43 ++++++++++++++++++++++--------------------- doc/manual/types.txt | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt index 9b04bf518b..9de984ecf0 100644 --- a/doc/manual/procs.txt +++ b/doc/manual/procs.txt @@ -121,7 +121,7 @@ different; for this a special setter syntax is needed: .. code-block:: nim type - Socket* = object of RootObj + Socket* = ref object of RootObj FHost: int # cannot be accessed from the outside of the module # the `F` prefix is a convention to avoid clashes since # the accessors are named `host` @@ -134,8 +134,8 @@ different; for this a special setter syntax is needed: ## getter of hostAddr s.FHost - var - s: Socket + var s: Socket + new s s.host = 34 # same as `host=`(s, 34) @@ -351,32 +351,32 @@ dispatch. .. code-block:: nim type - Expression = object of RootObj ## abstract base class for an expression - Literal = object of Expression + Expression = ref object of RootObj ## abstract base class for an expression + Literal = ref object of Expression x: int - PlusExpr = object of Expression - a, b: ref Expression - - method eval(e: ref Expression): int = + PlusExpr = ref object of Expression + a, b: Expression + + method eval(e: Expression): int = # override this base method quit "to override!" - method eval(e: ref Literal): int = return e.x - - method eval(e: ref PlusExpr): int = + method eval(e: Literal): int = return e.x + + method eval(e: PlusExpr): int = # watch out: relies on dynamic binding result = eval(e.a) + eval(e.b) - proc newLit(x: int): ref Literal = + proc newLit(x: int): Literal = new(result) result.x = x - - proc newPlus(a, b: ref Expression): ref PlusExpr = + + proc newPlus(a, b: Expression): PlusExpr = new(result) result.a = a result.b = b - - echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) + +echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) In the example the constructors ``newLit`` and ``newPlus`` are procs because they should use static binding, but ``eval`` is a method because it @@ -387,8 +387,8 @@ dispatching: .. code-block:: nim type - Thing = object of RootObj - Unit = object of Thing + Thing = ref object of RootObj + Unit = ref object of Thing x: int method collide(a, b: Thing) {.inline.} = @@ -400,8 +400,9 @@ dispatching: method collide(a: Unit, b: Thing) {.inline.} = echo "2" - var - a, b: Unit + var a, b: Unit + new a + new b collide(a, b) # output: 2 diff --git a/doc/manual/types.txt b/doc/manual/types.txt index c78984db80..e9d33045b1 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -568,7 +568,7 @@ the ``of`` operator can be used to determine the object's type. name*: string # the * means that `name` is accessible from other modules age: int # no * means that the field is hidden - Student = object of Person # a student is a person + Student = ref object of Person # a student is a person id: int # with an id field var