Ребят, презентация нового языка программирования ObjectScript
От: unitpoint  
Дата: 25.09.12 21:02
Оценка: 36 (4)
Сколько же существует всяких языков программирования, еще один? Ну можно и так сказать, а можно сказать и по другому: я программист и пишу программы на разных языках программирования для разных задач. В одних языках есть одни плюсы, в других — другие. Вот я и решил предложить свой универсальный язык программирования для множества задач.

ObjectScript — новый объектно-ориентированный язык программирования с открытым исходным кодом. Сами исходники занимают 459 Кб (парсер, компилятор и виртуальная машина) и находятся в двух файлах source\objectscript.h и source\objectscript.cpp. Скачать их можно по прямой ссылке тут. ObjectScript — очень легкий, предназначен для вставки в приложение на C++.

ObjectScript сочетает в себе возможности таких языков, как JavaScript, Lua и PHP. Например, синтаксис в основном взят из JavaScript, множественное присваивание — из Lua, работа со свойствами через перегружаемые методы — из PHP.

Кроме унификации нескольких существующих языков программирования, ObjectScript добавляет также и свои уникальные и полезные фишки.

Далее по тексту я буду показывать код языка ObjectScript в теге для JavaScript, т.к. тега ObjectScript пока несуществует.

Синтаксис

    x = 12;
    y = "Hello World!";

А что если убрать точки с запятыми?

    x = 12
    y = "Hello World!"

ObjectScript автоматически разпознает отдельные выражения (новая строка тут не причем, все можно писать и в одну строчку), поэтому точку с запятой (;) можно не использовать без явной на то необходимости.

Вызовы функций

Привычный синтаксис, который используется в большинстве языках программирования:

    print(5, " differences")

А зачем там собственно запятая?

    print(5 " differences")

Запятые в ObjectScript при перечислении параметров не обязательны. Например, есть в языке такая функции concat, которая соединяет все аргументы в одну строку, тогда игнорируя запятые можно записать вот так:

    var s = concat("name: "name", count: "count", time: "time)

Красиво и понятно! name, count и time — некоторые переменные. Соединение строк конечно же не обязательно делать через эту функция, есть специальный оператор .. (две точки) для конкатенации, но иногда функция concat может быть удобнее, да и быстрее при обработке нескольких параметров.

Иногда в функцию передается только один параметр, например:
    print({firstname:"Ivan", lastname:"Petrov"})

В фигурных скобках задан объект в привычном для JavaScript синтаксисе. Такой синтаксис полностью поддерживается в ObjectScript, но подобный вызов выглядит НЕ очень красиво. А что если убрать круглые скобки?

    print {firstname:"Ivan", lastname:"Petrov"}

Уже симпатичнее?! Эта возможность взята из Lua. Так можно вызывать любые функции и не только с объектом в качестве параметра, например:

    print "Hello World!"

Довольно таки просто и читабильно!

Объекты

Но вернемся к предыдущему примеру. А зачем там собственно запятая в описании объекта? А если без нее?

    print {firstname:"Ivan" lastname:"Petrov"}

Довольно неплохо, ничего лишнего, а еще можно так:

    print {firstname="Ivan" lastname="Petrov"}

Т.е. при формировании пар в объекте (индекс и значение) можно использовать как двоеточие, так и знак равно. Кроме этого, допускается отделение пар запятыми, точкой с запяток (;) или не использовать разделитель вовсе. Следует также отметить, что использование разделяющих символов после конечного значения допускается, например, следующее выращение полностью допустимо в ObjectScript:

    a = {x=1, y=3; "zero" "one", "two" last:7,}

Что полностью эквивалентно привычной в JavaScript-е записи:
    a = {x:1, y:3, 0:"zero", 1:"one", 2:"two", last:7}

В данном примере используются не только ассоциативные значения, но и порядковые с автоматическим индексом, как в масиве. Индекс начинается с нуля. Например:

    print a[1]

выведет one. А что если необходимо в качестве индекса значения использовать выражение, а не константу, легко:

    a = {[2+3]="five" y=3}

Т.е. выражение в квадратных скобках будет вычислено на этапе выполнения программы и результат будет использован в качестве индекса соответствующего значения в объекте. Иначе говоря:

    print a[5]

Выведет five

Порядок значений в объекте сохраняется таким, в каком порядке значения были добавлены в объект (это бывает важно в итерационных процессах, о которых мы поговорим позже).

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

    a = {x=1 y=2}
    b = {[a]="powerful" 7="greate"}
    print b[a]

Выведет powerful, причем это никак не уменьшает скорость доступа к данным объекта и не увеличивает потребление памяти. Иначе говоря, если есть потребность, можно использовать смело.

Масивы

Масивы — это индексные списки. Как и в JavaScript масив можно записать следующим образом:

    a = [10, 20, 30, 40]

Ну в целом все понятно и нормально, единственное, что можно тут упростить — убрать запятые:

    a = [10 20 30 40]

Выглядит даже интересно и полностью валидно для ObjectScript.

Множественное присваивание

ObjectScript полностью поддерживает множественное присваивание и выглядит это следующим образом:

    i, j, k = 0, 1, 3

Переменной i присвоится значение 0, j присвоится 1, k — 3. Интересным следствием множественного присваивания является возможность смены значений в переменых одной строкой:

    i, j = j, i

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

    var test = function(){ return 1, 2 }
    var a, b = test()

Функция test возвращает два значения, в переменную a сохранится 1, а в b — 2. Если затребовать из функции больше значений, чем она возвращает, то количество результатов дополнится пустыми значениями — null

    var a, b, c = test()
    print(a, b, c)

Выведет: 1 2 null

Итераторы

Итераторы позволяют обработать элементы некоторого списка друг за другом по очереди и выполнить какую-то работу с этими элементами. Например, пусть нам нужно обработать элементы объекта и показать их индексы и значения:

    obj = { null awesome=true 12 "excellent" }
    for(k, v in obj){
        print( k " --> " v )
    }

Данная программа выведет:

0 --> null
awesome --> true
1 --> 12
2 --> excellent

Когда компилятор ObjectScript видит for in, он генерит на выходе специальный код, для приведенного выше примера следующий:

    obj = { null awesome=true 12 "excellent" };
    {
        var iter_func = obj.__iter()
        for(var iter_valid;;){
            iter_valid, k, v = iter_func()
            if(!iter_valid) break
            print( k " --> " v )
        }
    }

По-русски говоря для obj вызывается метод __iter, который должен вернуть итерационную функции (для всех стандартных типов эта функция уже есть, но никто не запрещает ее переписать по своему усмотрению):

    var iter_func = obj.__iter()

Затем эта функция вызывается перед каждым шагом итерации:

    iter_valid, k, v = iter_func()

Она должна вернуть первым результатом логическое значение, иначе говоря true, если текущая итерация валидна, а затем любое количество значений, которые ожидает программист от данного процесса итерации. Первый результат функции обрабатывается языком самостоятельно:

    if(!iter_valid) break

Если процесс итерации завершен, то break прерывает цикл.

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

    obj = { null awesome=true 12 "excellent" }
    for(k in obj){
        print k
    }

Это мы говорили об объектах, теперь перейдем к масивам. Итератор масива на ObjectScript выглядит следующим образом:

    Array.__iter = function(){
        var i, self = 0, this
        return function(){
            if(i < #self){
                return true, i, self[i++]
            }
        }
    }

Тут может быть немного сложно, давайте по-порядку. Array — это глобальная переменная, в которой содержится описание функционала для масивов. В С++ это был бы class Array. Когда создается масив, он получает ссылку на объект Array к качестве прототипа. Ее даже можно прочитать из программы следующим образом:

    print [1 2 3].prototype === Array

Выведет true (оператор === это строгое сравнение без преобразования типов аргументов). Но вернемся к нашему примеру. В прототипе Array перегружается функция __iter (как мы помним она вызывается при запуске процесса итерации). А далее начинается хитрая штука под названием замыкание (анг. closure). Да, ObjectScript поддерживает замыкания в полном объеме — это когда любая вложенная функция имеет доступ к локальным переменным всех своих функций-родителей (даже если родители завершили выполнения). В данном случае, нас интересуют переменные i, self.

    var i, self = 0, this

В i сохраняется 0, а в self сохраняется this (это ссылка на текущий объект, в данном случае масив, с которым мы работаем).

    return function(){
        if(i < #self){
            return true, i, self[i++]
        }
    }

Далее возвращается функция, которая будет вызвана при каждом шаге итерации. Эта функция проверяет, не достигли ли мы конца масива (# — это оператор, который возвращает количество элементов), и если все ок, то возвращает true (показывая, что мы в процессе), далее индекс и само значение. При этом сам индекс каждый раз инкрементируется. В противном случае ничего не возвращается, т.е. функция завершается своим естественным путем. Это приводит к тому, что затребованные значения, в том числе iter_valid, принимают null и цикл прекращается по условию:

    if(!iter_valid) break

Имя переменной iter_valid приведено тут только в качестве удобства, реально создается временная переменная, доступ к которой программист не имеет.

В качестве примера давайте сами напишем итератор.

    var range = function(a, b){
        return function(){
            if(a <= b){
                return true, a++
            }
        }
    }
    for(var i in range(10, 13)){
        print( "i = ", i )
    }

Выведется:

    i = 10
    i = 11
    i = 12
    i = 13

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

    Function.__iter = function(){ return this }

Function — это прототип для всех функций, например, там находятся методы call и apply, которые полностью эквивалентны аналогичным в JavaScript.

Объектно-ориентированное программирование (ООП) в ObjectScript

Как можно было бы понять из названия языка, он просто обязан быть объектно ориентированным и поддерживает ООП во всей своей красе.

Опишем класс следующим образом:

    Person = {
        __construct = function(firstname, lastname){
            this.firstname = firstname
            this.lastname = lastname
        }
        __get@fullname = function(){
            return this.firstname .. " " .. this.lastname
        }
        walk = function(){
            print this.fullname .. " is walking!"
        }
    }

Теперь создадим экземпляр данного класса:

    var p = Person("James", "Bond")

Фактически Person — это обычный объект, когда объект вызывается, как функция, ObjectScript автоматически создает новый экземпляр данного объекта и инициализирует его методом __construct. Выше приведенный код будет реально выполнен следующим образом:

    var p = {}
    p.prototype = Person
    p.__construct("James", "Bond")

Если затем выполнить:

    p.walk()
    print p

то выведется:

James Bond is walking!
{"firstname":"James","lastname":"Bond"}

Из новых фишек следует выделить метод __get@fullname, который неявно вызывается из метода walk:

    __get@fullname = function(){
        return this.firstname .. " " .. this.lastname
    }
    walk = function(){
        print this.fullname .. " is walking!"
    }

Метод __get@fullname возвращает значение свойства fullname. Могут быть также специальные методы для установки свойств, но об этом позже в разделе Свойства, getter-ы и setter-ы.

Из интересного тут нужно отметить, что метод __get@fullname содержит символ @, который в ObjectScript является полностью валидным для любых имен методов и переменных, на ряду с символом $ ну и остальными уже более стандартными символами.

Наследование

Теперь самое время унаследоваться от Person.

    // опишем класс IvanPerson
    var IvanPerson = extends Person {
        __construct = function(){
            super("Ivan", "Petrov")
        }
    }
    var p = IvanPerson() // создадим экземпляр класса IvanPerson
    p.walk()
    print p

Выведется:

Ivan Petrov is walking!
{"firstname":"Ivan","lastname":"Petrov"}

Наследование делается оператором extends, который принимает два выражения exp1 и exp2, любых, в том числе расчитанных на этапе выполнение и эквивалентен следующему коду:

    (function(exp1, exp2){ 
        exp2.prototype = exp1 
        return exp2 
    })()

Тут важно отметить:
    super("Ivan", "Petrov")

super вызывает метод родительского класса (прототипа) с именем метода, из которого он был вызван, в данном случае — это __construct, который и инициализирует экземпляр объекта.

ООП на закуску

Давайте создадим совершено новый тип данных, который будет работать как трехмерный вектор:

    var vec3 = {
        __construct = function(x, y, z){
            this.x = x
            this.y = y
            this.z = z
        }
        __add = function(a, b){
            return vec3(a.x + b.x, a.y + b.y, a.z + b.z)
        }
        __mul = function(a, b){
            return vec3(a.x * b.x, a.y * b.y, a.z * b.z)
        }
    }

    var v1 = vec3(10 20 30)
    var v2 = vec3(1 2 3)
    var v3 = v1 + v2 * v2
    print v3

Выведется: {"x":11,"y":24,"z":39}

Свойства, getter-ы и setter-ы

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

Геттер (getter) — возвращает значение свойства, сеттер (setter) — устанавливает значение. ObjectScript автоматически понимает, считывается свойство или устанавливается, и вызывает соответствующие методы.

    a = {
        _color = "red"
        __get@color = function(){ return this._color }
        __set@color = function(v){ this._color = v }
    }
    
    print a["color"]
    a.color = "blue"
    print a.color

Выведется:

red
blue

Как же это реально работает? При чтении свойства color ObjectScript ищет значение в объекте с именем color. Если таковое найдено, то оно просто возвращается. Если нет, то ищется метод __get@color, нашелся — отлично, значит ObjectScript вызывает и возвращает его результат. Если не нашелся, не беда, ObjectScript ищет метод __get. Если таковой присутствует, то ObjectScript вызывает этот метод с именем запрошенного свойства. Если ничего не нашлось, то возвращается null и точка.

При установке свойства, все происходит аналогично, но вместо __get используется __set. Еще один пример:

    a = {
        _color = "white"
        __get = function(name){ 
            if(name == "color")
                return this._color 
        }
        __set = function(name, v){
            if(name == "color")
                this._color = v
        }
        __del = function(name){
            if(name == "color")
                delete this._color
        }
    }
    
    print a.color
    a.color = "green"
    print a.color
    delete a.color
    print a.color

Выведется:

white
green
null

Тут показан новый оператор delete, который удаляет ссылка на значение в объекте, в данном случае с использование метода __del.

Многомерные свойства

ObjectScript поддерживает следующий (обычный для некоторых языков) синтаксис, который является полностью эквивалентным:

    print a.color
    print a["color"]

А что, если в квадратных скобках передать несколько значений? В ObjectScript это вполне реально!

    a = {
        _matrix = {}
        __getdim = function(x, y){
            return this._matrix[y*4 + x]
        }
        __setdim = function(value, x, y){
            this._matrix[y*4 + x] = value
        }
        __deldim = function(x, y){
            delete this._matrix[y*4 + x]
        }
    }
    a[1, 2] = 5        // компилятор преобразует это в a.__setdim(5, 1, 2)
    print a[1, 2]    // print(a.__getdim(1, 2))
    delete a[1, 2]    // a.__deldim(1, 2)
    print a[1, 2]    // print(a.__getdim(1, 2))

Выведется:

5
null

Остается только обратить внимание на метод __setdim, который первым параметром принимает новое значение, а в остальных параметрах — атрибуты свойства (их количество может быть любым начиная от двух).

Пустые свойства

А что на счет следующего кода?

    b = a[]
    a[] = 2
    delete a[]

Вполне! ObjectScript в этом случае вызывает следующие методы соответственно: __getempty, __setempty, __delempty. Программист может решить по своему усмотрению, как использовать этот функционал.

Заключение

На закуску несколько не отмеченных выше моментов.

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

    print function(a b c){ return a + b * c }(1 2 3)

Выведет 7

В функциях можно использовать arguments — возвращает масив всех параметров, с которыми функция была запущена, ... (три точки) — масив дополнительных параметров, которые не описаны в объявлении функции.

Оператор # вызывает для объекта применения метод __len. Для строк он возвращает количество символов в строке, а для объектов и масивов — количество элементов. Также в классе Object заведено свойство:

    Object.__get@length = function(){ return #this }

А т.к. все объекты, в том числе строка и масивы, унаследованы от Object, то можно использовать свойство length, например, в масивах, на манер JavaScript.

Из необычных математических операторов можно отметить ** — возведение в степень.

Из структурных конструкций на данный момент реализованы:

    if(exp) block [elseif(exp) block ][else block ]
    for(pre_block; exp; post_block) block
    for(assign_list in exp) block
    break
    continue
    function(var_list){ block }

Одинаковые строки ObjectScript хранит в единственном экземпляре, это делается автоматически. Причем не важно, была строка получена на этапе выполнения или компиляции программы.

Локальные переменные имеют область видимости, например.

    var i = 1;
    {
        var i = i
        i++
        print i
    }
    print i

Выведется
2
1


ObjectScript имеет два зарезервированных слова для целей отладки, первое — debugger (как в JavaScript). При срабатывании debugger программа остановится в дебагере, как при точке останова. Второе — debuglocals, которое возвращает ассоциативный объект с названиями видимых из точки использования debuglocals локальных переменых и их значений. Например:

    function(a){
        var c = a * 2;
        {
            var c = a - 1
            print debuglocals
        }
    }(10)

Выведется:

{a:10,c:9}

ObjectScript разпознает tail call. Это когда внутри функции возвращается результат выполнения др. функции. В этом случае вызываемая функция может заместить call stack текущей функции, а не увеливать call stack, добавляя себя в него.

Преобразование выражений в тип boolean происходит следующим образом: значения null, false и NaN возвращают false, все др. значения — true, в том числе пустая строка и число 0.

Операторы && и || возвращают то значение, которые было им передано, например:

    print 7 && 9
    print 7 || 9

Выведется:

9
7

При присваивании объектов, их копии не создаются, присваивается ссылка на сам объект. Чтобы создать копию, необходимо воспользоваться оператором clone, который клонирует аргумент. Для объектов и масивов, этот оператор копирует все значения в новый объект, др. типы не клонируются по умолчанию, а возвращаются как есть. Но на финальной стадии процесса вызывается метод __clone, в котором можно сделать что-то свое или дополнительное. Вопрос о спецификации данного метода пока не решен окончательно. Возможно есть смысл возвращать результатом клонирования то, что вернет метод __clone. В этом случае программист сможет клонировать и свои внутренние типы данных, созданные с помощью userdata, если пожелает.

Также есть typeof, valueof, numberof, stringof, arrayof, objectof, functionof, userdataof. Спецификация этих операторов прорабатывается.

Ну вот как-то так. Если вам ObjectScript кажется интересным, давайте разрабатывать и развивать язык вместе. Текущие задачи, над которыми я работаю — сборщик мусора, багфикс, оптимизация, документация, environment для функции, расширение синтаксиса, поддержка многострочных констант, компиляция в байт-код, компиляция в JavaScript (чтобы писать клиенты для веба). Предлагайте и комментируйте.

Стандарт языка в процессе формирования, поэтому любые идеи будут интересны.

Об интеграции с C++ расскажу в одной из следующих статей. Вкратце:

int test(OS * os, int, int, int, void*)
{
    os->pushNumber(123);
    return 1;
}

int main(int argc, char* argv[])
{
    OS * os = OS::create();

    os->pushCFunction(test);
    os->setGlobal("test");

    os->eval("print(test())"); // выведет 123

    os->release();
    return 0;
}


Как запустить пример того, что описано в этой статье? Скачать исходники, откомпилированный файл с примером с репозитория на github, прямая ссылка для загрузки. Перейти в папку OS\examples и запустить файл test3.cmd.

В файле test3.txt генерируется отладочная информация того, как ObjectScript скомпилировал исходник, это может потребоваться для лучшего понимания процессов, которые происходят внутри языка, например:

[14] print( a[v1] a.v2 )

    begin call
      get env var print
      begin params 2
        begin get property
          get local var a (1 0 param)
          get local var v1 (0 0 param)
        end get property ret values 1
        ,
        begin get property
          get local var a (1 0 param)
          push const string "v2"
        end get property ret values 1
      end params ret values 2
    end call ret values 0


В сухом остатке

ObjectScript полностью совместим с JSON, т.к. понимает этот формат, как свой родной, но добавляет в описание объектов и масивов свой расширенный и простой синтаксис. ObjectScript реализует все плюсы таких языков, как JavaScript, Lua и PHP, при этом добавляет свои уникальные возможности программирования. ObjectScript — объектно-ориентированный язык программирования, реализуюет все его парадигмы. Оператор new при этом не используется, минимизируя код и делая его более читабильным. Синтаксис ObjectScript позволет реализовать все необходимые конструкции, но направлен на простоту и читабильность. ObjectScript предназначен для вставки в приложение на C++, позволяет интегрироваться с С++ на уровне функций и пользовательских данных (в том числе объектно-ориентированных). ObjectScript — очень легкий, текущие исходники занимают 459 Кб. Язык пока не имеет стабильной версии и находится в стадии формирования спецификации и балансировки.

На данный момент я начал делать некоторые примеры по использованию языка ObjectScript и записывать видео, вы можеет посмотреть некоторые из них по следующим ссылкам:

http://www.youtube.com/watch?v=OCWIfQYW9rc
http://www.youtube.com/watch?v=P5KPJOVSs3E
http://www.youtube.com/watch?v=htDqDNqHX-I
http://www.youtube.com/watch?v=wqiDeuf7yu8
http://www.youtube.com/watch?v=uep2SvXdCNU

в описании к видео указаны ссылки, от куда можно скачать полные исходники примеров.
objectscript javascript lua php
Re: Ребят, презентация нового языка программирования ObjectScript
От: ArtDenis Россия  
Дата: 26.09.12 17:05
Оценка:
А есть в этом языке какие-нибудь полезные фичи, которые бы заставили перейти на него с других скриптовых языков, предназначенных для встраивания?
... << RSDN@Home 1.2.0 alpha 5 rev. 55>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: Ребят, презентация нового языка программирования ObjectScript
От: Ziaw Россия  
Дата: 27.09.12 03:46
Оценка: +1 -1
Здравствуйте, unitpoint, Вы писали:

U>А что если убрать точки с запятыми?


Это хороший шаг

U>Вызовы функций


U>
U>    print(5, " differences")
U>

U>А зачем там собственно запятая?

А это не очень, это мешает убрать скобки если аргумент не один

U>
U>    var s = concat("name: "name", count: "count", time: "time)
U>

U>Красиво и понятно! name, count и time — некоторые переменные. Соединение строк конечно же не обязательно делать через эту функция, есть специальный оператор .. (две точки) для конкатенации, но иногда функция concat может быть удобнее, да и быстрее при обработке нескольких параметров.

Некрасиво и непонятно. Красиво и понятно так:

"name: $name, count: $count, time: $time"


U>В фигурных скобках задан объект в привычном для JavaScript синтаксисе. Такой синтаксис полностью поддерживается в ObjectScript, но подобный вызов выглядит НЕ очень красиво. А что если убрать круглые скобки?

U>
U>    print {firstname:"Ivan", lastname:"Petrov"}
U>

U>Уже симпатичнее?! Эта возможность взята из Lua. Так можно вызывать любые функции и не только с объектом в качестве параметра, например:

Тут можно убрать и фигурные тоже, как сделали в ruby.
    print firstname:"Ivan", lastname:"Petrov"


    print "Hello World!"

U>Довольно таки просто и читабильно!

Действительно, только для нескольких аргументов это тоже должно работать.

U>А что если необходимо в качестве индекса значения использовать выражение, а не константу, легко:

U>
U>    a = {[2+3]="five" y=3}
U>

U>Т.е. выражение в квадратных скобках будет вычислено на этапе выполнения программы и результат будет использован в качестве индекса соответствующего значения в объекте. Иначе говоря:

Не читабельно вообще, круглые скобки тут были бы гораздо органичнее. Да и отсутствие запятой как бы связывает те выражения которые должны отделяться.
Вот этот пример совершенно явно это показывает:
U>
U>    a = {x=1, y=3; "zero" "one", "two" last:7,} // непонятно
U>    a = {x:1, y:3, 0:"zero", 1:"one", 2:"two", last:7} //понятно
U>


U>Еще одной важной особенностью является то, что в качестве индекса значения может выступать значение любого типа, например:

U>
U>    a = {x=1 y=2}
U>    b = {[a]="powerful" 7="greate"}
U>    print b[a]
U>

Это не особенность, это обычное поведение практически всех языков.

U>Множественное присваивание


U>ObjectScript полностью поддерживает множественное присваивание и выглядит это следующим образом:


U>
U>    i, j, k = 0, 1, 3
U>

U>Переменной i присвоится значение 0, j присвоится 1, k — 3. Интересным следствием множественного присваивания является возможность смены значений в переменых одной строкой:

Это частный случай паттернматчинга. Рекомендую изучить эту тему и сделать более универсальное решение.

U>Итераторы


Очень много места в статье уделено итераторам. Если планируете ее еще где-то публиковать, порежьте этот пункт.

U>Объектно-ориентированное программирование (ООП) в ObjectScript


U>Как можно было бы понять из названия языка, он просто обязан быть объектно ориентированным и поддерживает ООП во всей своей красе.


Но ужасные префиксы __ или __get@ обычно говорят, что фича прикручена сбоку к языку изначально не приспособленному для этого.

U>Оператор # вызывает для объекта применения метод __len. Для строк он возвращает количество символов в строке, а для объектов и масивов — количество элементов. Также в классе Object заведено свойство:


U>
U>    Object.__get@length = function(){ return #this }
U>

U>А т.к. все объекты, в том числе строка и масивы, унаследованы от Object, то можно использовать свойство length, например, в масивах, на манер JavaScript.

Очень странный дизайн, о чем будет говорить длина объекта Money? Как связаны __len и __get@length?

U>Одинаковые строки ObjectScript хранит в единственном экземпляре, это делается автоматически. Причем не важно, была строка получена на этапе выполнения или компиляции программы.


var text  = "... 60 mbytes of text"
var text2 = text.substring(0, text.length - 1) // большой текст без последнего символа
var text3 = text + 't' // тот же самый большой текст, он действительно будет в единственном экземпляре?


U>ObjectScript имеет два зарезервированных слова для целей отладки, первое — debugger (как в JavaScript). При срабатывании debugger программа остановится в дебагере, как при точке останова. Второе — debuglocals, которое возвращает ассоциативный объект с названиями видимых из точки использования debuglocals локальных переменых и их значений. Например:


вот для таких вещей как раз оправдано использование __ или @, вместо ключевых слов.

Остаток:

не проработаны такие вещи как:
а) выражениия: любая конструкция должна возвращать какое-то значение, например блок кода — последнее вычисленное в нем выражение, это очень удобный и правильный принцип
б) паттерн матчинг (я о нем уже писал)
в) функции. описание функции в функциональном языке оставлено неестественно длинным, сравните function(x) {return x*x} и x => x * x

Если хотите сделать удобный яваскрипт, посмотрите на CoffeeScript.
Re: Ребят, презентация нового языка программирования ObjectScript
От: cgibin  
Дата: 28.09.12 06:12
Оценка:
Здравствуйте, unitpoint, Вы писали:

Практически всё есть в TiScript
Re[2]: Ребят, презентация нового языка программирования ObjectScript
От: unitpoint  
Дата: 30.09.12 02:47
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Некрасиво и непонятно. Красиво и понятно так:


Z>
Z>"name: $name, count: $count, time: $time"
Z>

Да, к этому я думаю нужно прийти.

Z>Тут можно убрать и фигурные тоже, как сделали в ruby.

Z>
Z>    print firstname:"Ivan", lastname:"Petrov"
Z>

Скобки убирать не планировалось.

U>>А что если необходимо в качестве индекса значения использовать выражение, а не константу, легко:

U>>
U>>    a = {[2+3]="five" y=3}
U>>

U>>Т.е. выражение в квадратных скобках будет вычислено на этапе выполнения программы и результат будет использован в качестве индекса соответствующего значения в объекте. Иначе говоря:

Z>Не читабельно вообще, круглые скобки тут были бы гораздо органичнее.


Этот синтаксис был взят из Lua, на мой взгляд синтаксис правильный.

U>>Еще одной важной особенностью является то, что в качестве индекса значения может выступать значение любого типа, например:

U>>
U>>    a = {x=1 y=2}
U>>    b = {[a]="powerful" 7="greate"}
U>>    print b[a]
U>>

Z>Это не особенность, это обычное поведение практически всех языков.

Из прародителей такое умеет только Lua, ни PHP ни JS этого не умеет.

Z>Но ужасные префиксы __ или __get@ обычно говорят, что фича прикручена сбоку к языку изначально не приспособленному для этого.


В этом плане преследовалась мысль — расширить JS с помощью полезных возможностях в др. языках, сохранив при этом все что поддерживает JS.

U>>Одинаковые строки ObjectScript хранит в единственном экземпляре, это делается автоматически. Причем не важно, была строка получена на этапе выполнения или компиляции программы.


Z>
Z>var text  = "... 60 mbytes of text"
Z>var text2 = text.substring(0, text.length - 1) // большой текст без последнего символа
Z>var text3 = text + 't' // тот же самый большой текст, он действительно будет в единственном экземпляре?
Z>


Да, строки в OS всегда живут в одном экземпляре.

Z>не проработаны такие вещи как:

Z>а) выражениия: любая конструкция должна возвращать какое-то значение, например блок кода — последнее вычисленное в нем выражение, это очень удобный и правильный принцип
Z>б) паттерн матчинг (я о нем уже писал)
Z>в) функции. описание функции в функциональном языке оставлено неестественно длинным, сравните function(x) {return x*x} и x => x * x
Z>Если хотите сделать удобный яваскрипт, посмотрите на CoffeeScript.

Перечисленные вами моменты знакомы мне конечно, но я не планировал делать язык, чтобы реализовать эти моменты, в том числе делать что-то похожее на CoffeeScript. Главная цель, которая преследовалась — сделать язык для тех же целей и задач, которые сейчас решают Lua и JS, соединим удобные моменты из этих и некоторых др. языков вместе. Как частный случай — разработка кросс платформенного движка для мобильных платформ.
Re[2]: Ребят, презентация нового языка программирования ObjectScript
От: unitpoint  
Дата: 30.09.12 02:49
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Некрасиво и непонятно. Красиво и понятно так:


Z>
Z>"name: $name, count: $count, time: $time"
Z>

Да, к этому я думаю нужно прийти.

Z>Тут можно убрать и фигурные тоже, как сделали в ruby.

Z>
Z>    print firstname:"Ivan", lastname:"Petrov"
Z>

Скобки убирать не планировалось.

U>>А что если необходимо в качестве индекса значения использовать выражение, а не константу, легко:

U>>
U>>    a = {[2+3]="five" y=3}
U>>

U>>Т.е. выражение в квадратных скобках будет вычислено на этапе выполнения программы и результат будет использован в качестве индекса соответствующего значения в объекте. Иначе говоря:

Z>Не читабельно вообще, круглые скобки тут были бы гораздо органичнее.


Этот синтаксис был взят из Lua, на мой взгляд синтаксис правильный.

U>>Еще одной важной особенностью является то, что в качестве индекса значения может выступать значение любого типа, например:

U>>
U>>    a = {x=1 y=2}
U>>    b = {[a]="powerful" 7="greate"}
U>>    print b[a]
U>>

Z>Это не особенность, это обычное поведение практически всех языков.

Из прародителей такое умеет только Lua, ни PHP ни JS этого не умеет.

Z>Но ужасные префиксы __ или __get@ обычно говорят, что фича прикручена сбоку к языку изначально не приспособленному для этого.


В этом плане преследовалась мысль — расширить JS с помощью полезных возможностях в др. языках, сохранив при этом все что поддерживает JS.

U>>Одинаковые строки ObjectScript хранит в единственном экземпляре, это делается автоматически. Причем не важно, была строка получена на этапе выполнения или компиляции программы.


Z>
Z>var text  = "... 60 mbytes of text"
Z>var text2 = text.substring(0, text.length - 1) // большой текст без последнего символа
Z>var text3 = text + 't' // тот же самый большой текст, он действительно будет в единственном экземпляре?
Z>


Да, строки в OS всегда живут в одном экземпляре.

Z>не проработаны такие вещи как:

Z>а) выражениия: любая конструкция должна возвращать какое-то значение, например блок кода — последнее вычисленное в нем выражение, это очень удобный и правильный принцип
Z>б) паттерн матчинг (я о нем уже писал)
Z>в) функции. описание функции в функциональном языке оставлено неестественно длинным, сравните function(x) {return x*x} и x => x * x
Z>Если хотите сделать удобный яваскрипт, посмотрите на CoffeeScript.

Перечисленные вами моменты знакомы мне конечно, но я не планировал делать язык, чтобы реализовать эти моменты, в том числе делать что-то похожее на CoffeeScript. Главная цель, которая преследовалась — сделать язык для тех же целей и задач, которые сейчас решают Lua и JS, соединим удобные моменты из этих и некоторых др. языков вместе. Как частный случай — разработка кросс платформенного движка для мобильных платформ.
Re: Ребят, презентация нового языка программирования ObjectScript
От: c-smile Канада http://terrainformatica.com
Дата: 02.10.12 06:15
Оценка:
Здравствуйте, unitpoint, Вы писали:

А можно как-то озвучить design goals? Языка, VM и идеологии встраивания?

Пока видится комбинация JS syntax, Python class model(?) и LUA embedding(?). Все это по отдельности не есть winning features. А даже скорее наоборот.

Я бы лично ожидал от встраиваемого языка некой супер-удобной для C++ встраиваемости.
Но для органичной встраиваемости в C++ язык должен быть ref-count based. Т.е. a la python.

Короче было бы интересно услышать про design...
Re[2]: Ребят, презентация нового языка программирования ObjectScript
От: unitpoint  
Дата: 02.10.12 15:57
Оценка:
Я начал описывать API по интеграции с C++ в этой статье ObjectScript API, интеграция с C++. Часть 3: подключение модуля с функциями на C++.
Re[3]: Ребят, презентация нового языка программирования ObjectScript
От: -MyXa- Россия  
Дата: 02.10.12 17:09
Оценка: +1
Здравствуйте, unitpoint, Вы писали:

U>Я начал описывать API по интеграции с C++ в этой статье ObjectScript API, интеграция с C++. Часть 3: подключение модуля с функциями на C++.


Это прелестно!

Только я не понимаю, чем код в духе:
static int my_isdigit(OS * os, int params, int, int, void*)

лучше того или этого.
Если не поможет, будем действовать током... 600 Вольт (C)
Re[4]: Ребят, презентация нового языка программирования ObjectScript
От: ArtDenis Россия  
Дата: 03.10.12 06:29
Оценка:
Здравствуйте, -MyXa-, Вы писали:
MX> ...

+1

Ты ещё забыл упомянуть LuaBind: http://www.rasterbar.com/products/luabind/docs.html
Там всё по той же технологии сделано. Например, нужно задействовать эту ф-цию:
void repeat(const std::string &str, int times)
{
    for (int i = 0; i < times; i++) std::cout << str << std::endl;
}

Подключаем эту (и другие) ф-ции в луа:
module(L)
[
    def("repeat", &repeat)
];

Ну и используем из луа:
repeat("Hello world!", 12)

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

Вот это я понимаю — удобная интеграция
... << RSDN@Home 1.2.0 alpha 5 rev. 55>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[5]: Ребят, презентация нового языка программирования ObjectScript
От: unitpoint  
Дата: 03.10.12 11:27
Оценка:
Удобное подключение внешних функций не совсем связано с самим языком, это лишь набор удобных дефайнов и темплейтов, которые оборачивают нативный API, что я собственно и начал разрабатывать. Опишу в одной из следующих статей.
Re[6]: Ребят, презентация нового языка программирования ObjectScript
От: ArtDenis Россия  
Дата: 03.10.12 12:11
Оценка:
Здравствуйте, unitpoint, Вы писали:

U>Удобное подключение внешних функций не совсем связано с самим языком, это лишь набор удобных дефайнов и темплейтов, которые оборачивают нативный API, что я собственно и начал разрабатывать. Опишу в одной из следующих статей.


Да никто не спорит. Просто если новый скриптовый язык для ничем особо не отличается от уже существующих, то пускай хотя бы он будет иметь удобное средство для встраивания, иначе он так и останется "языком одного проекта", если конечно дело вообще дойдёт до этого "проекта"
... << RSDN@Home 1.2.0 alpha 5 rev. 55>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[7]: Ребят, презентация нового языка программирования ObjectScript
От: unitpoint  
Дата: 07.10.12 00:58
Оценка:
Биндинг скоро покажу, на данный момент готово под студию, разбираюсь с проблемами под gcc, но выходит все очень здорово и просто.
Re[8]: Биндинг пользовательских классов и функций на C++
От: unitpoint  
Дата: 09.10.12 23:32
Оценка:
Как обещал, статья о том, как подключать классы на C++.

Предположим, у нас есть следующий тестовый класс на C++, который мы хотим использовать в коде на OS:

class TestClass
{
public:
    int i;
    float j;

    TestClass(int _i, float _j){ i = _i; j = _j; }

    int getI() const { return i; }
    void setI(int _i){ i = _i; }
    
    float getJ() const { return j; }
    void setJ(float _j){ j = _j; }

    double doSomething(int a, float b, double c, TestClass * pb)
    {
        return i + j + a + b + c + pb->i + pb->j;
    }

    void print()
    {
        printf("test class: %d, %f\n", i, j);
    }
};


Подключаем его к OS:

// 1. нужно объявить класс в пространстве имен ObjectScript
//    OS_DECL_USER_CLASS - это макрос, в котором объявляются несколько 
//    служебных функций для правильной типизации класса на C++
namespace ObjectScript { OS_DECL_USER_CLASS(TestClass); }

// 2. нужно сделать функцию, которая будет создавать экземпляр класса
TestClass * __constructTestClass(int i, float j){ return new TestClass(i, j); }

// 3. описать протопит класса и зарегистрировать его в OS
OS::FuncDef funcs[] = {
    def("__construct", __constructTestClass),
    def("__get@i", &TestClass::getI),
    def("__set@i", &TestClass::setI),
    def("__get@j", &TestClass::getJ),
    def("__set@j", &TestClass::setJ),
    def("doSomething", &TestClass::doSomething),
    def("print", &TestClass::print),
    {}
};
registerUserClass<TestClass>(os, funcs);


Готово, проверяем в OS:

var t = TestClass(1, 0.25)
print "t.i: "..t.i
print "t.j: "..t.j

var t2 = TestClass(2, 0.5)
t2.i = t2.i + t.j
print "t2"
t2.print()

print "t.doSomething(10, 100.001, 1000.1, t2): "..t.doSomething(10, 100.001, 1000.1, t2)


Вывод:

t.i: 1
t.j: 0.25
t2
test class: 2, 0.500000
t.doSomething(10, 100.001, 1000.1, t2): 1113.8509994506835


Полный текст статьи
objectscript objectscript api binder binding integration c++ javascript lua open source php
Re[9]: Биндинг пользовательских классов и функций на C++
От: ArtDenis Россия  
Дата: 10.10.12 02:50
Оценка:
Здравствуйте, unitpoint, Вы писали:

U>Как обещал, статья о том, как подключать классы на C++.


Уже гораздо лучше Но всё равно пока что "много буков", например, по сравнению с тем же LuaBind. Ещё не вижу вещей наподобе передачи владения объектом между райтаймом скриптового языка и хостовым кодом и обратно.
Кстати, наследование классов в биндинге поддерживается?
... << RSDN@Home 1.2.0 alpha 5 rev. 55>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[10]: Биндинг пользовательских классов и функций на C++
От: unitpoint  
Дата: 16.10.12 09:08
Оценка:
AD>Уже гораздо лучше Но всё равно пока что "много буков", например, по сравнению с тем же LuaBind.
AD>Ещё не вижу вещей наподобе передачи владения объектом между райтаймом скриптового языка и хостовым кодом и обратно.

Про владение напишу в одной статей, в целом смысл в том, что значение в OS удерживается (retain) внешним кодом, после чего OS пропускает его в ходе процесса сборки мусора.

AD>Кстати, наследование классов в биндинге поддерживается?


В C++, в OS? чтобы не было разночтения, приведите пожалуйста пример кода того, что вы имеете в виду или то, какую бы вы хотели видеть реализацию.
Re[11]: Биндинг пользовательских классов и функций на C++
От: ArtDenis Россия  
Дата: 16.10.12 17:06
Оценка:
Здравствуйте, unitpoint, Вы писали:

U>В C++, в OS? чтобы не было разночтения, приведите пожалуйста пример кода того, что вы имеете в виду или то, какую бы вы хотели видеть реализацию.


Ну например у меня в С++-проекте есть своя иерархия классов, которые в том числе реализуют различные интерфейсы. В ObejctScript хотелось бы поработать с объектами этих классов. Насколько это реально?
... << RSDN@Home 1.2.0 alpha 5 rev. 55>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[12]: Биндинг пользовательских классов и функций на C++
От: unitpoint  
Дата: 18.10.12 03:36
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, unitpoint, Вы писали:


U>>В C++, в OS? чтобы не было разночтения, приведите пожалуйста пример кода того, что вы имеете в виду или то, какую бы вы хотели видеть реализацию.


AD>Ну например у меня в С++-проекте есть своя иерархия классов, которые в том числе реализуют различные интерфейсы. В ObejctScript хотелось бы поработать с объектами этих классов. Насколько это реально?


Уже реально. Дополнение к предыдущему примеру с наследованием пользовательского класса:

class NewTestClass: public TestClass
{
public:

    NewTestClass(): TestClass(10, 20){}

    double doSomething(int a, float b, double c, TestClass * pb)
    {
        return i - j - a - b - c - pb->i - pb->j;
    }
};

namespace ObjectScript { OS_DECL_USER_CLASS(NewTestClass); }

NewTestClass * __constructNewTestClass()
{
    return new NewTestClass();
}

void registerNewTestClass(OS * os)
{
    OS::FuncDef funcs[] = {
        def("__construct", __constructNewTestClass),
        def("doSomething", &NewTestClass::doSomething),
        {}
    };
    registerUserClass<NewTestClass, TestClass>(os, funcs);
}


функция registerUserClass<NewTestClass, TestClass> регистрирует класс NewTestClass с наследованием от TestClass. Полный пример в исходниках тут https://github.com/unitpoint/objectscript, открыть proj.win32\examples.sln, проект osbind.

Это то, что вы имели в виду?
Re[13]: Биндинг пользовательских классов и функций на C++
От: ArtDenis Россия  
Дата: 18.10.12 04:06
Оценка:
Здравствуйте, unitpoint, Вы писали:

U>Это то, что вы имели в виду?


Да, именно это
... << RSDN@Home 1.2.0 alpha 5 rev. 55>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.