четверг, 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).

Отправить комментарий