introduce object before tuple in the tutorials (#10664)
This commit is contained in:
parent
b081eb4d6d
commit
80992c7a12
2 changed files with 106 additions and 35 deletions
116
doc/tut1.rst
116
doc/tut1.rst
|
|
@ -1441,31 +1441,111 @@ string that is "useless" and replace it with "useful".
|
|||
Note: alternate ways of writing this are ``b[^8..^2] = "useful"`` or
|
||||
as ``b[11..b.len-2] = "useful"`` or as ``b[11..<b.len-1] = "useful"``.
|
||||
|
||||
Tuples
|
||||
------
|
||||
Objects
|
||||
-------
|
||||
|
||||
A tuple type defines various named *fields* and an *order* of the fields.
|
||||
The constructor ``()`` can be used to construct tuples. The order of the
|
||||
fields in the constructor must match the order in the tuple's definition.
|
||||
Different tuple-types are *equivalent* if they specify fields of
|
||||
the same type and of the same name in the same order.
|
||||
The default type to pack different values together in a single
|
||||
structure with a name is the object type. An object is a value type,
|
||||
which means that when an object is assigned to a new variable all its
|
||||
components are copied as well.
|
||||
|
||||
The assignment operator for tuples copies each component. The notation
|
||||
``t.field`` is used to access a tuple's field. Another notation is
|
||||
``t[i]`` to access the ``i``'th field. Here ``i`` must be a constant
|
||||
integer.
|
||||
Each object type ``Foo`` has a constructor ``Foo(field: value, ...)``
|
||||
where all of its fields can be initialized. Unspecified fields will
|
||||
get their default value.
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Person = object
|
||||
name: string
|
||||
age: int
|
||||
|
||||
var person1 = Person(name: "Peter", age: 30)
|
||||
|
||||
echo person1.name # "Peter"
|
||||
echo person1.age # 30
|
||||
|
||||
var person2 = person1 # copy of person 1
|
||||
|
||||
person2.age += 14
|
||||
|
||||
echo person1.age # 30
|
||||
echo person2.age # 44
|
||||
|
||||
|
||||
# the order may be changed
|
||||
let person3 = Person(age: 12, name: "Quentin")
|
||||
|
||||
# not every member needs to be specified
|
||||
let person4 = Person(age: 3)
|
||||
# unspecified members will be initialized with their default
|
||||
# values. In this case it is the empty string.
|
||||
doAssert person4.name == ""
|
||||
|
||||
|
||||
Object fields that should be visible from outside the defining module have to
|
||||
be marked with ``*``.
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
|
||||
type
|
||||
Person = tuple[name: string, age: int] # type representing a person:
|
||||
# a person consists of a name
|
||||
# and an age
|
||||
Person* = object # the type is visible from other modules
|
||||
name*: string # the field of this type is visible from other modules
|
||||
age*: int
|
||||
|
||||
Tuples
|
||||
------
|
||||
|
||||
Tuples are very much like what you have seen so far from objects. They
|
||||
are value types where the assignment operator copies each component.
|
||||
Unlike object types though, tuple types are structurally typed,
|
||||
meaning different tuple-types are *equivalent* if they specify fields of
|
||||
the same type and of the same name in the same order.
|
||||
|
||||
The constructor ``()`` can be used to construct tuples. The order of the
|
||||
fields in the constructor must match the order in the tuple's
|
||||
definition. But unlike objects, a name for the tuple type may not be
|
||||
used here.
|
||||
|
||||
|
||||
Like the object type the notation ``t.field`` is used to access a
|
||||
tuple's field. Another notation that is not available for objects is
|
||||
``t[i]`` to access the ``i``'th field. Here ``i`` must be a constant
|
||||
integer.
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
type
|
||||
# type representing a person:
|
||||
# A person consists of a name and an age.
|
||||
Person = tuple
|
||||
name: string
|
||||
age: int
|
||||
|
||||
# Alternative syntax for an equivalent type.
|
||||
PersonX = tuple[name: string, age: int]
|
||||
|
||||
# anonymous field syntax
|
||||
PersonY = (string, int)
|
||||
|
||||
var
|
||||
person: Person
|
||||
personX: PersonX
|
||||
personY: PersonY
|
||||
|
||||
person = (name: "Peter", age: 30)
|
||||
# the same, but less readable:
|
||||
# Person and PersonX are equivalent
|
||||
personX = person
|
||||
|
||||
# Create a tuple with anonymous fields:
|
||||
personY = ("Peter", 30)
|
||||
|
||||
# A tuple with anonymous fields is compatible with a tuple that has
|
||||
# field names.
|
||||
person = personY
|
||||
personY = person
|
||||
|
||||
# Usually used for short tuple initialization syntax
|
||||
person = ("Peter", 30)
|
||||
|
||||
echo person.name # "Peter"
|
||||
|
|
@ -1484,10 +1564,6 @@ integer.
|
|||
# --> Error: type mismatch: got (tuple[street: string, number: int])
|
||||
# but expected 'Person'
|
||||
|
||||
# The following works because the field names and types are the same.
|
||||
var teacher: tuple[name: string, age: int] = ("Mark", 42)
|
||||
person = teacher
|
||||
|
||||
Even though you don't need to declare a type for a tuple to use it, tuples
|
||||
created with different field names will be considered different objects despite
|
||||
having the same field types.
|
||||
|
|
@ -1519,6 +1595,8 @@ variables! For example:
|
|||
echo badname
|
||||
echo badext
|
||||
|
||||
Fields of tuples are always public, they don't need to be explicity
|
||||
marked to be exported, unlike for example fields in an object type.
|
||||
|
||||
Reference and pointer types
|
||||
---------------------------
|
||||
|
|
|
|||
25
doc/tut2.rst
25
doc/tut2.rst
|
|
@ -40,18 +40,16 @@ and more efficient code. In particular, preferring composition over inheritance
|
|||
is often the better design.
|
||||
|
||||
|
||||
Objects
|
||||
-------
|
||||
Inheritance
|
||||
-----------
|
||||
|
||||
Like tuples, objects are a means to pack different values together in a
|
||||
structured way. However, objects provide many features that tuples do not:
|
||||
They provide inheritance and information hiding. Because objects encapsulate
|
||||
data, the ``T()`` object constructor should only be used internally and the
|
||||
programmer should provide a proc to initialize the object (this is called
|
||||
a *constructor*).
|
||||
|
||||
Objects have access to their type at runtime. There is an
|
||||
``of`` operator that can be used to check the object's type:
|
||||
Inheritance in Nim is entirely optional. To enable inheritance with
|
||||
runtime type information the object needs to inherit from
|
||||
``RootObj``. This can be done directly, or indirectly by
|
||||
inheriting from an object that inherits from ``RootObj``. Usually
|
||||
types with inheritance are also marked as ``ref`` types even though
|
||||
this isn't strictly enforced. To check at runtime if an object is of a certain
|
||||
type, the ``of`` operator can be used.
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
|
|
@ -71,11 +69,6 @@ Objects have access to their type at runtime. There is an
|
|||
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
|
||||
never *equivalent*. New object types can only be defined within a type
|
||||
section.
|
||||
|
||||
Inheritance is done with the ``object of`` syntax. Multiple inheritance is
|
||||
currently not supported. If an object type has no suitable ancestor, ``RootObj``
|
||||
can be used as its ancestor, but this is only a convention. Objects that have
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue