Каковы преимущества и недостатки подходов 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), возможно, это связано с проблемами обратной совместимости?


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 цента.
Джорджио
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.