Noop

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 22:31, 21 мая 2016.
Noop
Парадигма мультипарадигменный: функциональный, объектно-ориентированный
Первый   появившийся 2009
Печать дисциплины статическая
Лицензия Apache License 2.0
Портал: https://code.google.com/p/noop

Noop (произносится NOH-AWP, как машинная инструкция) это новый экспериментальный язык от Google, который пытается смешать лучшие уроки старых и новых языков. Noop изначально ориентирован для работы на виртуальной машине Java.

Что такое статус Noop?

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

Почему другой язык?

Опыт показывает, что разработчики часто создают код, который трудно проверить и поддерживать без его понимания. Это может создавать проблемы на большом программном продукте для всей команды в дальнейшем. При анализе этой проблемы, было обнаружено, что причиной во многих случаях были языковые особенности - глобально видимые состояния, неправильная классификация, обязательные и избыточные шаблоны и API, которым легко злоупотреблять. Noop стремится применять богатство накопленного языкового развития на протяжении последних 20 лет и нацелить оптимизацию на чистоту, проверяемость, легкость в модификации, и читаемость кода. Вместо инноваций особенностей языка, Noop пытается акцентироваться на опыте разработчика.

Кто стоит за Noop?

Noop является сайд-проектом из коллектива единомышленников-разработчиков, которые родом из нескольких компаний, в том числе (но не ограничиваясь) Google.

Noop «упрям»!

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

Да Нет
Внедрение зависимостей в язык Любая статика
Тестируемость – швов между каждой парой классов Наследование реализации (подклассы)
Неизменность Примитивные типы (все объекты)
Синтаксис направлен исключительно на читаемый код Ненужные шаблоны кода
Исполняемая документация никогда не выходит за границы текущего времени
Свойства, строгая типизация и разумные современные стандарты библиотек

Почему Noop?

Внедрение зависимостей изменило способ, по которому пишется программное обеспечение. Guice и PicoContainer сегодня являются важными составляющими для многих хорошо написанных приложений.

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

Noop это новый язык, работающий на виртуальной машине Java. В исходниках он выглядит подобно Java. Цель заключается в создании с самого начала зависимостей и их проверки в языке, а не полагаться на сторонние библиотеки других языков.

Есть три предлагаемых способа использования ваших исходные файлы Noop:

  • Java транслятор: производит исходники Java. Позволяет использовать Noop без конвертирования кода, но предоставляются не все особенности языка.
  • Интерпретатор: читает и оценивает код Noop. Работает медленнее, но имеет интерфейс командной строки
  • Компилятор: для Java байт-кода.

Первоначальные усилия будут сосредоточены на интерпретаторе и Java-трансляторе, чтобы позволить ранние эксперименты с Noop . Необходимо, чтобы люди создавали приложения, не размышляя о понятиях языка.

Основы

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

Читабельность

  • Всегда быть последовательным
  • Не используйте уплотнённость кода. Это делает код быстрее для написания, но труднее для прочтения, особенно для обозревателя кода, который не специализируется в языке, но знает C ++ или Java.

Достойная STDLIB

  • Выбор лучших реализаций из других языков
  • Используйте JodaTime для даты / времени API
  • Используйте util.concurrent для распараллеливания
  • Expose коллекции Google
  • Позволяют одновременно сбора итерации, когда дали ConcurrentIterator?
  • Анализ Objective-C стиля (легкий, несколько строк шаблонного)

Noop ссылки

Мы предполагаем, что возобновляемые объекты, в основном, данные или объекты (или entity объекты), которые могут иметь связанные с ними дополнительные удобные вычисления. Такие вычисления могут зависеть от наличия дополнительных внутренних делегатов. Есть много ситуаций, когда ссылка на объект может быть нулевой. Если, например, объект использует дополнительный делегат, тогда как объект выполняет вычисления, если дополнительный делегат объекта этого не делает? Обычно разработчики добавляют условный код для проверки на нулевое значение и выполняются альтернативные расчеты, когда дополнительные элементы отсутствуют. Мы предлагаем поддержку двух ключевых возможностей языка:

  1. Objective-C подход к нулевой ссылке
  2. Null Object Pattern в NOOP.

Применяя 2 таких подхода, значительное количество нуль-связанных логических условий можно заменить полиморфизмом.

Вызов по нулевой ссылке

Когда ссылке присваивается нулевое значение, мы можем вызвать метод по ней, похожий на метод в Objective-C. По умолчанию метод не возвращающий типы называется no-op. По умолчанию возвращающие методы возвращает NULL:

 Foo foo = null;
 foo.doFoo();  // Does not throw NullPointerException, performs a no-op by default
 assertTrue(null == foo.getFoo()); // Does not throw NPE, performs a no-op and returns  null by default

Привязка результатов методов в последовательность поведения no-op.

 BoogaResult result = foo.doBar().processBlah().boogabooga();

В данном случае не будет выброшено исключение, но это случится, если какой-либо из выше использованных методов вернёт null (или, если Foo является недействительным).

Null Object Pattern

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

 interface FooInput {
   void increment();
 }

 interface FooResult { ... }

 interface Foo {
   void doFoo(FooInput input);
   FooResult getFoo();
 }

 null Foo {
   void doFoo(FooInput input) {
  input.increment();
   }

   FooResult getFoo() {
     return new FooResult(5);
   }
 }

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

 null Foo(FooResult default) {
  void doFoo(FooInput input) {
  input.increment();
   }
   FooResult getFoo() {
     return default;
   }
 }

В следующем примере объект ShoppingCart группы LineItems представляет продукцию на заказ по поставке. Каждая строка указывает на продукт поставки, покупаемый по базовой цене, экземпляр денег, дополнительную скидку, которая вычисляет окончательную цену продукта после включения скидки. Вместо включения установлен условный код внутри LINEITEM, чтобы не беспокоится о том, что выполнять, когда программист создает LINEITEM без указания скидки. Здесь предоставляется смарт реализация нулевой скидки:

 interface ShoppingCart {
   void addLineItem(LineItem item);
 }

 interface Purchasable { ... }

 interface Currency { ... }

 interface Money {
   Currency getCurrency();
   long getAmount();
 }

 interface Date { ... }

 interface Discount {
   Money apply(Money basePrice, Date date);
 }

 null Discount {
   public Money apply(Money basePrice, Date date) {
     return basePrice;
   }  
 }

 createable LineItem {
  readable Purchasable product;
  readable Money basePrice;
  optional readable writeable Discount discount;
  readable virtual Money finalPrice {
     get {
       return discount.apply(basePrice, Date.now());
     }
   }
 }

Применение:

ShoppingCart shoppingCart = ...;

Purchasable catamaran = ...;
Money catamaranBasePrice = ...;
Discount catamaranDiscount = ...;
LineItem catamaranPurchase = new LineItem(catamaran, catamaranBasePrice, catamaranDiscount);

assertTrue(catamaranPurchase.finalPrice < catamaranPurchase.basePrice);

Purchasable carousel = ...;
Money carouselBasePrice = ...;
LineItem carouselPurchase = new LineItem(carousel, carouselBasePrice); // No discounts here

assertTrue(carouselPurchase.finalPrice == carouselPurchase.basePrice);

shoppingCart.addLineItem(catamaranPurchase);
shoppingCart.addLineItem(carouselPurchase);

Money grandTotal = shoppingCart.total();

Исключения

Проверяемые исключения вызывают много проблем, так Noop имеет только непроверяемые исключения.

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

// in Java
FileOutputStream out;
try {
  out = new FileOutputStream(new File("/tmp/foo"));
} catch (FileNotFoundException e) {
  // handle it
}
out.readline();

Использование исключений для проверки "ожидаемых" или "вероятностных" ошибок, как правило, не является подходящим для использования исключений. Создание исключения требует захвата трассировки стека, и блок Try-Catch прерывает поток управления и создает уродливые области видимости, с тем, чтобы обеспечить ссылку на исключения. В этом примере, для этого требуется присвоение выходной переменной нулевого состояния, поэтому она должен быть изменяемой.

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

File file = new File("/tmp/foo");
if (file.exists()) {
  FileOutputStream out = new FileOutputStream(file);
  out.readline();
} else {
  // handle it
}

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

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

Детали

В духе ошибок переменных Си, некоторые методы могут заявить, что они возвращают дополнительную ошибку в дополнение к возвращаемому значению. Это позволяет вызывающему абоненту обрабатывать ошибки в нормальном потоке управления.

Пример разбора строки String. Отказ разбора является ожидаемым ошибка.

 class Int() {
   Int, Error parse(String s) {...}
 }

 Int a, Error e = new Int().parse("13a");
 if (e.isError()) {
   // handle error
 } else {
   // a must be a good int
 }

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

Int a, _ = new Int().parse("100");

Параметры и свойства классов

Введение

Шаблонный код - зло. Java предназначена, к сожалению, для того, чтобы следовать рекомендуемой наилучшей практике выделения доступа к внутренним объектам, его назвали "bean" подходом. Добавление поддержки языка первого класса для ленивых объявлений и средств доступа позволит собственно инкапсулировать, не требуя "на всякий случай" шаблонного кода. В результате чего, вызывающий код не должен иметь никакой информации том, что есть получение или установка значений свойств с помощью их доступности или непосредственно через поля доступа.

Происхождение подхода

Методы доступа должны быть объявлены специально в языке в качестве первого элемента класса языка. На самом деле, синтаксис преимущественно из C # (с незначительными изменениями) будет только средством, чтобы создать переменную экземпляра.

Основы - декларация, хранения и использования

Свойства будут объявлены аналогично переменной экземпляра в традиционных языках, но методы установки и получения будут объявлены аналогично свойствам C #. Наиболее простой пример это:

public class Foo {
    public Bar bar;
}

Семантика этой декларации в том, что public свойство с именем Foo объявлено с типом Foo, и никакая специальная логика доступа или мутация не присутствует. Такое свойство получено путём переменных той же области (public) традиционно доступ в Java или C # тоесть:

     Foo foo = new Foo();
     foo.bar = new Bar();  // (sets foo's "bar" property)
     Bar bar = foo.bar; // (gets foo's "bar" property)

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

Лежащую в основе хранения переменную можно получить непосредственно только в самом классе, с помощью разыменования символа @. В случае Foo выше, можно было бы получить доступ к памяти bar. Тем не менее, bar не будет иметь никакого смысла за пределами самого класса. Нельзя вызвать Foo. @ bar, чтобы обойти Get / Set свойства. Будучи частными по отношению к примеру, сырое хранения не будет доступно для детей или для других классов.

    public Foo foo {
        set {
            @foo = foo;
        }
        get {
            return @foo;
        }
    }

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

public class(SomeService service) { 
    public virtual Foo foo {
        set {
            @service.processFoo(foo);
        }
        get {
            return @service.fetchFoo();
        }
    }
}

Так как что выше представленный метод виртуальный, то никакое хранение не создается под Foo и отсюда следующий код вызовет ошибку.

public class(SomeService service) {     public virtual Foo foo {
        set { @service.processFoo(foo); }
        get { return @service.fetchFoo(); }
    }

    public Void doSomethingOnFoo() {
        // this line is valid, as it accesses via the property
 foo.doSomething(); 
        // no such raw value for foo exists, so this breaks compilation
        @foo.doSomething();
    }
}

Литералы

Много полезных литералов!

  • Привет является строковым
  • линия1 \ nline2 это строка из нескольких строк
  • /.*/ это комментарий
  • {"а": "б", "в": "д"} является хэш-литералом
  • [1,2] является массивом
  • HTTP: // google.com является URL литералом

Ссылки

  1. Официальный сайт Google Noop
  2. wiki Noop