Сложность текущего предложения Lambda в Java 7? (Август 2010) - PullRequest
21 голосов
/ 04 августа 2010

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

После прочтения текущего временного синтаксиса для Lambda (≙Лямбда-выражения, прозрачность исключений, методы защиты и ссылки на методы) от августа 2010 г. Интересно, полностью ли игнорировали люди в Oracle бюджет на сложность Java при рассмотрении таких изменений?

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

  • Сравнимы ли предлагаемые дополнения по сложности с подходами, выбранными другими языками?
  • Можно ли вообще добавлять такие дополнения в язык и защита разработчика от сложности реализации?
  • Являются ли эти дополнения знаком достижения конца эволюции Java-как-языка или это ожидается при смене языкас огромной историей?
  • HУ других языков был совершенно другой подход на этом этапе эволюции языка?

Спасибо!

Ответы [ 5 ]

3 голосов
/ 16 августа 2010

Я не следил за процессом и развитием лямбда-предложения Java 7, я даже не уверен в том, какова последняя формулировка предложения.Рассматривайте это как разглагольствование / мнение, а не заявления правды.Кроме того, я не использовал Java целую вечность, поэтому синтаксис может быть ржавым и неправильным в некоторых местах.

Во-первых, каковы лямбды для языка Java?Синтаксический сахар.Хотя в целом лямбда-коды позволяют коду создавать небольшие функциональные объекты на месте, эта поддержка уже была задана - в некоторой степени - в языке Java с помощью внутренних классов.

Так насколько лучше синтаксислямбды?Где он превосходит предыдущие языковые конструкции?Где это может быть лучше?

Для начала мне не нравится тот факт, что есть два доступных синтаксиса для лямбда-функций (но это идет в строке C #, поэтому я думаю, что мое мнение не является широко распространенным. Я думаю, еслимы хотим приукрашивать, тогда #(int x)(x*x) слаще #(int x){ return x*x; }, даже если двойной синтаксис ничего не добавляет. Я бы предпочел второй синтаксис, более общий, за дополнительную плату написания return и ;в коротких версиях.

Чтобы быть действительно полезными, лямбды могут брать переменные из области видимости, в которой они определены, и из замыкания . В соответствии с внутренними классами, лямбды ограничены захват «эффективно окончательных» переменных. Согласованность с предыдущими функциями языка - хорошая возможность, но для удобства было бы хорошо иметь возможность собирать переменные, которые могут быть переназначены. Для этой цели ониучитывая, что переменные, присутствующие в контексте и помеченные @Shared, будут захвачены по ссылкеrence , разрешающий присваивания.Мне это кажется странным, так как лямбда может использовать переменную, которая определяется в месте объявления переменной, а не там, где определяется лямбда.Одна переменная может использоваться в более чем одной лямбде, и это приводит к одинаковому поведению во всех них.

Лямбды пытаются симулировать реальные функциональные объекты, но предложение не доходит до конца: сохранить синтаксический анализатор простым, поскольку до настоящего времени идентификатор обозначает либо объект, либо метод, который был согласованным, и для вызова лямбда-выражения требуется использовать ! после имени лямбда-выражения: #(int x)(x*x)!(5) вернет 25.Это дает новый синтаксис для использования с лямбдами, которые отличаются от остального языка, где ! обозначает каким-то образом как синоним для .execute в виртуальном универсальном интерфейсе Lambda<Result,Args...>, но почему бы не сделатьон завершен?

Можно создать новый универсальный (виртуальный) интерфейс Lambda.Он должен быть виртуальным, поскольку интерфейс не является реальным интерфейсом, а представляет собой семейство таких элементов: Lambda<Return>, Lambda<Return,Arg1>, Lambda<Return,Arg1,Arg2> ... Они могут определять один метод выполнения, на который я бы хотел походитьC ++ operator(), но если это бремя, тогда подойдет любое другое имя, приняв ! в качестве ярлыка для выполнения метода:

 interface Lambda<R> {
    R exec();
 }
 interface Lambda<R,A> {
    R exec( A a );
 }

Тогда компилятору нужно только перевести identifier!(args)до identifier.exec( args ), что просто.Перевод лямбда-синтаксиса потребовал бы, чтобы компилятор идентифицировал надлежащий реализуемый интерфейс, и мог бы соответствовать:

 #( int x )(x *x)
 // translated to
 new Lambda<int,int>{ int exec( int x ) { return x*x; } }

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

 new Lambda<int,int>{ int value = context_value;
     int exec( int x ) { return x * context_value; }
 };

Таким же образом, как текущее определение классов Inner, и, следовательно, естественным для текущих пользователей Java.Это может быть использовано, например, в цикле для генерации лямбда-множителя:

 Lambda<int,int> array[10] = new Lambda<int,int>[10]();
 for (int i = 0; i < 10; ++i ) {
    array[i] = new Lambda<int,int>{ final int multiplier = i;
       int exec( int x ) { return x * multiplier; }
    };
 }
 // note this is disallowed in the current proposal, as `i` is
 // not effectively final and as such cannot be 'captured'. Also
 // if `i` was marked @Shared, then all the lambdas would share
 // the same `i` as the loop and thus would produce the same
 // result: multiply by 10 --probably quite unexpectedly.
 //
 // I am aware that this can be rewritten as:
 // for (int ii = 0; ii < 10; ++ii ) { final int i = ii; ...
 //
 // but that is not simplifying the system, just pushing the
 // complexity outside of the lambda.

Это позволит использовать лямбда-выражения и методы, которые принимают лямбда-выражения как с новым простым синтаксисом: #(int x){ return x*x; } или с болеесложный ручной подход для особых случаев, когда сахарное покрытие мешает предполагаемой семантике.

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

3 голосов
/ 13 августа 2010

По модулю некоторых конструкций для устранения неоднозначности, почти все эти методы следуют из фактического определения лямбда-абстракции:

λx.E

Чтобы ответить на ваши вопросы по порядку:

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

Анонимные первоклассные функции, привязанные к императивным языкам, как правило, становятся функцией, которую некоторые программисты любят и часто используют, а другие полностью игнорируют - поэтому, вероятно, разумным является выбор некоторого синтаксиса, который не будет путать виды людей, которые предпочитают игнорировать наличие этой особенности языка. Я думаю, что скрывать сложность и особенности реализации - это то, что они пытались сделать, используя синтаксис, который хорошо сочетается с Java, но не имеет реального смысла для программистов Java.

Вероятно, желательно, чтобы они использовали некоторые биты синтаксиса, которые не будут усложнять существующие определения, и поэтому они немного ограничены в символах, которые они могут выбрать для использования в качестве операторов и тому подобное. Конечно, настойчивость Java в отношении обратной совместимости немного ограничивает эволюцию языка, но я не думаю, что это обязательно плохо. Подход PHP находится на другом конце спектра (т. Е. «Эй, ребята, давайте разберемся каждый раз, когда выйдет новый выпуск!»). Я не думаю, что эволюция Java по сути ограничена, за исключением некоторых фундаментальных принципов ее дизайна - например, соблюдение принципов ООП на основе виртуальных машин.

Я думаю, что очень сложно сделать убедительные заявления об эволюции языка с точки зрения Java. Это в достаточно уникальном положении. Во-первых, он очень, очень популярен, но он относительно старый. Microsoft получила преимущество как минимум 10-летнего наследия Java, прежде чем они решили даже начать разработку языка под названием «C #». Язык программирования C в основном перестал развиваться. C ++ претерпел несколько значительных изменений, которые нашли какое-либо признание в мейнстриме. Java продолжала развиваться через медленный, но последовательный процесс - во всяком случае, я думаю, что она лучше оснащена, чтобы продолжать развиваться, чем любые другие языки с такими же огромными установленными базами кода.

1 голос
/ 16 августа 2010

Это действительно очень близко к лямбда-функциям, предлагаемым в новом поколении C ++ (C ++ 0x), поэтому, я думаю, ребята из Oracle изучили другие реализации, прежде чем готовить свои собственные.

http://en.wikipedia.org/wiki/C%2B%2B0x

[](int x, int y) { return x + y; }
1 голос
/ 15 августа 2010

Возможно, это не совсем ответ на ваш вопрос, но это может быть сравнимо с тем, как target-c (который, конечно, имеет очень узкую базу пользователей в отличие от Java) был расширен блоками ( примеры ).Хотя синтаксис не соответствует остальной части языка (IMHO), он является полезным дополнением, и дополнительная сложность с точки зрения возможностей языка вознаграждается, например, за счет меньшей сложности параллельного программирования (простых вещей, таких как параллельная итерация по массиву илисложные методы, такие как Grand Central Dispatch ).

Кроме того, многие общие задачи упрощаются при использовании блоков, например, превращение одного объекта в делегат (или - в языке Java - «слушатель»)для нескольких экземпляров одного и того же класса.В Java анонимные классы уже могут использоваться для этой цели, поэтому программисты знают эту концепцию и могут просто сэкономить несколько строк исходного кода, используя лямбда-выражения.

В target-c (или в средах Cocoa / Cocoa Touch), новые функциональные возможности теперь часто доступны только с помощью блоков, и кажется, что программисты быстро их применяют (учитывая, что им приходится отказываться от обратной совместимости со старыми версиями ОС).

1 голос
/ 05 августа 2010

Это не намного сложнее, чем лямбда-выражения в других языках.

Рассмотрим ...

int square(x) {
    return x*x;
}

Java:

#(x){x*x}

Python:

lambda x:x*x

C #:

x => x*x

Я думаю, что подход C # немного более интуитивен.Лично я бы предпочел ...

x#x*x
...