2009-10-20 1 views
9

c, java и многие другие языки не обращают внимания на возвращаемые значения.Почему языки не допускают перегрузку методов по возвращаемому значению?

int i = func() 
float f = func() 
int func() { return 5 } 
float func() { return 1.3} 

Почему не является законным? Сложнее ли программировать

int i = func(func(func(func2(func3())))) //you dont know what you are getting 

Трудно ли написать компилятор? есть ли более однозначная формулировка языка? Есть ли язык, который может сделать выше?

+0

Вы пробовали LISP ?? Если не попробовать, это может решить вашу проблему. – Zinx

+0

Возможный дубликат [Перегрузка функций по типу возврата?] (Http://stackoverflow.com/questions/442026/function-overloading-by-return-type) – nawfal

ответ

14

Скажем, это было позволено, что бы этот вызов:

func(); 

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

+1

Это хороший момент. Параметры обычно требуются для функций, но обработка возвращаемого значения - нет. – Herms

+2

Я считаю неправильной практикой не обрабатывать возвращаемые значения. Это должно быть недействительным, забрасывая исключение или должно быть проверено возвращаемое значение. Однако var v = func(); (Назначение стиля C#) может вызвать проблемы ... (hmmmm)) – 2009-10-20 19:16:14

+0

+1 за то, что я признал var v = выше – 2009-10-20 19:16:45

17

Как насчет этого случая?

class A implements Foo { /*...*/ } 
class B implements Foo { /*...*/ } 

A func() { return new A(); } 
B func() { return new B(); } 

Foo v = func(); // which do you call?! 

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

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

+2

Точно так же должно быть 'System.out.println (func () + func()) 'output? – notnoop

+0

Это сделает код более сложным для понимания. +1. Может быть, я буду отмечать это как правильное (я хочу увидеть другие ответы) – 2009-10-20 19:18:09

+0

Как насчет того, чтобы одна из перегрузок была помечена как «предпочтительная», а другие использовались только тогда, когда тип возвращаемого текста был немедленно отброшен или принужден к другому типу (для которых предусмотрена более точная перегрузка) или когда тип возврата игнорируется (в этом случае будет использоваться перегрузка 'void', если она включена)? – supercat

6

Например C++, рассмотрим:

void g(int x); 
void g(float x); 
g(func()); 

Какой из перегруженных g() функций будет называться?

+1

, в этом случае он мог бы делать то, что иногда делает C++, и компилирует с неоднозначной ошибкой, заставляя пользователя писать 'g ((Float_OR_int_type) func());' – 2009-10-20 19:14:41

+0

Даже это не помогло бы. Что делать, если у вас есть несколько методов, которые возвращают тип, который можно корректно применить к объекту, на который вы клонируете? int может быть отлит для float и наоборот. – Herms

1

Большинство языков допускают операции смешанного режима с автоматическим принуждением (например, float + int), где допускаются множественные интерпретации. Без принуждения работа с несколькими числовыми типами (короткий, int, long, float, double) станет очень громоздкой; с принуждением, основанное на возврате тип disambigation приведет к трудно понятному коду.

1

Разрешение этих проблем может вызвать проблемы. Например:

int i = func2(func()); 
int func() { return 5; } 
float func() { return 1.3; } 
int func2(float a) { return a; } 
int func2(int a) { return a; } 

Это неоднозначно.

+0

Что было бы неправильно при указании, что каждая подпись метода должна иметь одну реализацию, которая помечается как предпочтительная, за исключением случаев, когда результат функции был либо назначен переменной, либо сразу же typecast? – supercat

3

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

+0

Что работает для Perl, но в Perl есть несколько вещей, которые, я думаю, не будут работать на более традиционном языке. Не говоря уже о том, что Perl не имеет системы типов в обычном смысле: типы - это $ scalars, @arrays, #hashes, @typeglobs, и мне кажется, что я их забыл. Не существует различия между integer, float и string, и операторы должны выяснить, следует ли действовать численно ($ i + 1) или со строками ($ i + "1"). –

+0

@ Давид: Я не думаю, что я восхвалял любые достоинства Perl в своем ответе и не предполагал, что такие вещи * должны быть добавлены к другим языкам. Я просто отвечал на вопрос, который спрашивает, что там. – Novelocrat

10

Да, разрешая перегрузку по типам возврата, усложняет язык. Это усложняет решение перегруженных идентификаторов (например, имена функций). Но это невозможно, например. Haskell позволяет перегружать функцию на основе возвращаемого типа.

class Num a where 
    fromInteger :: Integer -> a 
    ... 

Num класс типа в Haskell с методом, который называется fromInteger, который является функцией от произвольного размера Integer до произвольного типа, который имеет экземпляр Num. Механизм класса типа Haskell довольно отличается от концепции класса объектно-ориентированных языков. Поэтому мое объяснение может показаться странным.

Но в результате я могу использовать функцию fromInteger и, в зависимости от вызывающего контекста, различные реализации chooen во время компиляции.

Существует целая серия исследований систем типа, которые сделали эту функцию возможной. Поэтому я бы сказал, что это выполнимо в статически типизированных языках. Динамически типизированные языки либо потребуют путешествия во времени, либо некоторые умные идеи.

9

Чтобы избежать двусмысленности.

a(int) 
a(bool) 
int b() 
bool b() 

a(b()) -- Which b? 

Здесь тип вывода имеет циклическую зависимость. Какой b зависит от того, a, но который a зависит от того, b, так что он застревает.

Запрет перегрузки возвращаемых типов гарантирует, что вывод типа ацикличен. Тип возвращаемого значения всегда может определяться типами параметров, но типы параметров не могут определяться возвращаемым типом, поскольку они могут, в свою очередь, определяться типами параметров, которые вы пытаетесь найти.

+1

+1 для действительно красивого, краткого, прямого примера. –

+1

+1 для упоминания вывода типа –

+0

Существует много неоднозначных ситуаций, но это не означает, что перегрузка не может быть полезна, если использовать (1) некоторую «первичную» функцию, за исключением случаев, когда другая явно превосходит, и (2) в случаях, которые все еще были бы неоднозначными, компилятор мог бы использовать либо. Рассмотрим функции (int32, int32) -> int32, (int32, int32) -> int64 и (int64, int64) -> int64. Если они дают семантически тождественное поведение в случаях, когда вычисленное значение было бы внутри int32, компилятор мог бы использовать (int64, int64) -> int64 всегда, но производительность могла бы быть лучше, если вместо этого использовались (int32, int32) -> int32. – supercat

Смежные вопросы