Каковы преимущества и недостатки подходов C #, Java и Scala к Closures / Lambdas /…?

30

Интересно, каковы технические различия между C # и Scala в реализации и как оба решения сравниваются с идеями и проблемами реализации, озвученными в электронном письме Peek Past lambda Брайана Гетца, отправленном в список рассылки Project Lambda (JSR 335) ?

Из электронной почты:

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

и далее:

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

Вывод:

Lambdas-are-functions открывает двери. Lambdas-are-объекты закрывают их.
Мы предпочитаем, чтобы эти двери оставались открытыми.

И некоторый комментарий от человека в ветке Reddit говорит:

На самом деле я написал по электронной почте Нилу Гафтеру об этом и, насколько я понимаю, его объяснение C # и нынешний дизайн Java очень похожи в том, что делегаты на самом деле являются объектами, а не типами функций. Похоже, он считает, что Java должна учиться на недостатках лямбд в C # и избегать их (так же, как C # учился на недостатках Java и избегал их в начале).

Почему подход «Лямбда-ан-функции» дает больше возможностей в будущем, чем «Лямбда-ан-объекты»? Может кто-нибудь объяснить, какие существуют различия и как они повлияют на то, как будет написан код?

Видя, что вещи в Scala «просто работают», я продолжаю думать, что мне что-то не хватает в подходах, предложенных / предложенных в C # / Java (8), возможно, это связано с проблемами обратной совместимости?

Soc
источник
1
Это интересно. Учитывая, что система типов Javas не имеет понятия о функциях на данный момент, это будет означать, что нужно было сначала ввести это. Вполне возможно, что язык станет слишком сложным с этим.
Инго
Разве функции не должны быть экземплярами какого-то интерфейса? Что в них такого особенного?
общ
Lisp / Scheme / Clojure может моделировать объекты, в то время как Java / C # не может моделировать произвольное вложение функций. Тем не менее, Python, похоже, имеет лучшее из обоих миров.
Работа

Ответы:

15

Я думаю, что обсуждение объектов и функций - это красная сельдь. Если вопрос: «Является ли лямбда-функция или объект?» ответ должен быть да .

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

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

Рекс Керр
источник
9

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

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

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

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

Анджей Дойл
источник
лямды в C #! = от делегатов. Компилятор имеет возможность компилировать их либо в delgates, либо в деревья выражений. оба действительно являются объектными графами, но они не скомпилированы ни в «конкретный класс», ни даже в класс определенного дерева наследования
Rune FS
Если я правильно понимаю, то компиляция лямбды во внутренний класс объекта, с которым она связана, связывает его с этим объектом, поэтому в будущем, если Java введет функции более высокого порядка (функции на том же уровне объектов), то вы не может использовать реализацию внутреннего класса, и возникнет несоответствие. Я не думаю, что Java будет иметь функции высшего порядка в ближайшее время.
mwolfetech
@mwolfetech: Насколько я знаю, они уже запланированы для Java 8 с методами защитника. Они хотят , чтобы добавить такие вещи , как foreach, map, filterв коллекцию.
общ.,
@soc Хороший вопрос, трудно поспевать за количеством JSR и за тем, действительно ли они завершат и сделают целевую версию JDK. Похоже, что методы защитника могут быть частью одного и того же JSR. Что касается этой JSR , я нашел пост Брайана Гетца « Состояние лямбды» полезным - объясняет типы SAM и текущие идеи по реализации лямбда-выражений.
mwolfetech
"текущие мысли", м-м-м, разве этот пост 2010 года не устарел?
общ
5

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

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

Рассмотрим эти методы в Scala Regex:

def replaceAllIn (target: CharSequence, replacer: (Match)  String): String
def replaceSomeIn (target: CharSequence, replacer: (Match)  Option[String]): String

Было бы проще, если бы они были просто так:

def replace (target: CharSequence, replacer: (Match)  String): String
def replace (target: CharSequence, replacer: (Match)  Option[String]): String

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

Тем не менее, a Match- это что-то очень полезное, но в большинстве случаев вам нужен либо соответствующий, Stringлибо список подгрупп. Мы хотели бы иметь это:

def replaceAllIn (target: CharSequence, replacer: (String)  String): String
def replaceAllIn (target: CharSequence, replacer: (Seq[String])  String): String
def replaceAllIn (target: CharSequence, replacer: (Match)  String): String

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

Кроме того, учтите, что сопоставление с образцом в Scala и Java instanceofфактически бесполезны из-за стирания.

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

Даниэль С. Собрал
источник
Что ж, если стирание типов является единственной проблемой, которую они имеют, что они планируют делать? Нарушение всех кодов на этой планете уже
считалось невозможным
@ Soc Я так рад, что я не на их месте! Но это было Солнце, это Оракул. У Oracle никогда не было никаких сложностей в том, чтобы вносить серьезные изменения между основными и даже второстепенными версиями своего основного продукта.
Даниэль С. Собрал
Возможно, им следует сменить название языка и начать разработку нового языка, отказавшись от обратной совместимости. Таким образом, можно получить преимущества нового языка без необходимости играть со старым и устоявшимся языком. В конце концов, это то, что сделали Scala и Clojure.
Джорджио
@ Джорджио Это было бы немного бессмысленно. Ну, некоторые из людей , которые ответственны за то , что Java сегодня сделали, но, как вы сказали, есть есть альтернативы. Но люди, ответственные за Java, должны улучшить саму Java - они несут ответственность за это, в конце концов. Единственная альтернатива - просто отбросить Java и отказаться от всех преимуществ, связанных с ее управлением.
Даниэль С. Собрал,
@Daniel C. Sobral: IMO, язык программирования немного похож на часть программного обеспечения: в начале он может быть чистым и хорошо продуманным, но чем больше вы играете с ним, тем больше он запутывается. Поэтому я думаю, что в интересах разработчиков заморозить Java как язык и сосредоточить усилия на (1) создании новых библиотек или улучшении существующих, (2) улучшении JVM (если возможно), (3) разработке новых языков , Но, как вы сказали, есть люди, которые отвечают за Java и хотят продолжать продавать обновления. Таким образом, они собираются расширить его, чтобы сохранить его "прохладным". Просто мои 2 цента.
Джорджио