Содержание


Язык программирования Nimrod

Часть 8. Поддержка объектно-ориентированного программирования (продолжение)

Comments

Серия контента:

Этот контент является частью # из серии # статей: Язык программирования Nimrod

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Язык программирования Nimrod

Следите за выходом новых статей этой серии.

Nimrod - язык программирования, сочетающий в себе наилучшие черты различных стилей программирования. В первой статье был представлен общий обзор этого языка. Во второй статье описываются лексические элементы языка и основные типы данных. Конструкциям управления потоком выполнения посвящена третья статья. В четвёртой статье рассматривались процедуры и операторы языка. Составные и производные типы данных - тема пятой статьи. В шестой статье были описаны модули и макроопределения. В предыдущей (седьмой) статье и в данной, завершающей цикл, подробно рассматривается поддержка объектно-ориентированного программирования.

В предыдущей статье рассматривались объекты языка программирования Nimrod как определяемые программистом новые типы данных и как сущности, используемые в программе (то есть, собственно объекты, как таковые). Но сам по себе объект без инструментов работы с ним малоинтересен и практически бесполезен. В Nimrod такими инструментами являются методы и атрибуты объекта.

1. Методы

В большинстве объектно-ориентированных языков программирования (например, в С++) метод всегда связан с классом. Это решение выглядит вполне логичным, но тем не менее обладает некоторыми небольшими неудобствами. При добавлении метода в класс программисту приходится выполнять достаточно большой объём дополнительной работы по согласованию этого метода с другими членами класса и по сохранению целостности внешнего интерфейса класса. Кроме того, зачастую возникает неоднозначность, связанная с вопросом о принадлежности того или иного метода: например, является ли join методом класса string или методом класса array?

В Nimrod используются так называемые мультиметоды (multi-methods), которые не связываются с классами, то есть с конкретными типами объектов. А отличие мультиметодов от обычных процедур проявляется только в случаях динамического связывания.

1.1. Синтаксис вызова метода

Основная синтаксическая форма вызова метода похожа на вызов обычной процедуры, но с обязательным указанием объекта, к которому применяется данный метод:

имя_метода( объект, аргументы )

Существует также и другая форма, зачастую более удобная и наглядная (в подобных случаях формы синтаксиса, применяемые для удобства, называют "синтаксическим сахаром"):

объект.имя_метода( аргументы )

При отсутствии аргументов пустые круглые скобки можно опустить, например:

obj.len  # для вычисления длины объекта аргументы не требуются

1.2. Универсальность методов

Ещё одним преимуществом методов в Nimrod является их гибкость: их использование не ограничено только объектами, методы могут быть вызваны для любого другого типа данных, как показано в листинге 1.

Листинг 1. Вызов методов для различных объектов и типов данных
echo( "program".len )  # метод len вызывается для строки; то же самое, что len("program")
echo( "cpu".toUpper() )
echo( {'p', 'q', 'r', 's'}.card )
stdout.writeln( "Добрый день" )  # другая форма записи writeln( stdout, "Добрый день" )

Такую форму записи вызова методов часто называют постфиксной синтаксической формой записи.

Благодаря такой универсальности применения методов на Nimrod можно без затруднений писать так называемый "чистый объектно-ориентированный код", пример которого приведён в листинге 2.

Листинг 2. Чистый объектно-ориентированный код
import strutils

stdout.writeln( "Введите список чисел, разделённых пробелами:" )
stdout.write( stdin.readLine.split.each(parseInt).max.`$` )
stdout.writeln( " - наибольшее из введённых чисел" )

2. Атрибуты (свойства)

Как правило, атрибуты (свойства) объекта недоступны извне, и для доступа к ним создаются специальные методы. Но Nimrod устраняет необходимость и в таких специализированных методах, поскольку для этих же целей могут быть использованы обычные процедуры, вызываемые в синтаксической форме обращений к методам объекта. Впрочем, здесь необходимо обратить особое внимание на то, что присваивание значения атрибуту объекта всё же требует специализированной синтаксической формы, как показано в листинге 3. Следует отметить, что в листинге 3 также продемонстрировано использование встроенных (inline) методов, позволяющих снизить накладные расходы, неизбежные при стандартных обращениях к процедурам.

Листинг 3. Методы доступа к атрибутам объекта и встроенные методы
type
  TSocket* = object of TObject
    FHost: string   # К этим двум полям-атрибутам нельзя получить прямой доступ.
    FPort: int      # По соглашению поля-атрибуты начинаются с префикса 'F'
                    # поскольку обычно 'host' и 'port' - методы доступа

proc `port=`*( sock: TSocket, num_val: int ) {.inline.} =
  # метод установки значения номера порта
  sock.FPort = num_val

proc port*( sock: TSocket ): int {.inline.} =
  # метод получения значения номера порта
  return sock.FPort

var
  sock: TSocket

sock.port = 80  # полностью аналогичен вызову `port=`( sock, 80 )

3. Исключения

Рассматривая поддержку ООП в Nimrod, нельзя обойти вниманием такую важную тему, как обработка ошибок с помощью исключений (exceptions), тем более, что здесь исключения представляют собой объекты. По соглашению все типы исключений начинаются с префикса 'E'. В модуле system определена иерархия исключений, которую можно взять за основу и придерживаться её в своих приложениях.

Объекты-исключения должны быть размещены в общем пространстве памяти программы (heap), поскольку время их существования заранее неизвестно.

Существует ещё одно соглашение, касающееся необходимости генерации исключений только в конкретных, недвусмысленных ситуациях. Например, если не удалось открыть файл, то не следует генерировать исключение, так как причина неочевидна: файл может отсутствовать, может быть запрещён доступ к этому файлу, в имени файла или пути к нему могла быть допущена ошибка или опечатка и т.п.

3.1. Ключевое слово raise

Генерация исключения осуществляется с помощью ключевого слова raise, как показано в листинге 4.

Листинг 4. Пример генерации исключения
var
  ENoLib: ref EInvalidLibrary
new(ENoLib)
ENoLib.msg = "невозможно загрузить динамическую библиотеку"
raise ENoLib

Если после ключевого слова raise не указано выражение, то повторно генерируется самое последнее предыдущее исключение.

3.2. Ключевое слово try

Ключевое слово try позволяет организовать обработку потенциально возможных исключений. Пример обработки исключений при выполнении арифметических операций над числовыми данными, считываемыми из файла, показан в листинге 5.

Листинг 5. Обработка исключений при выполнении операций с данными
# Из файла считываются первые три строки, которые должны содержать числовые значения.
# Затем эти числовые значения суммируются, как целые.
import strutils
var
  f: TFile
if open( f, "numeric_data.txt" ):
  try:
    let num1 = readLine(f)
    let num2 = readLine(f)
    let num3 = readLine(f)
    echo( "Итого (общая сумма): ", parseInt(num1) + parseInt(num2) + parseInt(num3) )
  except EOverflow:
    echo( "переполнение при суммировании целых чисел" )
  except EInvalidValue:
    echo( "невозможно преобразовать строку в целое число" )
  except EIO:
    echo( "ошибка при чтении данных из файла" )
  except:
    echo( "Неопознанное исключение" )
    # повторная генерация самого последнего предыдущего исключения
    raise
  finally:
    close(f)

Инструкции после ключевого слова try выполняются до тех пор, пока не будет сгенерировано исключение или до успешного завершения их выполнения. В случае возникновения исключительной ситуации выполняется соответствующая часть exception. Часть except без указания объекта-исключения выполняется, если не обнаружилось соответствие ни одному из перечисленных исключений. В какой-то мере это можно считать аналогом ветви else конструкции if.

Если присутствует часть finally, то она обязательно выполняется после завершения обработки исключений. Любое исключение принимается и обрабатывается в одной из частей exception. Если исключение не обрабатывается, то оно передаётся по стеку вызовов процедур, то есть в этом случае (исключение сгенерировано, но не обработано) оставшаяся часть процедуры, которая не включена в секцию finally, может быть не выполнена.

Заключение

В данной статье было продолжено описание поддержки объектно-ориентированного программирования в языке Nimrod: рассматривались методы, работа с полями-атрибутами (свойствами) объектов и обработка исключений.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source, Linux
ArticleID=856959
ArticleTitle=Язык программирования Nimrod: Часть 8. Поддержка объектно-ориентированного программирования (продолжение)
publish-date=01312013