Во многих языках синтаксис function_name(arg1, arg2, ...)
используется для вызова функции. Когда мы хотим вызвать функцию без каких-либо аргументов, мы должны это сделать function_name()
.
Я нахожу странным, что компилятор или интерпретатор сценариев потребовал ()
бы успешного обнаружения его как вызова функции. Если известно, что переменная может быть вызвана, почему этого function_name;
недостаточно?
С другой стороны, на некоторых языках мы можем сделать: function_name 'test';
или даже function_name 'first' 'second';
вызвать функцию или команду.
Я думаю, что круглые скобки были бы лучше, если бы они были необходимы только для объявления порядка приоритета, а в других местах были необязательными. Например, делать if expression == true function_name;
должно быть так же, как if (expression == true) function_name();
.
Самое неприятное, на мой взгляд, это делать, 'SOME_STRING'.toLowerCase()
когда явно не нужны аргументы для функции-прототипа. Почему дизайнеры решили против простого 'SOME_STRING'.lower
?
Отказ от ответственности: не поймите меня неправильно, я люблю C-подобный синтаксис! ;) Я просто спрашиваю, может ли это быть лучше. Есть ли у требования ()
преимущества в производительности или облегчает понимание кода? Мне действительно любопытно, в чем именно причина.
источник
()
, и все же в вашем посте выделяетсяif (expression == true)
утверждение. Вы беспокоитесь о лишних()
, но тогда используйте лишнее== true
:)Ответы:
Для языков, которые используют первоклассные функции , довольно часто синтаксис ссылки на функцию:
в то время как акт вызова этой функции:
a
в приведенном выше примере будет ссылка на вышеуказанную функцию (и вы можете вызвать ее, выполнивa()
), аb
будет содержать возвращаемое значение функции.Хотя некоторые языки могут делать вызовы функции без скобок, это может привести к путанице , являются ли они вызов функции, или просто обращаясь к функции.
источник
make_list
которая упаковывает свои аргументы в список, есть большая разница междуf(make_list)
передачей функцииf
или передачей пустого списка.SATInstance.solve
или другую невероятно дорогую чистую функцию другой функции, не пытаясь немедленно запустить ее. Это также делает вещи действительно неловкими, еслиsomeFunction
делает что-то другое в зависимости от тогоsomeFunction
, объявлен ли он чистым. Например, если у меня есть (псевдокод)func f() {return g}
,func g() {doSomethingImpure}
иfunc apply(x) {x()}
, затемapply(f)
звонитf
. Если я тогда заявляю, чтоf
это чисто, то внезапноapply(f)
переходитg
кapply
,apply
звонитg
и делает что-то нечистое.apply(f)
, еслиg
это нечисто (apply
а также?), Тогда все это нечисто и, конечно, разрушается.foo.bar()
не является одной операцией «вызов методаbar
объектаfoo
», а скорее двумя операциями: «поле разыменованияbar
объектаfoo
и затем вызов объекта, возвращенного из этого поля». Таким образом,.
это оператор поля селектора и()
является оператором вызова , и они независимы.Действительно, Scala позволяет это, хотя и существует соглашение: если метод имеет побочные эффекты, в любом случае следует использовать круглые скобки.
Как писатель компилятора, я считаю, что наличие круглых скобок довольно удобно; Я всегда знал бы, что это вызов метода, и мне не пришлось бы встраивать бифуркацию для нечетного случая.
Как программист и читатель кода, наличие круглых скобок не оставляет сомнений в том, что это вызов метода, даже если параметры не передаются.
Передача параметров не является единственной определяющей характеристикой вызова метода. Почему я должен относиться к методу без параметров, который отличается от метода с параметрами?
источник
def foo()
это метод с одним пустым списком параметров, иdef foo
это метод без списка параметров, и это разные вещи ! Как правило, метод без списка параметров должен вызываться без списка аргументов, а метод с пустым списком параметров должен вызываться с пустым списком аргументов. Вызов метода без списка параметров с пустым аргументом на самом деле ...apply
метода объекта, возвращаемого вызовом метода с пустым списком аргументов, тогда как вызов метода с пустым списком параметров без списка аргументов может в зависимости от контекста интерпретироваться по-разному как вызов метода с пустым списком аргументов, η-расширение в частично примененный метод (т. е. «справочник по методу»), иначе он может не скомпилироваться вообще. Кроме того, Scala следует принципу унифицированного доступа, не разделяя (синтаксически) различие между вызовом метода без списка аргументов и ссылкой на поле.На самом деле это довольно тонкая случайность выбора синтаксиса. Я буду говорить с функциональными языками, которые основаны на типизированном лямбда-исчислении.
В указанных языках каждая функция имеет ровно один аргумент . То, что мы часто называем «множественными аргументами», на самом деле является единственным параметром типа продукта. Так, например, функция, которая сравнивает два целых числа:
занимает одну пару целых чисел. Скобки не обозначают параметры функции; они используются для сопоставления с аргументом. Чтобы убедить вас, что это действительно один аргумент, мы можем вместо этого использовать проективные функции вместо сопоставления с образцом для деконструкции пары:
Таким образом, круглые скобки действительно являются удобством, которое позволяет нам сопоставлять шаблоны и сохранять некоторые данные. Они не обязательны.
Как насчет функции, которая якобы не имеет аргументов? Такая функция на самом деле имеет домен
Unit
. Одиночный членUnit
обычно пишется как()
, поэтому и появляются круглые скобки.Чтобы вызвать эту функцию, мы должны применить ее к значению типа
Unit
, которое должно быть()
, поэтому мы заканчиваем писатьsay_hi ()
.Таким образом, действительно нет такой вещи, как список аргументов!
источник
()
напоминают ложки минус ручку.leq
функции, которая использует,<
а не<=
довольно запутанно!()
для представления устройства. Я не удивлюсь, если хотя бы одна из причин будет напоминать «функцию без параметров». Однако есть и другое возможное объяснение синтаксиса. В алгебре типовUnit
фактически есть тождество для типов товаров. Бинарный продукт записывается как(a,b)
, мы могли бы написать унарный продукт как(a)
, поэтому логическим расширением было бы написать нулевой продукт так же просто()
.Например, в Javascript использование имени метода без () возвращает саму функцию без ее выполнения. Таким образом, вы можете, например, передать функцию в качестве аргумента другому методу.
В Java был сделан выбор, что идентификатор, за которым следует () или (...), означает вызов метода, а идентификатор без () ссылается на переменную-член. Это может улучшить читабельность, так как вы не сомневаетесь, имеете ли вы дело с методом или переменной-членом. Фактически, одно и то же имя может использоваться как для метода, так и для переменной-члена, оба будут доступны с соответствующим синтаксисом.
источник
Perl Best Practices
делаетObject::toString
определяет метод.Синтаксис следует семантике, поэтому давайте начнем с семантики:
Есть, на самом деле, несколько способов:
Наличие схожего синтаксиса для разных целей - лучший способ создать либо неоднозначный язык, либо, по крайней мере, запутанный (и у нас его достаточно).
В C и C-подобных языках:
func()
&func
(C создает указатель на функцию)someVariable::someMethod
например (ограничено приемником метода, но все еще полезно)Обратите внимание, что каждое использование имеет свой синтаксис, что позволяет легко их различать.
источник
::
Оператор в Java является частичным оператором приложения, а не оператор Выделки. Частичное приложение - это операция, которая принимает функцию и одно или несколько значений и возвращает функцию, принимающую меньшее количество значений. Карринг действует только на функции, а не на значения.Ни один из других ответов не пытался решить вопрос: сколько должно быть избыточности в дизайне языка? Потому что даже если вы можете разработать язык так, чтобы
x = sqrt y
установить x в квадратный корень из y, это не означает, что вы обязательно должны это делать.В языке без избыточности каждая последовательность символов означает что-то, что означает, что если вы допустите одну ошибку, вы не получите сообщение об ошибке, ваша программа будет делать не то, что может сильно отличаться от того, что вы предназначено и очень сложно для отладки. (Как знает любой, кто работал с регулярными выражениями.) Небольшая избыточность - это хорошо, потому что она позволяет обнаруживать многие из ваших ошибок, и чем больше избыточность, тем выше вероятность того, что диагностика будет точной. Сейчас, конечно, вы можете зайти слишком далеко (никто из нас не хочет писать на языке COBOL в наши дни), но есть правильный баланс.
Избыточность также помогает удобочитаемости, потому что есть больше подсказок. Английский без избыточности будет очень трудно читать, и то же самое можно сказать о языках программирования.
источник
:=
и сравнение==
, и=
его можно использовать только для инициализации во время компиляции, то вероятность опечаток, превращающих сравнения в назначения, будет значительно уменьшена.()
вызов функции с нулевым аргументом, но также потребовался бы токен, чтобы «взять адрес» функции. Первое действие встречается гораздо чаще, поэтому сохранение токена в менее распространенном случае не так уж и полезно.На языке с побочными эффектами IMO действительно полезно различать (теоретически без побочных эффектов) чтение переменной
и вызов функции, которая может вызвать побочные эффекты
OTOH, если нет никаких побочных эффектов (кроме тех, которые закодированы в системе типов), тогда нет никакого смысла даже различать чтение переменной и вызов функции без аргументов.
источник
noun.verb
синтаксис может быть таким же понятным по смыслу, какnoun.verb()
и немного менее загроможденным. Точно так же функция,member_
возвращающая левую ссылку, может предложить дружественный синтаксис, чем обычная функция-установщик:obj.member_ = new_value
vs.obj.set_member(new_value)
(_
постфикс - это подсказка, говорящая «выставлено», напоминающее_
префиксы для «скрытых» функций).noun.verb
означает вызов функции, как вы отличаете ее от простого доступа к члену?В большинстве случаев это синтаксический выбор грамматики языка. Для грамматики полезно, чтобы различные индивидуальные конструкции были (относительно) однозначными, когда все они взяты вместе. (Если есть неоднозначности, как в некоторых объявлениях C ++, должны быть определенные правила для разрешения.) У компилятора нет широты для угадывания; необходимо следовать спецификации языка.
Visual Basic в различных формах различает процедуры, которые не возвращают значение, и функции.
Процедуры должны быть вызваны как операторы, и для них не нужны парены, просто аргументы, разделенные запятыми, если они есть. Функции должны быть вызваны как часть выражения и требуют скобок.
Это относительно ненужное различие, которое делает ручной рефакторинг между двумя формами более болезненным, чем должно быть.
(С другой стороны , Visual Basic использует те же скобки
()
для ссылок на массивы как для вызовов функций, поэтому ссылки на массив выглядят вызовы функций. И это облегчает ручную рефакторинг массива в вызов функции! Таким образом, мы могли бы подумать другие языки используют[]
«ю.ш. для ссылок на массивы, но я отвлекся ...)В языках C и C ++ доступ к содержимому переменных осуществляется автоматически с использованием их имени, и если вы хотите обратиться к самой переменной, а не к ее содержимому, вы применяете унарный
&
оператор.Этот вид механизма также может быть применен к именам функций. Необработанное имя функции может подразумевать вызов функции, тогда как унарный
&
оператор будет использоваться для ссылки на функцию (саму) как на данные. Лично мне нравится идея доступа к функциям без аргументов без побочных эффектов с тем же синтаксисом, что и для переменных.Это вполне правдоподобно (как и другие синтаксические варианты для этого).
источник
call <procedure name> (<arguments>)
? Я уверен, что это был верный способ использования процедур, когда я занимался программированием QuickBASIC в другой жизни ...Call
метод, который мне почти никогда не нужен в «нормальном» рабочем коде.Согласованность и удобочитаемость.
Если я узнаю , что вы вызываете функцию
X
вроде этого:X(arg1, arg2, ...)
, то я ожидаю , что это работает так же , как для каких - либо аргументов:X()
.Теперь в то же время я узнаю, что вы можете определить переменную как некоторый символ и использовать ее следующим образом:
Что бы я подумал, когда найду это?
Твоя догадка так же хороша как и моя. В нормальных условиях
X
переменная. Но если бы мы пошли по твоему пути, это тоже могло бы стать функцией! Должен ли я вспомнить, соответствует ли какой символ какой группе (переменным / функциям)?Мы могли бы наложить искусственные ограничения, например «Функции начинаются с заглавной буквы. Переменные начинаются с строчной буквы», но это излишне и усложняет задачу, хотя иногда может помочь некоторым целям разработки.
Примечание 1: Другие ответы полностью игнорируют еще одну вещь: язык может позволить вам использовать одно и то же имя как для функции, так и для переменной, и различать по контексту. Смотрите
Common Lisp
в качестве примера. Функцияx
и переменнаяx
прекрасно сосуществуют.Побочное примечание 2: Принятый ответ показывает нам синтаксис:
object.functionname
. Во-первых, он не универсален для языков с первоклассными функциями. Во-вторых, как программист, я бы отнесся к этому как к дополнительной информации:functionname
принадлежитobject
. Является лиobject
объект, класс или пространство имен не имеет большого значения, но он говорит мне, что он где-то принадлежит . Это означает, что вы должны либо добавить искусственный синтаксисobject.
для каждой глобальной функции, либо создать такой,object
чтобы он содержал все глобальные функции.И в любом случае, вы теряете возможность иметь отдельные пространства имен для функций и переменных.
источник
Чтобы добавить к другим ответам, возьмите этот пример C:
Если оператор вызова был необязательным, не было бы никакой возможности различить назначение функции и вызов функции.
Это еще более проблематично в языках, в которых отсутствует система типов, например, JavaScript, где вывод типа не может использоваться для определения того, что является и не является функцией.
источник
function cross(a, b) { return a + b; }