четверг, 22 октября 2009 г.

[comp.prog.flame] Zimbu – новый язык программирования от Брама Мулинара

Не, ну так нельзя – заходишь с утра на LOR и видишь новость о том, что разработчик ViM, Брам Мулинар, затеял создание нового языка программирования – Zimbu. Все, работа встала! :)

Итак, новый язык имеет свой сайт: http://www.zimbu.org

Для чего понадобился новый язык (ёптыть, разве ж не понятно – все остальное писали не мы – прим.eao197)? Вот что пишет автор:

Предположим, что вы хотите написать новую программу, что-нибудь вроде текстового редактора. На каком языке вы будете это делать?
- он должен быть настолько быстрым, насколько это возможно, поэтому интерпретируемые языки не рассматриваются;
- вы не хотите заниматься микроуправлением памятью, поэтому C не рассматриваются;
- вы не хотите, чтобы программистам требовалась ученая степень, поэтому C++ не рассматриваются;
- вы хотите быстрый запуск и не хотите зависимостей от большого run-time, поэтому Java не рассматривается;
- он должен работать на большинстве систем с компилятором C, поэтому D не рассматривается;
- вы хотите получать удовольствие от создания чего-нибудь нового.

Не существует языков, которые действительно удовлетворяют этим требованиям. Поэтому создается новый, который удовлетворяет.

Какие цели преследуются при создании языка?

- легкость чтения кода – код читается в N раз чаще, чем пишется;
- избежание распространенных ошибок – нужно сделать сложным написание плохого кода (но вы можете писать хаки, если вы действительно этого хотите);
- краткость и ясность, не нужно повторять одно и тоже дважды – нет заголовочных файлов, нет повторения спецификации типа;
- эффект выражения должен быть предсказуемым и не должен зависеть от чего-то в другом файле;
- эффективное исполнение: нет задержек при старте, разумное потребление памяти – нет эффектов JIT-компиляции;
- поддержка большого диапазона приложений – Zimbu может быть использован для написания ядра ОС, коротких скриптов и больших GUI приложений;
- переносимость – возможность компиляции и запуска на почти всех системах;
- много стандартных типов, модулей и классов – большинство вещей, которые вам нужны, уже здесь.

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

Какие решения уже были приняты автором языка?

- конвертация программы в C и использование компилятора C для генерации машинного кода (в последствии может быть что-нибудь другое);
- в основном использование статической проверки типов, так же разрешена run-time проверка типов;
- объектно-ориентированность, все данные обрабатываются как объекты, но есть и свободные функции;
- исходные файлы содержат один модуль и несколько классов, каталоги образуют пакеты, один import определяет одно имя;
- стандартные модули и классы доступны без импорта;
- многие модули являются частью языка, они работают одинаково везде;
- все ключевые слова пишутся заглавными буквами, вы можете использовать все остальные имена не беспокоясь о том, что следующие версии языка поломают вашу программу.

Для демонстрации всего сказанного выше несколько примеров.

Вот, какие правила именования используются в языке:

  • ключевые слова записываются только заглавными буквами;
  • функции, методы и переменные начинаются со строчной буквы или подчеркивания: openFile(), getName(), file, name, _msg;
  • классы и перечисления начинаются с заглавной буквы, но имена не могут иметь вид X_ (где X – это любая буква): Node, FilePointer;
  • имена интерфейсов начинаются с I_: I_writer, I_runnable;
  • имена исключений начинаются с E_: E_negativeArg, E_pastEnd.

Блок заканчивается одной(!) закрывающей фигурной скобкой, открывающей скобки не нужно:

FOR arg IN ARG.getAll()
   IF !didFirst && arg == "-n"
     writeNewline = FALSE
   ELSE
     IO.write(sep + arg)
     sep = " "
   }
   didFirst = TRUE
}

Точки с запятой, в конце выражений так же не нужны.

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

Не правильно

Правильно

Объяснение

func (x) func(x) аргументы принадлежат функциям, а не являются самостоятельной сущностью
[ item, item ] [item, item] код должен быть компактным
[item,item] [item, item] пробел после запятой выделяет элементы
if f#comment if f #comment комментарий является отдельным элементом выражения
x=y1+p3*3 x = y1 + p3 * 3 пробелы должны разделять элементы выражения

Операция конкатенации строк, вроде бы, записывается как “a”..”b”, а не “a”+”b”.

Базовыми типами являются: bool, int (64-бит знаковое целое), int8-int64, bigInt, nat (64-бит целое без знака), nat8-nat64, bigNat, float (64-бит с плавающей точкой), float8-float128, fixed1-fixed15.

Составными базовыми типами являются:

  • string (предполагается, что хранит UTF-8, но может хранить любые символы, в том числе и нулевые);
  • массивы (поддерживается операция resize, но она может быть неэффективной, в качестве типа элемента может использоваться ANY):
    int[100] counters
    int[] oneTwoThree = [1, 2, 3]
    string[100] names = ["Monday", "Tuesday"]
  • туплы:
    FUNC tuple<int, string, list<string>> getValues()
      ...
    }
    int n
    string name
    list<string> list
    [n, name, list] = getValues()     # tuple/list/array unpack
    
    # Initializers
    [< 1, "hello", ["a", "b"] >]      # implied types
    tuple<int, string>(123, "foo")
    tuple<ANY, ANY>   # item containing two arbitrary items
  • списки:
    list<string> words  # list of strings
    list<ANY> list      # list of anything
    
    [1, 2, 3]                        # implied type.
    list<float>.NEW([1, 2, 0.3])     # specified type
    list<ANY>.NEW([1, "word", 0.3])  # any type
  • словари:
    dict<string, Int>     # key is string, value is Int
    dict<string, ANY>     # key is string, any type of value
    dict<ANY, ANY>        # key is any type, value is any type
    
    {'a': 1, 'b': 2}                   # use type of first entry, implied type
    dict<string, float>.NEW({'a': 3})  # specified type
    dict<string, ANY>.NEW({'a': 1, 'b': "x"})
  • мульти-словари (несколько значений для одного ключа):
    multiDict<string, string> mdict = NEW()
    mdict.add("Smith", "John")
    mdict.add("Smith", "Peter")
    mdict.count("Smith")   # 2
    list<string> firstNames = mdict.get("Smith")
    mdict.remove("Smith", "Peter")
    mdict.clear("Smith")
  • множества (ключи без связанных с ними значений):
    set mySet = NEW()
    mySet.add("Peter")
    mySet.remove("Peter")  # same as set.clear("Peter")
    bool hasPeter = mySet.has("Peter")
    mySet.get("Peter")     # error
    mySet.count("Peter")   # 0 or 1
    bool hadPeter = mySet.pop("Peter")
    
    ["Peter", "John"] # initializers
  • мульти-множества (повторяющиеся ключи):
    setmultiSet mset = NEW()
    mset.add("Peter")
    mset.add("Peter")
    mset.count("Peter")   # 2
    mset.remove("Peter")
    mset.count("Peter")   # 1
    mset.get("Peter")     # compile Error
    mset.clear("Peter")

Язык объектно-ориентированный. Для чего в языке могут быть объявлены следующие сущности: CLASS (обычный класс, методы могут иметь реализацию), FINAL CLASS (от которого нельзя наследоваться), ABSTRACT CLASS (не имеет части реализации), MIXIN (не очень пока понятно, как это выглядит), INTERFACE (интерфейс, не может иметь реализации).

При переопределении методов в производных классах нужно использовать специальную метку REPLACE (напоминает override в других языках). Для того, чтобы сделать метод виртуальным (т.е. чтобы разрешить его переопределение в производных типах) нужно пометить его с помощью FUNC.default или PROC.default.

Ну а теперь пора смотреть слайды. Слайд-шоу, как водится, начинается с Hello, World:

MAIN()
  IO.write("Hello, World!\n")
}

Точкой входа в программу является функция MAIN. Модуль IO стандартный, поэтому не нужно его импортировать.

Теперь реализация Unix-овой утилиты echo:

MAIN()
  bool    writeNewline = TRUE
  string  sep = ""
  bool    didFirst
  FOR arg IN ARG.getAll()
    IF !didFirst && arg == "-n"
      writeNewline = FALSE
    ELSE
      IO.write(sep + arg)
      sep = " "
    }
    didFirst = TRUE
  }
  IF writeNewline
    IO.write("\n")
  }
}

Ну а на закуску демонстрация объектной-ориентированности:

CLASS Animal
  PROC.default eat()
    IO.writeLine("I eat like a generic Animal.")
  }
}
 
CLASS Wolf EXTENDS Animal
  REPLACE PROC eat()
    IO.writeLine("I eat like a wolf!")
  }
}
 
CLASS Fish EXTENDS Animal
  REPLACE PROC.default eat()
    IO.writeLine("I eat like a fish!")
  }
}
 
CLASS.final GoldFish EXTENDS Fish
  REPLACE PROC eat()
    IO.writeLine("I eat like a goldfish!")
  }
}
 
CLASS OtherAnimal EXTENDS Animal
}
 
MAIN()
  list<animal.i> animals = NEW()
  animals.add(Animal.NEW())
  animals.add(Wolf.NEW())
  animals.add(Fish.NEW())
  animals.add(GoldFish.NEW())
  animals.add(OtherAnimal.NEW())
 
  FOR a IN animals
    a.eat()
  }
}

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

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

Лично я пока не понял, что там с исключениями. В правилах именования сущностей исключения присутствуют, но вот в описаниях их не видно.

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

Что здесь интригует: Брам Муленар зарекомендовал себя как прагматик, все-таки ViM – это не абы что. Так что, если он взялся, то может и довести до реализации (камешек в огород Вальтера Брайта – прим.eao197). И если он потом на своем языке замутит какой-то новый редактор или новую версию редактора ViM, то это будет серьезным killer application для нового языка.

В общем, хочу пожелать мужику удачи! Больше нативных языков – хороших и разных! :)

Disclaimer: обзор очень и очень поверхностный. Я даже не смог показать вкусности перечислений и новый хитрый тип BITS (http://www.zimbu.org/design/basic-types).

14 комментариев:

Skynin комментирует...

Спасибо!

Пять копеек в пользу: “a”..”b”, а не “a”+”b”.

Приключение со строками
char c='0';
string str="Text"+c;
// Что будет в str?

В динамически-типизированных языках вообще никак без отдельного оператора конкатенации строк, но и в статических ИМХО давно пора прекратить экономить на дополнительном операторе. Потому что операции со строками весьма частые и программист пусть явно указывает, что он хочет, чтобы при чтении было видно. Даже в Java/С# дало бы возможность реализовать:
int ii = 2;
int iistr = ii + "344";
string str = ii .. "344" .. 5;
int nii = "22" + str;

Потому что утомляет писать все эти Convert.ToInt32 да Integer.parseInt

И читабельности такие конструкции - никак не прибавляют.

eao197 комментирует...

Со строками у меня уже несколько раз были приключения, причем не такие, как у Алены.

В D, если мне склероз не изменяет, для конкатенации строк и массивов оператор ~ используется: a = b ~ c;

Skynin комментирует...

В D,
Да помнится и мне что есть.

Интересно, сколько еще лет нужно, чтобы дойти до выделенных операторов сравнения, а не переопределять == или оставлять вообще Equals

Должно быть семейство, для сравнения по содержимому, типа:
=^= - на равенство без учета регистра
=?= - с учетом

=^<, =?<, =^>, =?>

И уж если нужно с учетом локалей/культур - Equals с параметрами.

Потому что уже вторая, или третья моя программа - "готовила" текст для дальнейшего втягивания в вентуру паблишер. (На плайн Си. в 92ом)

Я бы из чисел обошелся, дайте удобную работу со строками!!! Доколе???

:)

gp комментирует...

Очень приятно читать про дизайн на оф. сайте -- какие варианты были, что и почему было выбрано.

Самое классное из увиденного -- http://www.zimbu.org/design/classes-and-interfaces/class-composition

Mixins -- это очень классно.

eao197 комментирует...

2gp: это вообще на моей памяти один из немногих языков программирования, о котором много узнаешь из очень небольших описаний и примеров.

Помню, как я в начале 2000-х пытался разбираться с языком D, когда там вменяемого описания еще не было -- мрак. А здесь как с Oberon-ом -- с нескольких страниц и примеров врубаешься, что к чему.

Вот на счет MIXIN-ов я лажанулся, не прочитал сразу... Ну да я много там по диагонали просмотрел... :(

А вот единственная закрывающая фигурная скобка, имхо, неудачный вариант. Надо было что-то другое, более заметное. Да тот же END, хотя бы.

Rustam комментирует...

Очень интересно, но похоже слабее D намного. Закрывающая скобка да убивает. Хоть бы опциональную открывающую что-ли сделали-бы :)

gp комментирует...

Слабее D? Да ладно! Здесь чувствуется vision, а в D -- просто feature creep. В языке главное -- отнюдь не количество фич.

Rustam комментирует...

В D тоже есть некий стержень и философия. Но блин долгострой :(

eao197 комментирует...

2Rustam: ну, D тоже без шаблонов и замыканий начинался. Так что нужно посмотреть, что будет дальше.

По поводу закрывающей скобки -- оказывается, дело привычки. Я сегодня смотрю на эти примеры и уже не замечаю даже, что открывающей нет. Выглядит уже и привычно, и читабельно.

2gp: Соглашусь с Rustam-ом. На данный момент нативный язык без замыканий (лямбда-функций или блоков кода) и обобщенного программирования вряд ли будет кому-то интересен. Разве что как замена чистого C в каких-то специфических задачах. Но такие и так были -- Modula-2, Oberon/ComponentPascal, Lisac.

Quaker комментирует...

Очередной велосипед? Чем его не устроили Ada или тот же Eiffel?

eao197 комментирует...

2Quaker:

Очередной велосипед?

Пока на нем не написано ничего более-менее стоящего -- определенно велосипед.

Чем его не устроили Ada или тот же Eiffel?

Не подходят по нескольким пунктам:

- сборка мусора появилась только в стандарте Ada2005 и доступна, AFAIK, только в версиях Ada для управляемых платформ;

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

- Eiffel не стал популярным языком. Поэтому нет смысла делать его новую открытую реализацию (SmartEiffel, полагаю, благополучно скончался). А писать что-нибудь на дорогом коммерческом EiffelStudio -- не все могут себе позволить, да и лицензия GPL многим не нравится.

Другое дело, почему бы не сделать какой-нибудь собственный D 1.0 to C транслятор.

Skynin комментирует...

Статья о Zimbu от А. Зубинского (украинские айтишники знают его как журналиста по ЯП и просто оригинальным, свежим идеям в программировании)
Опять язык программирования? И опять – новый?
Есть разработки, интересные не столько результатом (и даже такие, результат которых вообще не интересен) или проектным процессом, сколько логикой принимаемых в нем решений.

eao197 комментирует...

>Статья о Zimbu от А. Зубинского

Спасибо, почитаем.

eao197 комментирует...

>Статья о Zimbu от А. Зубинского

Как-то слов много, а о самом языке ничего :( Чтоже это за статья о ЯП, в которой нет ни одного примера кода (хотя бы уровня Hello, World).