Почему нет "вызова вызова составного метода", то есть ". ="?

У многих языков программирования уже есть составные утверждения +=, -=, /= и т.д. Относительно новый стиль программирования - это "цепочка" вызовов метода друг на друга, например. в Linq, JQuery и ORM Django.

Я иногда, чаще, чем мне хотелось бы, нашел необходимость сделать это в Django:

# Get all items whose description beginning with A
items = Items.objects.filter(desc__startswith='A')
if something:
    # Filter further to items whose description also ends with Z
    items = items.filter(desc__endswith='Z')

Я думаю, что было бы проще и на самом деле более читаемым, если бы существовал составной вызов вызова метода, например .=, который мог бы работать следующим образом:

items = Items.objects.filter(desc__startswith='A')
if something:
    items .= filter(desc__endswith='Z')
  • Есть ли языки программирования, которые поддерживают это или что-то вроде этого?
  • Если ответ отрицательный, почему бы и нет?
  • Является ли этот стиль программирования действительно новым?
  • Есть ли какие-либо PEP (предложения по улучшению Python), которые поддерживают эту идею?

Ответ 1

Это поддерживается в Perl 6.

Ответ 2

IMHO, мне это не нравится.

просто представьте это,

items .= click(function(){...});

это не синтаксическая ошибка, но это не имеет смысла, не так ли?

Я могу сказать, что это не имеет смысла просто потому, что, если вы расширите мой пример, это будет так:

items = items.click(function(){...});

items.click(function(){...}); просто вернет объект items, и вы назначите его items?

в этом примере,

items .= filter(desc__endswith='Z');

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

как parent .= children();, что произойдет с parent позже в кодах?

Я говорю jQuery.

Ответ 3

Я не могу ответить на эти вопросы, и я не уверен, что я думаю об этом, потому что раньше я его не видел, но у него есть интересное приложение: все операторы inplace становятся устаревшими.

a = 1
a .= __add__(1)
a .= __mul__(2)

Конечно, проще написать a += 1, но если этот синтаксис пришел раньше в дизайне языка, а методы __add__ были менее уродливы (например, просто add), язык сегодня может сегодня у нас осталось 11 операторов.

(Конечно, были бы другие последствия этого - в частности, было бы потеряно автоматическое отключение от __iadd__ до __add__. Тем не менее, это интересная концепция.)

Ответ 4

Scala коллекции поддерживают операции на месте при условии, что переменная имеет значение var.

scala> var L = List("b", "c")
L: List[java.lang.String] = List(b, c)

scala> L ::= "a"

scala> L
res8: List[java.lang.String] = List(a, b, c)

(Для тех, кто не знаком с Scala, :: является методом List)

Это стиль программирования, который многие избегают, и в Scala вы можете избежать такой мутации на месте, используя неизменяемые val s:

scala> val L = List("b", "c")
L: List[java.lang.String] = List(b, c)

scala> L ::= "a"
<console>:7: error: reassignment to val
       L ::= "a"

Ответ 5

Я часто об этом думал при программировании на Java или С#, где вы повторяете не только одну, но часто те же две или более ссылки на объекты с обеих сторон задания - например, у вас есть член какого-либо объекта это строка, и вы хотите вызвать некоторые методы в этой строке и присвоить ее переменной-члену. Как ни странно, это не беспокоило меня почти так же, как на Python.

Оператор .=, который вы предлагаете, является одной из идей, которые я думал о том, что я делал С#. Другой вариант заключается в том, чтобы разрешить ведущую точку в качестве сокращения для назначаемого объекта, например:

foo.bar.str = .lower()  # same as foo.bar.str = foo.bar.str.lower()

Pascal, Modula-2 и Visual Basic имеют оператор with (отличный от оператора Python с тем же именем), который позволит вам написать что-то вроде этого, если оно существует в Python (я называю это "using" здесь поэтому для действительного Python это не ошибочно):

using foo.bar:
    str = str.lower()  # same as foo.bar.str = foo.bar.str.lower()

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

using foo.bar:
    str = .lower()

Мне кажется, что это будет хороший бит синтаксического сахара, и я нахожу его очень читаемым, но, похоже, он не является приоритетом в списке приоритетов большинства языковых дизайнеров. Однако, поскольку Python имеет влияние Modula-2, возможно, не исключено, что он в конечном итоге будет добавлен.

Ответ 6

Ruby имеет эту функцию в некотором смысле, но реализует ее по-разному. Это происходит через "деструктивные" методы, которые изменяют переменную, на которую они вызваны. Например, вызов str.split просто возвращает объект split, он не изменяет его. Но, если вы вызовете str.split! он меняет его на месте. Большинство встроенных массивов и строковых методов имеют деструктивную и неразрушающую версию.