Почему возвращаемый тип метода не включен в подпись метода?

Почему возвращаемый тип метода не включен в подпись?

Пример

public void method1(String arg){...}

public String method1(String arg){...}

Это приведет к ошибке.

Ответ 1

Это сделано потому, что компилятор не сможет определить перегрузку во всех контекстах all contexts.

Например, если вы позвоните

String x = method1("aaa");

компилятор знает, что вы ищете вторую перегрузку. Тем не менее, если вы позвоните

method1("aaa");

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

Ответ 2

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

func some() -> Bool {
    return true;
}

func some() -> Int {
    return 1;
}

let valBool: Bool = some()
let valInt: Int = some()

// this doesn't work: Ambiguous use of 'some'
some()

В дополнение к этому Swift даже делает его более интересным. Это позволяет вам иметь 2 функции/методы с одинаковыми параметрами и типами возврата только в том случае, если имена параметров различны, например:

func some(#foo: Bool) -> Bool {
    return foo;
}

func some(#bar: Bool) -> Bool {
    return bar;
}

some(foo: true)
some(bar: false)

Таким образом, это дает вам семантическую дифференциацию в подписи методов

UPD. Поскольку имя внешнего параметра Swift 2.0 было изменено, и теперь вы должны дважды указывать внешние и локальные имена, даже если это одно и то же

func some(foo foo: Bool) -> Bool {
    return foo;
}

func some(bar bar: Bool) -> Bool {
    return bar;
}

some(foo: true)
some(bar: false)

Ответ 3

Вы не можете перегружать метод только возвращаемым типом. Это просто незаконно. Предположим на мгновение, что методы перегрузки с использованием типа возврата будут законными, и вы определили два метода method1. Теперь мы хотим называть то, что возвращает String object:

String string = method1(sth);

JVM теоретически сможет распознать, какой метод вы хотели бы назвать, но как насчет такого вызова:

method1(sth);

Как вы можете видеть, оба метода могут быть вызваны, и такие операции недвусмысленны. JVM не знает, какой метод он должен назвать. Вот почему такая перегрузка запрещена.

Ответ 4

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

public static void main(String... args) {
    method1("aaa");
}

Ответ 5

При проектировании таких вещей, как разрешение перегрузки, необходимо учитывать несколько моментов.

Причины отказа от перегрузки по типу возврата:

  1. Упростите игнорирование возвращаемого значения функции (например, люди часто делают с кодами ошибок).
  2. Делает программу легче переваривать для читателей. В частности, это причина в Python, у них вообще нет функциональных перегрузок. (вопрос вкуса)
  3. C. Когда язык приходит из C-семьи, а дизайнеры не считают, что что-то очень важно, оно остается таким, каким оно всегда было...

Причины добавления перегрузки по типу возврата:

  1. Не рекомендуется игнорировать возвращаемые значения. Это может быть удобно и экономит некоторую типизацию, но определенно укусит вас в один прекрасный день.
  2. Выразительность (конечно, в отличие от простоты переваривания :)). Вы когда-нибудь хотели писать такие вещи, как int x = json.get("int_value"); float y = json.get("float_value"); int x = json.get("int_value"); float y = json.get("float_value"); ? На некоторых языках (например, C++), которые все еще можно достичь с помощью прокси и операторов трансляции, но перегрузка по типу возврата будет намного проще.
  3. Выразительность. Каждый раз, когда вы передаете значение retun в качестве ссылки на свою функцию только для повторного использования своих ресурсов, это может быть перегрузка по типу возврата (с таким же скрытым параметром). Рассмотрим string s; getline(cin, s); string s; getline(cin, s); vs string s = getline(cin); , И именно здесь выразительность сочетается с ссылочной прозрачностью и, в конечном счете, легкостью переваривания кода.

Вернемся к вашему вопросу "почему?". Поскольку вы спрашивали о Java, ответ, очевидно, объясняется тем, что Джеймс ценил причины отказа от возвращаемых типов перегрузок по причинам, чтобы включить их в язык.

Ответ 6

вы можете вызвать функцию как процедуру: method1("arg"); где method1 - второй метод в вашем списке (String method1(String arg){}). Компилятор тогда не сможет отличить его от первого (void method1(String arg){}).

Ответ 7

Компилятор заботится о привязке метода. Когда он сталкивается с methodName(), он должен связываться с определением метода, в этот момент он может не знать тип возвращаемого метода. Таким образом, тип возвращаемого значения метода не включен в сигнатуру метода. Компилятор связывает метод в соответствии с сигнатурой метода.

Ответ 8

Перегрузка метода проверяется на основе количества и типа аргументов, а не на основе типа возвращаемого значения. Вот почему вы получаете ошибку.