Введение, или краткий обзор — различия между версиями

Материал из Deeptown Manual
Перейти к: навигация, поиск
 
(не показаны 35 промежуточных версий 10 участников)
Строка 7: Строка 7:
 
Классический пример программы, выводящей строку "Hello, world!" на экран, на языке K++ выглядит следующим образом:
 
Классический пример программы, выводящей строку "Hello, world!" на экран, на языке K++ выглядит следующим образом:
  
[[Изображение:Kpp1.png]]
+
<source lang="kpp" line="1">
<!-- package hello_world;
+
package hello_world;
+
import std;
+
external console_stream STDOUT;
+
+
export function void main()
+
{
+
    STDOUT.print("Hello, world!\n");
+
}-->
+
+
Как уже [[Модули|отмечалось ранее]], в K++ любая программа или библиотека является модулем. Первая строчка данной программы задает имя модуля, в который будет скомпилирована программа.
+
  
Стандартные типы данных, такие как строки, целые числа, а также класс console_stream, объявлены в модуле std - третья строчка программы подключает этот модуль.
+
export function void main() {
 +
    print("Hello, world!\n");
 +
}
 +
</source>
  
Теперь несколько слов о том, как такая программа будет запущена.
 
  
В первую очередь стоит отметить, что нет никаких стандартов на имя функции main или объекта STDOUT. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные STDIN, STDOUT и STDERR, имеющие тип console_stream, и запускает функцию main, экспортируемую программой.
+
;1: Как уже [[Модули|отмечалось ранее]], в K++ любая программа или библиотека является модулем. Ключевое слово <tt>'''package'''</tt> используется для объявления имени модуля, в который должна быть скомпилирована программа.
  
Если бы мы, скажем, писали бы программу, генерирующую текстуру - никакой функции main в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации.
+
;3-5: Наконец, объявляется функция <tt>main()</tt>, которая вызывает системную функцию <tt>print()</tt> [[Стандартная библиотека Gide|стандартной библиотеки]], передав ей строку "Hello, world!\n" в качестве параметра. Пара символов <tt>'''\n'''</tt> является специальной последовательностью, которая в момент компиляции преобразуется в символ перевода строки.
  
Четвертая строчка программы объявляет глобальную переменную STDOUT, имеющую тип console_stream, как внешнюю - т.е. создаваемую пользователем.
+
: Ключевое слово <tt>'''export'''</tt> говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность [[Функции#Перегрузка функций и операторов|перегружать функции]] с одинаковыми именами, но разными списками параметров (или параметрами разных типов), а так же для реализации [[Пространства имен|пространств имен]].
  
И, наконец, строки 6-9 задают функцию main, которая вызывает метод print объекта STDOUT, передав ему строку "Hello, world!\n" в качестве параметра.
+
<!--
 +
Теперь несколько слов о том, как такая программа будет запущена. В первую очередь стоит отметить, что нет никаких стандартов на имя функции <tt>main()</tt> или объекта ''STDOUT''. На платформе Gide каждая программа является библиотекой, и порядок ее использования полностью определяется пользователем. В данном случае предполагается, что программа будет запускаться при помощи консольной команды '''gide.run''', реализованной в модуле стандартной библиотеки. Эта команда определяет три глобальные переменные ''STDIN'', ''STDOUT'' и ''STDERR'', имеющие тип <tt>console_stream</tt> и запускает функцию <tt>main()</tt>, экспортируемую программой.
  
Ключевое слово export говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность перезагружать функции с одинаковыми именами но разными типами параметров.
+
Если бы мы, скажем, писали программу, генерирующую текстуру — никакой функции <tt>main()</tt> в ней не было бы. Набор экспортируемых ей функций полностью определялся бы требованиями генератора текстур, которые описаны в соответствующей документации. -->
  
 
== Более сложный пример ==
 
== Более сложный пример ==
Строка 38: Строка 31:
 
Вот более сложный пример, демонстрирующий использование переменных и циклов:
 
Вот более сложный пример, демонстрирующий использование переменных и циклов:
  
package sums;
+
<source lang="kpp" line="1">
import std;
+
package sums;
export function void main()
+
{
+
    var ary = [ 1, 2, 3, 4 ];
+
    var sums = new array;
+
    var int i;
+
    sums.push(ary[0]);
+
    for(i = 1; i < ary.size(); ++i)
+
        sums.push(sums[i-1] + ary[i]);
+
}
+
  
Смысл этой программы понятен интуитивно: создается два массива - исходный (ary) и результирующий (sums), и затем массив sums заполняется суммами чисел из массива ary от 0 до текущего индекса i.
+
export function void main() {
 +
    var ary = [ 1, 2, 3, 4 ];
 +
    var sums = new array;
 +
    var int i;
 +
    sums.push(ary[0]);
 +
    for (i = 1; i < ary.size(); ++i)
 +
        sums.push(sums[i-1] + ary[i]);
 +
}
 +
</source>
  
Особое внимание в этом примере следует уделить объявлениям переменных. В строках 5 и 6 объявляются два массива - ary и sums - причем в инструкции var их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной (т.е. выражения, стоящего справа от =).
+
Смысл этой программы понятен интуитивно: создается два массива — исходный (''ary'') и результирующий (''sums''), и затем массив ''sums'' заполняется суммами чисел из массива ''ary'' от 0 до текущего индекса i.
  
Выражения, записанные в квадратных скобках через запятую - это встроенная в K++ конструкция, создающая объект, имеющий тип array (объявленный в стандартной библиотеке) и заполненный соответствующими значениями.
+
;4-5: Особое внимание в этом примере следует уделить объявлениям переменных. Мы видим, что объявляются два [[Стандартные типы данных#Массивы|массива]] — ''ary'' и ''sums'', причем в инструкции <tt>'''var'''</tt> их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной, т.е. выражения, стоящего справа от оператора '<tt>=</tt>'.
  
Оператор new создает экземпляр произвольного класса - здесь мог бы стоять в том числе и пользовательский класс. В данном случае new создает экземпляр класса array.
+
:Выражения, записанные в квадратных скобках через запятую — это встроенная в K++ конструкция, создающая объект, имеющий тип <tt>[[Стандартные типы данных#Массивы|array]]</tt> (объявленный в [[Стандартная библиотека gide|стандартной библиотеке]]) и заполненный соответствующими значениями.
  
Третья инструкция (строка 7) создает переменную типа int. Когда тип указан в самой конструкции var - объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны:
+
:Оператор <tt>'''new'''</tt> создает экземпляр произвольного класса — здесь мог бы стоять, в том числе, и пользовательский класс. В данном случае <tt>'''new'''</tt> создает экземпляр класса <tt>[[Стандартные типы данных#Массивы|array]]</tt>.
  
var sums = new array;
+
;6: Здесь мы создаем переменную типа <tt>[[Стандартные типы данных#Целые числа|int]]</tt>. Когда тип указан в самой конструкции <tt>'''var'''</tt> — объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны:
var sums = [ ];
+
 
var array sums;
+
<source lang="kpp">
 +
var sums = new array;
 +
var sums = [ ];
 +
var array sums;
 +
</source>
  
 
или
 
или
  
var i = 0;
+
<source lang="kpp">
var i = new int;
+
var i = 0;
var int i;
+
var i = new int;
 +
var int i;
 +
</source>
  
Метод push класса array добавляет элемент в конец массива; size - возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит.
+
Метод <tt>push()</tt> класса <tt>array</tt> добавляет элемент в конец массива; <tt>size()</tt> — возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит.
  
 
== Использование блоков ==
 
== Использование блоков ==
  
Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторый связанный (с вызовом) блок кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который возвращает блок.
+
Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторого связанного (с вызовом) блока кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который он возвращает.
  
 
Выглядит это следующим образом:
 
Выглядит это следующим образом:
  
package block_demo;
+
<source lang="kpp" line="1">
import std;
+
package block_demo;
external console_stream STDOUT;
+
 
+
function void times(int i, block b) {
function void times(int i, block b)
+
    for (var n = 0; n < i; n++)
{
+
        b(n);
    var int n;
+
}
    for(n = 0; n < i; ++n)
+
 
        b(n);
+
export function void main() {
}
+
    times(3) { |i| print((i as string) + " "); };
+
    print("\n");
export function void main()
+
}
{
+
</source>
    times(3) { |i| STDOUT.print((i as string) + " "); };
+
    STDOUT.print("\n");
+
}
+
  
 
Результат выполнения программы:
 
Результат выполнения программы:
Строка 99: Строка 94:
 
  0 1 2
 
  0 1 2
  
Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить - в этом случае будет сгенерирован [[Переменные#Динамическая типизация на примере Ruby|динамический код]].
+
Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить в этом случае будет сгенерирован [[Переменные#Динамическая типизация на примере Ruby|динамический код]].
  
В функции main используется специальный синтаксис для вызова функции times: тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр-блок объявлен последним.
+
;4: Обратите внимание на то, что управляющая переменная создается непосредственно по месту использования, то есть в [[Основные синтаксические конструкции#Цикл_for|цикле <tt>'''for'''</tt>]]. Такой подход является предпочтительным по сравнению с подходом, при котором управляющая переменная создается за пределами цикла. Почему это так, будет сказано в отдельном разделе, посвященном циклам.
 +
 
 +
;10:В функции <tt>main()</tt> используется специальный синтаксис для вызова функции <tt>times()</tt>: тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр—блок объявлен последним.
  
 
Можно было бы переписать эту конструкцию так:
 
Можно было бы переписать эту конструкцию так:
  
var b = { |i| STDOUT.print((i as string) + " "); };
+
<source lang="kpp">
times(3,b);
+
var b = { |i| print((i as string) + " "); };
 +
times(3,b);
 +
</source>
  
Параметры блока могут быть перечислены между символами "|" через запятую. В данном случае блок принимает один параметр - номер итерации.
+
Параметры блока могут быть перечислены между символами "|" через запятую. В данном случае блок принимает один параметр номер итерации.
  
 
== Расширение классов ==
 
== Расширение классов ==
Строка 114: Строка 113:
 
Приведенный выше пример можно переписать следующим образом:
 
Приведенный выше пример можно переписать следующим образом:
  
package extend_demo;
+
<source lang="kpp" line="1">
import std;
+
package extend_demo;
external console_stream STDOUT;
+
 
+
extend int {
extend int {
+
    public const function void times(block b) {
    public const function void times(block b)
+
        for (var n = 0; n < this; n++)
    {
+
            b(n);
        var int n;
+
    }
        for(n = 0; n < this; ++n)
+
}
            b(n);
+
 
    }
+
export function void main() {
}
+
    3.times() { |i| print((i as string) + " "); };
+
    print("\n");
export function void main()
+
}
{
+
</source>
    3.times() { |i| STDOUT.print((i as string) + " "); };
+
 
    STDOUT.print("\n");
+
;3-8: Оператор <tt>'''extend'''</tt> расширяет функционал класса — в данном случае класса <tt>[[Стандартные типы данных#Целые числа|int]]</tt>. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу.
}
+
 
 +
: Таким образом, к классу <tt>int</tt>, объявленному в стандартной библиотеке, добавляется метод <tt>times()</tt>, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс <tt>int</tt>, который отвечает за хранение числа).
  
Оператор extend расширяет функционал класса - в данном случае класса int. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу.
+
;11: После такого объявления, в функции <tt>main()</tt> мы используем уже метод <tt>times()</tt> класса <tt>int</tt>: конструкция <tt>3.times()</tt> означает создание объекта 3 класса <tt>int</tt> и вызов у этого объекта метода <tt>times()</tt>.
  
Таким образом, к классу int, объявленному в стандартной библиотеке, добавляется метод times, вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс int, который отвечает за хранение числа).
 
  
После такого объявления, в функции main мы используем уже метод times класса int: конструкция 3.times() означает создание объекта 3 класса int и вызов у этого объекта метода times().
+
'''Примечание:''' Расширение будет работать во всем модуле, а так же во всех модулях, которые импортируют данный модуль.

Текущая версия на 13:43, 13 июля 2013

Содержание


(Введение...)

[править] Здравствуй, мир!

Классический пример программы, выводящей строку "Hello, world!" на экран, на языке K++ выглядит следующим образом:

<source lang="kpp" line="1"> package hello_world;

export function void main() {

   print("Hello, world!\n");

} </source>


1
Как уже отмечалось ранее, в K++ любая программа или библиотека является модулем. Ключевое слово package используется для объявления имени модуля, в который должна быть скомпилирована программа.
3-5
Наконец, объявляется функция main(), которая вызывает системную функцию print() стандартной библиотеки, передав ей строку "Hello, world!\n" в качестве параметра. Пара символов \n является специальной последовательностью, которая в момент компиляции преобразуется в символ перевода строки.
Ключевое слово export говорит о том, что имя функции не следует декорировать. Декорирование имен применяется для того, чтобы дать возможность перегружать функции с одинаковыми именами, но разными списками параметров (или параметрами разных типов), а так же для реализации пространств имен.


[править] Более сложный пример

Вот более сложный пример, демонстрирующий использование переменных и циклов:

<source lang="kpp" line="1"> package sums;

export function void main() {

   var ary = [ 1, 2, 3, 4 ];
   var sums = new array;
   var int i;
   sums.push(ary[0]);
   for (i = 1; i < ary.size(); ++i)
       sums.push(sums[i-1] + ary[i]);

} </source>

Смысл этой программы понятен интуитивно: создается два массива — исходный (ary) и результирующий (sums), и затем массив sums заполняется суммами чисел из массива ary от 0 до текущего индекса i.

4-5
Особое внимание в этом примере следует уделить объявлениям переменных. Мы видим, что объявляются два массиваary и sums, причем в инструкции var их тип никак не указывается. В этом случае работает следующее правило: если при объявлении переменной ее тип не указан, то типом переменной становится тип результата инициализатора переменной, т.е. выражения, стоящего справа от оператора '='.
Выражения, записанные в квадратных скобках через запятую — это встроенная в K++ конструкция, создающая объект, имеющий тип array (объявленный в стандартной библиотеке) и заполненный соответствующими значениями.
Оператор new создает экземпляр произвольного класса — здесь мог бы стоять, в том числе, и пользовательский класс. В данном случае new создает экземпляр класса array.
6
Здесь мы создаем переменную типа int. Когда тип указан в самой конструкции var — объект соответствующего класса создается автоматически. Таким образом, например, следующие объявления эквивалентны:

<source lang="kpp"> var sums = new array; var sums = [ ]; var array sums; </source>

или

<source lang="kpp"> var i = 0; var i = new int; var int i; </source>

Метод push() класса array добавляет элемент в конец массива; size() — возвращает количество элементов массива. Дальнейший код, думаю, объяснять не стоит.

[править] Использование блоков

Подобно языку Ruby, в K++ реализован механизм передачи в качестве параметра функции некоторого связанного (с вызовом) блока кода. Функция затем может вызвать этот блок один или более раз, и воспользоваться результатом, который он возвращает.

Выглядит это следующим образом:

<source lang="kpp" line="1"> package block_demo;

function void times(int i, block b) {

   for (var n = 0; n < i; n++)
       b(n);

}

export function void main() {

   times(3) { |i| print((i as string) + " "); };
   print("\n");

} </source>

Результат выполнения программы:

0 1 2

Данный пример также демонстрирует объявление параметров функции: это делается в стиле языка C. Впрочем, тип параметра функции можно опустить — в этом случае будет сгенерирован динамический код.

4
Обратите внимание на то, что управляющая переменная создается непосредственно по месту использования, то есть в цикле for. Такой подход является предпочтительным по сравнению с подходом, при котором управляющая переменная создается за пределами цикла. Почему это так, будет сказано в отдельном разделе, посвященном циклам.
10
В функции main() используется специальный синтаксис для вызова функции times(): тело блока идет сразу после оператора вызова функции. Такой синтаксис работает только в том случае, если параметр—блок объявлен последним.

Можно было бы переписать эту конструкцию так:

<source lang="kpp"> var b = { |i| print((i as string) + " "); }; times(3,b); </source>

Параметры блока могут быть перечислены между символами "|" через запятую. В данном случае блок принимает один параметр — номер итерации.

[править] Расширение классов

Приведенный выше пример можно переписать следующим образом:

<source lang="kpp" line="1"> package extend_demo;

extend int {

   public const function void times(block b) {
       for (var n = 0; n < this; n++)
           b(n);
   }

}

export function void main() {

   3.times() { |i| print((i as string) + " "); };
   print("\n");

} </source>

3-8
Оператор extend расширяет функционал класса — в данном случае класса int. Его использование аналогично объявлению класса, но объявленные внутри поля, методы и операторы будут добавлены к уже существующему классу.
Таким образом, к классу int, объявленному в стандартной библиотеке, добавляется метод times(), вызывающий связанный блок количество раз, равное текущему числу (не забываем: мы добавляем метод в класс int, который отвечает за хранение числа).
11
После такого объявления, в функции main() мы используем уже метод times() класса int: конструкция 3.times() означает создание объекта 3 класса int и вызов у этого объекта метода times().


Примечание: Расширение будет работать во всем модуле, а так же во всех модулях, которые импортируют данный модуль.

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
информация
документация
Инструменты