Merge pull request #2410 from def-/refobj

Use ref objects with inheritance in Tut2 (fixes #1817)
This commit is contained in:
Andreas Rumpf
2015-03-26 19:46:42 +01:00
3 changed files with 38 additions and 32 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -82,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.)
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
@@ -228,7 +232,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 +245,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 +317,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 +330,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