Почему необязательные параметры должны стоять в конце объявления

Во всех языках программирования, поддерживающих необязательные параметры, которые я видел, есть имитация того, что необязательные параметры должны появляться в конце объявления. Никакие обязательные параметры не могут быть включены после необязательного элемента. В чем причина этого? Я предполагаю, что это может быть требование компилятора/интерпретатора.


person Incognito    schedule 24.05.2010    source источник


Ответы (6)


Ну, а если бы они были на фронте, как бы вы определили, что их перестали снабжать? Единственным способом было бы, если бы тип переменной был другим после необязательных параметров. Немного странное требование, поэтому имеет смысл просто заставить их быть последними (избавьтесь от сложных правил для определения «последнего» необязательного параметра).

Кроме того, это наиболее естественный способ сделать это при вызове функции.

person Noon Silk    schedule 24.05.2010
comment
Да, это выглядит так очевидно сейчас :). Спасибо. - person Incognito; 24.05.2010
comment
@Incognito: он отлично работает в Ruby. Если после необязательных идут обязательные параметры, то обязательные аргументы берутся с конца списка аргументов. Все, что осталось, это необязательные аргументы. См. StackOverflow.Com/questions/2896106/ для примера. - person Jörg W Mittag; 25.05.2010

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

Он отлично работает в Ruby:

def foo(m1, m2, o1='o1', o2='o2', *rest, m3, m4)
  return m1, m2, o1, o2, rest, m3, m4
end

foo(1, 2, 3, 4)
# => [1, 2, 'o1', 'o2', [], 3, 4]

foo(1, 2, 3, 4, 5)
# => [1, 2, 3, 'o2', [], 4, 5]

foo(1, 2, 3, 4, 5, 6)
# => [1, 2, 3, 4, [], 5, 6]

foo(1, 2, 3, 4, 5, 6, 7)
# => [1, 2, 3, 4, [5], 6, 7]

foo(1, 2, 3, 4, 5, 6, 7, 8)
# => [1, 2, 3, 4, [5, 6], 7, 8]

Должны быть указаны все обязательные аргументы:

foo(1, 2, 3)
# => ArgumentError: wrong number of arguments (3 for 4)

Без параметра rest предоставление большего количества аргументов, чем число_обязательных + число_необязательных, является ошибкой:

def bar(m1, m2, o1='o1', o2='o2',  m3, m4)
  return m1, m2, o1, o2, m3, m4
end

bar(1, 2, 3, 4, 5, 6, 7)
# => ArgumentError: wrong number of arguments (7 for 6)

Обязательные параметры в начале списка параметров привязываются слева направо от начала списка аргументов. Обязательные параметры в конце списка параметров привязываются справа налево от конца списка аргументов. Необязательные параметры привязываются слева направо от начала оставшегося списка аргументов. Все оставшиеся аргументы привязываются к остальным аргументам.

person Jörg W Mittag    schedule 24.05.2010
comment
Очевидно правильно --- тем более, что у вас есть рабочий пример, чтобы показать. Но я придираюсь к тому, что с-подобные языки в основном строятся из простых правил, а путь ruby ​​многословен: это было бы большим сюрпризом в с и, по крайней мере, небольшим в с++. - person dmckee --- ex-moderator kitten; 25.05.2010
comment
@dmckee: Единственный известный мне C-подобный язык с необязательными аргументами — это C#, но его правила чрезвычайно сложны из-за сложных взаимодействий между необязательными аргументами и перегрузки на основе арности. Я нахожу их оба как минимум одинаково сложными, возможно, C# даже немного сложнее. - person Jörg W Mittag; 27.05.2010
comment
Здесь скрывается еще более фундаментальное правило: все необязательные параметры должны быть непрерывными. Вы правы в том, что один непрерывный блок из них может легко появиться в любом месте списка, хотя влияние на разрешение перегрузки на основе типов (если оно у вас есть) может быть очень странным. - person Davis Herring; 06.05.2020

Рассмотрим объявление вроде:

int foo(float a, int b=0, int c=0, float d);

(обратите внимание, как я определил параметры по умолчанию в середине списка), которые впоследствии вызываются как

foo(0.0,1,2.0)

Какой звонок? В частности, были ли опущены b или c?

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

foo(a=0,c=0,d=2.0)

функция, доступная, например, в python.

person dmckee --- ex-moderator kitten    schedule 24.05.2010
comment
Эта функция также доступна в C#: foo(a: 0, c: 0, d: 2.0). Проблема в том, что делать, когда делаются позиционные коллы. - person configurator; 24.05.2010
comment
Это прекрасно работает в Ruby. Обязательные параметры в начале списка параметров привязываются слева направо от начала списка аргументов. Обязательные параметры в конце списка параметров привязываются справа налево от конца списка аргументов. Необязательные параметры привязываются слева направо от начала оставшегося списка аргументов. Все оставшиеся аргументы привязываются к остальным аргументам. Отсутствие обязательного аргумента или предоставление более num_mandatory + num_optional аргументов при отсутствии остальных параметров является ошибкой. - person Jörg W Mittag; 25.05.2010
comment
В вашем конкретном примере a будет привязан к 0.0, d к 2.0, b к 1, а c получит значение по умолчанию 0. - person Jörg W Mittag; 25.05.2010
comment
@ Jore В приведенном выше примере, если я хочу передать 1 в c и заставить b использовать его значение по умолчанию, что мне делать? Похоже, что в Ruby 'b' не является обязательным... - person Bolu; 27.09.2010

Необязательные параметры в конце позволяют вам прекратить указывать параметры в какой-то момент, например.

void Test(int a, optional int b = 0, optional int c = 0) { ... } 

Test(3);

Если вы сделаете c обязательным параметром, вам придется использовать такой синтаксис:

Test(3, , 2);
Test(a := 3, c := 2);

Преимущество необязательного параметра в том, что его можно рассматривать так, как если бы его не было. Если необязательные параметры находятся в середине списка параметров, это невозможно без «подсчета запятых» или использования слишком подробного синтаксиса.

person Heinzi    schedule 24.05.2010
comment
Это прекрасно работает в Ruby. Обязательные параметры в начале списка параметров привязываются слева направо от начала списка аргументов. Обязательные параметры в конце списка параметров привязываются справа налево от конца списка аргументов. Необязательные параметры привязываются слева направо от начала оставшегося списка аргументов. Все оставшиеся аргументы привязываются к остальным аргументам. Отсутствие обязательного аргумента или предоставление более num_mandatory + num_optional аргументов при отсутствии остальных параметров является ошибкой. - person Jörg W Mittag; 25.05.2010

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

person Johannes Rudolph    schedule 24.05.2010
comment
Я бы сомневался в этом, я думаю, что вызывающий абонент просто нажмет значения по умолчанию. - person tstenner; 24.05.2010

Java и С# не имеют именованных параметров, поэтому вы не можете:

myfunction(param1='Meh', optionalParam=2)

Ты должен сделать:

myfunction('Meh', 2)

Иначе

myFunction(2, 'Meh')

Неоднозначно. Как компилятор должен узнать, что вы имели в виду 2 в необязательном наборе параметров?

person cyborg    schedule 24.05.2010
comment
C# 4.0 имеет именованные параметры. - person Incognito; 24.05.2010