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
commit 96d15e9258
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 .. code-block:: nim
type type
Socket* = object of RootObj Socket* = ref object of RootObj
FHost: int # cannot be accessed from the outside of the module FHost: int # cannot be accessed from the outside of the module
# the `F` prefix is a convention to avoid clashes since # the `F` prefix is a convention to avoid clashes since
# the accessors are named `host` # the accessors are named `host`
@ -134,8 +134,8 @@ different; for this a special setter syntax is needed:
## getter of hostAddr ## getter of hostAddr
s.FHost s.FHost
var var s: Socket
s: Socket new s
s.host = 34 # same as `host=`(s, 34) s.host = 34 # same as `host=`(s, 34)
@ -351,32 +351,32 @@ dispatch.
.. code-block:: nim .. code-block:: nim
type type
Expression = object of RootObj ## abstract base class for an expression Expression = ref object of RootObj ## abstract base class for an expression
Literal = object of Expression Literal = ref object of Expression
x: int x: int
PlusExpr = object of Expression PlusExpr = ref object of Expression
a, b: ref Expression a, b: Expression
method eval(e: ref Expression): int = method eval(e: Expression): int =
# override this base method # override this base method
quit "to override!" quit "to override!"
method eval(e: ref Literal): int = return e.x method eval(e: Literal): int = return e.x
method eval(e: ref PlusExpr): int = method eval(e: PlusExpr): int =
# watch out: relies on dynamic binding # watch out: relies on dynamic binding
result = eval(e.a) + eval(e.b) result = eval(e.a) + eval(e.b)
proc newLit(x: int): ref Literal = proc newLit(x: int): Literal =
new(result) new(result)
result.x = x result.x = x
proc newPlus(a, b: ref Expression): ref PlusExpr = proc newPlus(a, b: Expression): PlusExpr =
new(result) new(result)
result.a = a result.a = a
result.b = b 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 In the example the constructors ``newLit`` and ``newPlus`` are procs
because they should use static binding, but ``eval`` is a method because it because they should use static binding, but ``eval`` is a method because it
@ -387,8 +387,8 @@ dispatching:
.. code-block:: nim .. code-block:: nim
type type
Thing = object of RootObj Thing = ref object of RootObj
Unit = object of Thing Unit = ref object of Thing
x: int x: int
method collide(a, b: Thing) {.inline.} = method collide(a, b: Thing) {.inline.} =
@ -400,8 +400,9 @@ dispatching:
method collide(a: Unit, b: Thing) {.inline.} = method collide(a: Unit, b: Thing) {.inline.} =
echo "2" echo "2"
var var a, b: Unit
a, b: Unit new a
new b
collide(a, b) # output: 2 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 name*: string # the * means that `name` is accessible from other modules
age: int # no * means that the field is hidden 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 id: int # with an id field
var var

View file

@ -56,11 +56,11 @@ Objects have access to their type at runtime. There is an
.. code-block:: nim .. code-block:: nim
type type
Person = object of RootObj Person = ref object of RootObj
name*: string # the * means that `name` is accessible from other modules name*: string # the * means that `name` is accessible from other modules
age: int # no * means that the field is hidden from other modules age: int # no * means that the field is hidden from other modules
Student = object of Person # Student inherits from Person Student = ref object of Person # Student inherits from Person
id: int # with an id field id: int # with an id field
var var
@ -69,6 +69,7 @@ Objects have access to their type at runtime. There is an
assert(student of Student) # is true assert(student of Student) # is true
# object construction: # object construction:
student = Student(name: "Anton", age: 5, id: 2) student = Student(name: "Anton", age: 5, id: 2)
echo student[]
Object fields that should be visible from outside the defining module have to Object fields that should be visible from outside the defining module have to
be marked by ``*``. In contrast to tuples, different object types are 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 to introduce new object roots apart from ``system.RootObj``. (This is used
in the GTK wrapper for instance.) 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 **Note**: Composition (*has-a* relation) is often preferable to inheritance
(*is-a* relation) for simple code reuse. Since objects are value types in (*is-a* relation) for simple code reuse. Since objects are value types in
@ -228,7 +232,7 @@ is needed:
.. code-block:: nim .. code-block:: nim
type type
Socket* = object of RootObj Socket* = ref object of RootObj
FHost: int # cannot be accessed from the outside of the module FHost: int # cannot be accessed from the outside of the module
# the `F` prefix is a convention to avoid clashes since # the `F` prefix is a convention to avoid clashes since
# the accessors are named `host` # the accessors are named `host`
@ -241,8 +245,8 @@ is needed:
## getter of hostAddr ## getter of hostAddr
s.FHost s.FHost
var var s: Socket
s: Socket new s
s.host = 34 # same as `host=`(s, 34) s.host = 34 # same as `host=`(s, 34)
(The example also shows ``inline`` procedures.) (The example also shows ``inline`` procedures.)
@ -313,8 +317,8 @@ dispatching:
.. code-block:: nim .. code-block:: nim
type type
Thing = object of RootObj Thing = ref object of RootObj
Unit = object of Thing Unit = ref object of Thing
x: int x: int
method collide(a, b: Thing) {.inline.} = method collide(a, b: Thing) {.inline.} =
@ -326,8 +330,9 @@ dispatching:
method collide(a: Unit, b: Thing) {.inline.} = method collide(a: Unit, b: Thing) {.inline.} =
echo "2" echo "2"
var var a, b: Unit
a, b: Unit new a
new b
collide(a, b) # output: 2 collide(a, b) # output: 2