introduce object before tuple in the tutorials (#10664)

This commit is contained in:
Arne Döring 2019-02-14 22:17:05 +01:00 • committed by Miran
commit 80992c7a12
2 changed files with 106 additions and 35 deletions

View file

@ -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 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"``. 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 default type to pack different values together in a single
The constructor ``()`` can be used to construct tuples. The order of the structure with a name is the object type. An object is a value type,
fields in the constructor must match the order in the tuple's definition. which means that when an object is assigned to a new variable all its
Different tuple-types are *equivalent* if they specify fields of components are copied as well.
the same type and of the same name in the same order.
The assignment operator for tuples copies each component. The notation Each object type ``Foo`` has a constructor ``Foo(field: value, ...)``
``t.field`` is used to access a tuple's field. Another notation is where all of its fields can be initialized. Unspecified fields will
``t[i]`` to access the ``i``'th field. Here ``i`` must be a constant get their default value.
integer.
.. 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 .. code-block:: nim
:test: "nim c $1" :test: "nim c $1"
type type
Person = tuple[name: string, age: int] # type representing a person: Person* = object # the type is visible from other modules
# a person consists of a name name*: string # the field of this type is visible from other modules
# and an age 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 var
person: Person person: Person
personX: PersonX
personY: PersonY
person = (name: "Peter", age: 30) 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) person = ("Peter", 30)
echo person.name # "Peter" echo person.name # "Peter"
@ -1484,10 +1564,6 @@ integer.
# --> Error: type mismatch: got (tuple[street: string, number: int]) # --> Error: type mismatch: got (tuple[street: string, number: int])
# but expected 'Person' # 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 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 created with different field names will be considered different objects despite
having the same field types. having the same field types.
@ -1519,6 +1595,8 @@ variables! For example:
echo badname echo badname
echo badext 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 Reference and pointer types
--------------------------- ---------------------------

View file

@ -40,18 +40,16 @@ and more efficient code. In particular, preferring composition over inheritance
is often the better design. is often the better design.
Objects Inheritance
------- -----------
Like tuples, objects are a means to pack different values together in a Inheritance in Nim is entirely optional. To enable inheritance with
structured way. However, objects provide many features that tuples do not: runtime type information the object needs to inherit from
They provide inheritance and information hiding. Because objects encapsulate ``RootObj``. This can be done directly, or indirectly by
data, the ``T()`` object constructor should only be used internally and the inheriting from an object that inherits from ``RootObj``. Usually
programmer should provide a proc to initialize the object (this is called types with inheritance are also marked as ``ref`` types even though
a *constructor*). this isn't strictly enforced. To check at runtime if an object is of a certain
type, the ``of`` operator can be used.
Objects have access to their type at runtime. There is an
``of`` operator that can be used to check the object's type:
.. code-block:: nim .. code-block:: nim
:test: "nim c $1" :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) student = Student(name: "Anton", age: 5, id: 2)
echo student[] 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 Inheritance is done with the ``object of`` syntax. Multiple inheritance is
currently not supported. If an object type has no suitable ancestor, ``RootObj`` 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 can be used as its ancestor, but this is only a convention. Objects that have