Я не читал документы по новому языковому стандарту, но я бы предположил, что ваши абоненты до версии 4.0 должны будут передать все объявленные параметры, как они это делают сейчас. Это из-за способа передачи параметров.
Когда вы вызываете метод, аргументы помещаются в стек. Если переданы три 32-битных аргумента, то в стек будут помещены 12 байтов; если переданы четыре 32-битных аргумента, то в стек будут помещены 16 байтов. Количество байтов, помещаемых в стек, неявно указано в вызове: вызываемый объект предполагает, что передано правильное количество аргументов.
Таким образом, если функция принимает четыре 32-битных параметра, она будет искать в стеке 16 байтов, предшествующих адресу возврата вызывающей стороны. Если вызывающий передал только 12 байтов, то вызываемый будет считывать 4 байта из того, что уже было в стеке, прежде чем был сделан вызов. Он не может знать, что все 16 ожидаемых байтов не были переданы.
Вот как это работает сейчас. Это не изменится для существующих компиляторов.
Для поддержки необязательных параметров должно произойти одно из двух:
- Вызывающий может передать дополнительное значение, которое явно сообщает вызываемому, сколько аргументов (или байтов) было помещено в стек. Затем вызываемый абонент может заполнить значения по умолчанию для любых пропущенных параметров.
- Вызывающий может продолжить передачу всех объявленных параметров, подставив значения по умолчанию (которые будут считаны из метаданных вызываемого) для любых необязательных параметров, пропущенных в коде. Затем вызываемый объект считывает все значения параметров из стека, как это происходит сейчас.
Я подозреваю, что это будет реализовано, как в (2) выше. Это похоже на то, как это делается в C ++ (хотя C ++, в котором отсутствуют метаданные, требует, чтобы параметры по умолчанию были указаны в заголовочном файле), более эффективно, чем опция (1), поскольку все это делается во время компиляции и не требует дополнительного значения, помещаемого в стек, и является наиболее простой реализацией. Недостаток опции (2) состоит в том, что, если значения по умолчанию изменяются, все вызывающие программы должны быть перекомпилированы, иначе они будут продолжать передавать старые значения по умолчанию, так как они были скомпилированы как константы. Это похоже на то, как теперь работают публичные константы. Обратите внимание, что опция (1) не имеет этого недостатка.
Опция (1) также не поддерживает передачу именованных параметров, поэтому функция, объявленная следующим образом:
static void Foo(int a, int b = 0, int c = 0){}
это можно назвать так:
Foo(1, c: 2);
Параметр (1) можно изменить, чтобы учесть это, сделав дополнительное скрытое значение битовой картой пропущенных аргументов, где каждый бит представляет один необязательный параметр. Это произвольно ограничивает число необязательных параметров, которые может принять функция, хотя, учитывая, что это ограничение будет по крайней мере 32, это может быть не так уж плохо. Однако крайне маловероятно, что это фактическая реализация.
При любой реализации вызывающий код должен понимать механизм необязательных параметров, чтобы пропустить любые аргументы в вызове. Кроме того, с опцией (1) должен быть передан дополнительный скрытый параметр, о котором старые компиляторы даже не знали бы, если бы он не был добавлен в качестве формального параметра в метаданные.