동적으로 유형이 지정된 언어로 단일 함수에서 다른 데이터 유형을 반환하는 것은 나쁜 생각입니까?


65

기본 언어는 정적으로 입력됩니다 (자바). Java에서는 모든 메소드에서 단일 유형을 리턴해야합니다. 예를 들어 조건부로 a를 반환 String하거나 조건부로 a를 반환하는 메서드를 사용할 수 없습니다 Integer. 그러나 예를 들어 JavaScript에서는 이것이 가능합니다.

정적으로 입력 된 언어로 이것이 왜 나쁜 생각인지 알 수 있습니다. 모든 메소드가 반환되면 Object(모든 클래스가 상속하는 공통 부모) 당신과 컴파일러는 당신이 다루고있는 것을 모릅니다. 런타임시 모든 실수를 발견해야합니다.

그러나 동적으로 유형이 지정된 언어에는 컴파일러가 없을 수도 있습니다. 동적으로 유형이 지정된 언어에서 여러 유형을 반환하는 함수가 나쁜 생각 인 이유는 분명하지 않습니다. 정적 언어에 대한 나의 배경은 그러한 함수를 작성하는 것을 피하게하지만, 내가 볼 수없는 방식으로 코드를 깨끗하게 만들 수있는 기능에 대해 염려하고 있습니다.


편집 : 예를 제거하려고합니다 (더 나은 것을 생각할 수있을 때까지). 나는 내가 만들려고하지 않은 지점에 대답하는 것이 사람들을 조종하고 있다고 생각합니다.


오류 사례에서 예외를 발생시키지 않는 이유는 무엇입니까?
TrueWill

1
@TrueWill 다음 문장에서 그 문제를 다룰 것입니다.
Daniel Kaplan

이것이 더 동적 인 언어에서 일반적인 관행이라는 것을 알고 있습니까? 기능적 언어에서는 일반적 이지만 규칙은 매우 명확합니다. 그리고 인수 가 다른 유형이 될 수있는 것이 일반적이라는 것을 알고 있습니다 (기본적으로 함수 오버로드를 수행하는 유일한 방법이기 때문에).이 값이 반환 값에 적용되는 것을 거의 보지 못했습니다. 내가 생각할 수있는 유일한 예제는 대부분 자동 배열 배치 / 언 랩핑이있는 PowerShell이며, 스크립팅 언어는 예외적입니다.
Aaronaught

3
언급되지 않았지만 리턴 유형을 매개 변수로 사용하는 함수의 예 (Java Generics에서도)가 있습니다. 예를 들어 Common Lisp에서는 (coerce var 'string)a string또는 (concatenate 'string this that the-other-thing)이와 비슷한 수율을 갖습니다 . 나도 같은 것을 썼다 ThingLoader.getThingById (Class<extends FindableThing> klass, long id). 그리고 거기에서, 나는 당신이 요청한 것을 서브 클래스로 돌려주는 것만을 반환 할 loader.getThingById (SubclassA.class, 14)수도 있습니다 : SubclassB확장 하는 것을 반환 할 수도 있습니다 SubclassA...
BRPocock

1
동적으로 입력 된 언어는 영화 The MatrixSpoon 과 같습니다 . 숟가락문자열 이나 숫자 로 정의하려고하지 마십시오 . 불가능합니다. 대신 ... 진실만을 이해하려고 노력하십시오. 숟가락 이 없습니다 .
Reactgular

답변:


42

다른 답변과 달리 다른 유형의 반환이 허용되는 경우가 있습니다.

실시 예 1

sum(2, 3)  int
sum(2.1, 3.7)  float

정적으로 유형이 지정된 일부 언어에는 과부하가 포함되므로 미리 정의 된 고정 유형을 반환하는 여러 가지 방법이 있다고 생각할 수 있습니다. 동적 언어에서 이는 다음과 같이 구현 된 동일한 기능 일 수 있습니다.

var sum = function (a, b) {
    return a + b;
};

동일한 함수, 다른 유형의 반환 값.

실시 예 2

OpenID / OAuth 컴포넌트로부터 응답을받는다고 상상해보십시오. 일부 OpenID / OAuth 제공자는 개인의 나이와 같은 추가 정보를 포함 할 수 있습니다.

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Facebook',
//     name: {
//         firstName: 'Hello',
//         secondName: 'World',
//     },
//     email: 'hello.world@example.com',
//     age: 27
// }

다른 사람들은 최소한 이메일 주소 나 가명 일 것입니다.

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Google',
//     email: 'hello.world@example.com'
// }

다시, 동일한 기능, 다른 결과.

여기서 다른 유형을 반환하는 이점은 유형과 인터페이스를 신경 쓰지 않고 실제로 객체에 포함되는 상황에서 특히 중요합니다. 예를 들어, 웹 사이트에 성숙한 언어가 포함되어 있다고 가정 해 봅시다. 그러면 다음 findCurrent()과 같이 사용될 수 있습니다.

var user = authProvider.findCurrent();
if (user.age || 0 >= 16) {
    // The person can stand mature language.
    allowShowingContent();
} else if (user.age) {
    // OpenID/OAuth gave the age, but the person appears too young to see the content.
    showParentalAdvisoryRequestedMessage();
} else {
    // OpenID/OAuth won't tell the age of the person. Ask the user himself.
    askForAge();
}

모든 공급자가 자체 정의 된 기능을 가지고있는 잘 정의 된 고정 유형을 리턴하는 코드로 이것을 리팩토링하면 코드베이스가 저하되고 코드 복제가 발생할뿐만 아니라 어떠한 이점도 얻지 못할 것입니다. 다음과 같은 공포가 생길 수도 있습니다.

var age;
if (['Facebook', 'Yahoo', 'Blogger', 'LiveJournal'].contains(user.provider)) {
    age = user.age;
}

5
"정적으로 입력 된 언어에서이 오버로드를 포함한다" 나는 당신이 "의 의미가 생각하는 몇 가지 : 정적으로 입력 된 언어로"좋은 정적으로 입력 된 언어는 같은 뭔가 오버로드를 필요로하지 않습니다 sum예.
Andres F.

17
구체적인 예를 들어 Haskell :을 고려하십시오 sum :: Num a => [a] -> a. 숫자 인 목록을 합칠 수 있습니다. 자바 스크립트와 달리 숫자가 아닌 것을 합산하려고하면 컴파일시 오류가 발생합니다.
Andres F.

3
스칼라에서 @MainMa Iterator[A]는 method def sum[B >: A](implicit num: Numeric[B]): B를 가지고 있는데, 이것은 다시 모든 종류의 숫자를 합산 할 수있게하고 컴파일 타임에 확인된다.
Petr Pudlák

3
@Bakuriu 물론 그런 함수를 작성할 수는 있지만, 먼저 +문자열에 과부하를가하거나 ( Num디자인 을 구현 하는 데는 끔찍한 아이디어이지만 구현 에 의해) 정수와 문자열에 의해 오버로드 된 다른 연산자 / 함수를 발명해야합니다 각기. Haskell은 타입 클래스를 통해 임시 다형성을 가지고 있습니다. 정수와 문자열을 모두 포함하는 목록은 훨씬 어렵지만 (언어 확장이 없으면 불가능할 수도 있음) 다소 다른 문제입니다.

2
나는 당신의 두 번째 예에 특별히 감명받지 않았습니다. 이 두 객체는 ​​동일한 개념의 "유형"이며 일부 경우 특정 필드가 정의되거나 채워지지 않습니다. 정적으로 유형이 지정된 언어에서도 null값을 사용하여 잘 표현할 수 있습니다.
Aaronaught

31

일반적으로 정적 인 형식의 언어에서 도덕적으로 동등한 것은 나쁜 생각과 같은 이유로 나쁜 생각입니다. 어떤 구체적인 유형이 반환되는지 모릅니다. 어떤 가치로도 할 수있는 일). 정적 유형 시스템에서는 반환 유형에 대한 컴파일러 검사 주석이 있지만 동적 언어에는 동일한 지식이 여전히 존재합니다. 이는 비공식적이며 소스 코드가 아닌 두뇌 및 문서에 저장됩니다.

그러나 많은 경우 유형이 반환되는 운율과 이유가 있으며 그 효과는 정적 유형 시스템의 과부하 또는 파라 메트릭 다형성과 유사합니다. 다시 말해, 결과 유형 예측 가능하지만 표현하기가 쉽지 않습니다.

그러나 특정 함수가 제대로 설계되지 않은 다른 이유가있을 수 있습니다. 예를 들어, sum유효하지 않은 입력에서 false를 반환 하는 함수는 반환 값이 쓸모없고 오류가 발생하기 쉬운 (0 <-> 잘못된 혼동) 기본적으로 나쁜 생각입니다.


40
내 두 센트 : 나는 그것이 일어날 때 싫어. 결과가 없으면 하나의 결과에 Object, 두 개 이상의 결과에 Array가 반환되는 JS 라이브러리를 보았습니다. 따라서 배열을 반복하는 대신 배열이 null인지 아닌지, 배열이 아닌지, 배열인지 여부를 결정해야합니다. 그렇지 않으면 한 가지 작업을 수행하고 그렇지 않으면 다른 작업을 수행하십시오. 특히, 정상적인 의미에서, 제정신 개발자는 Object를 Array에 추가하고 배열을 처리하지 못하도록 프로그램 로직을 재활용 할 것입니다.
phyrfox

10
@Izkata : 전혀 NaN"카운터 포인트 " 라고 생각하지 않습니다 . NaN은 실제로 모든 부동 소수점 계산에 유효한 입력입니다. NaN실제 숫자로 할 수있는 모든 것을 할 수 있습니다. 사실, 상기 계산의 최종 결과는 당신에게별로 유용하지 않을 수도 있지만, 이상한 런타임 오류가 발생하지 않으며 항상 확인할 필요가 없습니다 . 일련의 계산. NaN은 다른 유형 이 아니며 Null Object 와 같은 특별한 일뿐 입니다.
Aaronaught

5
@Aaronaught 반면에 NaN, null 객체와 마찬가지로 오류가 발생하면 나중에 숨길 때만 숨기는 경향이 있습니다. 예를 들어, NaN루프 조건부로 미끄러 지면 프로그램이 종료 될 수 있습니다.
이즈 카타

2
@Izkata : NaN과 null은 완전히 다른 동작을합니다. NaN이 전파되면 Null 참조가 액세스하자마자 폭발합니다. 후자가 발생하는 이유는 분명하므로 모든 하위 표현식의 결과를 확인하지 않고도 수학 표현식을 작성할 수 있습니다. NaN은 적절한 수치 개념을 나타 내기 때문에 개인적으로 null을 훨씬 더 손상시킵니다. 수학적으로 전파하지 않으면 올바른 행동입니다.
Phoshi

4
이것이 왜 "널 대 다른 것"논쟁으로 바뀌 었는지 모르겠다. 나는 단지 NaN값이 (a) 실제로 다른 반환 유형이 아니며 (b) 잘 정의 된 부동 소수점 의미를 가지고 있으므로 가변 유형의 반환 값과 유사하지 않다는 것을 지적했습니다. 정수 산술 에서 0 과 다른 것은 아닙니다 . 실제로; "실수로"0이 계산에 빠지면 결과로 0 또는 0으로 나누기 오류가 발생하는 경우가 많습니다. IEEE 부동 소수점으로 정의 된 "무한대"값도 악한가?
Aaronaught

26

동적 언어에서는 반환 여부를 물어 안 다른 유형 하지만 다른 API를 사용하여 객체 . 대부분의 동적 언어는 실제로 유형에 신경 쓰지 않지만 다양한 버전의 오리 입력을 사용 합니다.

다른 유형을 반환 할 때 의미가 있습니다.

예를 들어이 방법은 의미가 있습니다.

def load_file(file): 
    if something: 
       return ['a ', 'list', 'of', 'strings'] 
    return open(file, 'r')

파일과 문자열 목록은 모두 파이썬에서 문자열을 반환하는 반복 가능하기 때문에. 매우 다른 유형, 동일한 API (누군가가 목록에서 파일 메소드를 호출하려고하지 않는 한, 이것은 다른 이야기입니다).

조건부로 반환 list하거나 tuple( tuple파이썬에서는 불변 목록입니다).

공식적으로도 :

def do_something():
    if ...: 
        return None
    return something_else

또는:

function do_something(){
   if (...) return null; 
   return sth;
}

파이썬 None과 자바 스크립트 null는 모두 자체적 으로 유형이므로 다른 유형을 반환합니다 .

이 모든 유스 케이스는 정적 언어로 대응되며 함수는 적절한 인터페이스를 리턴합니다.

조건부로 다른 API를 가진 객체를 반환하는 것이 좋습니다

다른 API를 반환하는 것이 좋은 아이디어인지에 대해 대부분의 경우 IMO는 의미가 없습니다. 현명한 예는 @MainMa가 말한 것과 비슷 합니다. API가 다양한 세부 정보를 제공 할 수있을 때 사용 가능한 경우 더 자세한 정보를 반환하는 것이 좋습니다.


4
좋은 대답입니다. Java / 정적으로 유형이 동등한 것은 함수가 특정 구체적 유형이 아닌 인터페이스를 리턴하고 API / 추상화를 나타내는 인터페이스를 갖는 것입니다.
mikera

1
나는 당신이 nitpicking이라고 생각합니다. 파이썬에서 목록과 튜플은 다른 "유형"일 수 있지만 같은 "오리 유형"입니다. 즉, 동일한 연산 세트를 지원합니다. 그리고 이와 같은 경우는 오리 타이핑이 도입 된 이유입니다. Java에서도 long x = getInt () 할 수 있습니다.
Kaerber

"다양한 유형 반환" "다른 API를 사용하여 객체 반환 "을 의미 합니다. (일부 언어는 객체의 구성 방식을 API의 기본 부분으로 만들지 만, 그렇지 않은 경우도 있습니다. 유형 시스템의 표현력 문제입니다.) 목록 / 파일 예제에서 do_file문자열의 반복 가능한 방식을 반환합니다.
Gilles

1
이 Python 예제에서는 iter()목록과 파일을 모두 호출 하여 결과를 두 경우 모두 반복 자로 만 사용할 수 있도록 할 수도 있습니다.
RemcoGerlich

1
리턴 None or something은 PyPy, Numba, Pyston 등과 같은 도구로 수행되는 성능 최적화의 킬러입니다. 이것은 파이썬을 그렇게 빠르지 않게 만드는 파이썬주의 중 하나입니다.
Matt

9

당신의 질문은 내가 조금 울고 싶어합니다. 귀하가 제공 한 사용 예가 아니라 누군가가 무의식적으로이 접근 방식을 취하기 때문입니다. 엄청나게 유지 보수 할 수없는 코드에서 짧은 단계입니다.

오류 조건 유스 케이스 종류는 의미 가 있으며 정적으로 유형이 지정된 언어 의 null 패턴 (모든 패턴 이되어야 함)은 동일한 유형의 작업을 수행합니다. 함수 호출은 object또는을 반환합니다 null.

하지만 "나는 만들려면이를 사용하는거야 말에 짧은 단계의 공장 패턴을 반환"중 하나 foo또는 bar또는 baz함수의 기분에 따라. 이것을 디버깅하는 것은 호출자가 기대 foo하지만 받을 때 악몽이 될 것 bar입니다.

그래서 나는 당신이 마음을 닫고 있다고 생각하지 않습니다. 언어 기능을 사용하는 방법에 대해 신중한주의를 기울이고 있습니다.

공개 : 저의 배경은 정적으로 입력 된 언어로되어 있으며, 일반적으로 유지 관리 가능한 코드가 필요한 대규모의 다양한 팀에서 근무했습니다. 내 관점도 왜곡 될 수 있습니다.


6

Java에서 Generics를 사용하면 정적 유형 안전을 유지하면서 다른 유형을 리턴 할 수 있습니다. 함수 호출의 일반 유형 매개 변수에 리턴하려는 유형을 지정하기 만하면됩니다.

Javascript에서 비슷한 접근 방식을 사용할 수 있는지 여부는 명백한 질문입니다. Javascript는 동적으로 유형이 지정된 언어이므로를 반환하는 object것은 명백한 선택처럼 보입니다.

정적으로 유형이 지정된 언어로 작업 할 때 동적 리턴 시나리오가 작동하는 위치를 알고 싶다면 dynamicC # 에서 키워드를 검토하십시오 . Rob Conery는 키워드를 사용하여 400 줄의 코드 로 Object-Relational Mapper 를 성공적으로 작성할 수있었습니다 dynamic.

물론 dynamic실제로 모든 것은 object런타임 유형 안전으로 변수를 래핑하는 것 입니다.


4

다른 유형을 조건부로 반환하는 것은 나쁜 생각입니다. 이것이 나에게 자주 나타나는 방법 중 하나는 함수가 하나 이상의 값을 반환 할 수 있는지입니다. 하나의 값만 반환해야하는 경우 호출 함수에서 압축을 풀지 않기 위해 값을 Array로 포장하는 대신 값을 반환하는 것이 합리적 일 수 있습니다. 그러나 이것 (및 이것의 대부분의 다른 경우)은 호출자에게 두 가지 유형을 구별하고 처리 할 의무가 있습니다. 함수가 항상 같은 유형을 반환하는지 쉽게 추론 할 수 있습니다.


4

"나쁜 습관"은 언어를 정적으로 입력했는지 여부에 관계없이 존재합니다. 정적 언어는 이러한 관행을 피하기 위해 더 많은 노력을 기울이고 더 공식적인 언어이기 때문에 정적 언어에서 "나쁜 연습"에 대해 불평하는 사용자를 더 많이 찾을 수 있습니다. 그러나 근본적인 문제는 동적 언어로되어 있으며 문제의 정당화 여부를 결정할 수 있습니다.

여기 당신이 제안한 것에 반대하는 부분이 있습니다. 어떤 유형이 반환되는지 모르는 경우 반환 값을 즉시 사용할 수 없습니다. 나는 그것에 대해 무언가를 "발견해야"한다.

total = sum_of_array([20, 30, 'q', 50])
if (type_of(total) == Boolean) {
  display_error(...)
} else {
  record_number(total)
}

코드에서 이런 종류의 스위치는 종종 나쁜 습관입니다. 코드를 읽기 어렵게 만듭니다. 이 예에서는 예외 사례를 던지고 잡는 것이 왜 인기가 있는지를 보여줍니다. 다른 방법으로 말하면, 함수가 말하는 것을 수행 할 수 없다면 성공적으로 반환해서는 안됩니다 . 함수를 호출하면 다음과 같이하고 싶습니다.

total = sum_of_array([20, 30, 'q', 50])
display_number(total)

첫 번째 줄이 성공적으로 반환되므로 total실제로 배열의 합이 포함되어 있다고 가정합니다 . 성공적으로 반환되지 않으면 프로그램의 다른 페이지로 이동합니다.

오류 전파에 관한 것이 아닌 다른 예제를 사용하십시오. 어쩌면 sum_of_array는 똑똑하고 일부 경우에 "그건 내 사물함 조합입니다!"와 같이 사람이 읽을 수있는 문자열을 반환하려고 시도 할 것입니다. 배열이 [11,7,19] 인 경우에만 해당됩니다. 좋은 모범을 생각하는 데 어려움을 겪고 있습니다. 어쨌든 같은 문제가 적용됩니다. 반환 값을 검사하여 무엇이든 할 수 있습니다.

total = sum_of_array([20, 30, 40, 50])
if (type_of(total) == String) {
  write_message(total)
} else {
  record_number(total)
}

함수가 정수 또는 부동 소수점을 반환하는 것이 유용 할 것이라고 주장 할 수 있습니다. 예를 들면 다음과 같습니다.

sum_of_array(20, 30, 40) -> int
sum_of_array(23.45, 45.67, 67.789044) -> float

그러나 당신이 걱정하는 한, 그 결과는 다른 유형이 아닙니다. 당신은 그것들을 숫자로 취급 할 것이고, 그것이 당신이 관심을 갖는 전부입니다. 따라서 sum_of_array는 숫자 유형을 반환합니다. 이것이 다형성에 관한 것입니다.

따라서 함수가 여러 유형을 반환 할 수있는 경우 위반할 수있는 몇 가지 방법이 있습니다. 그것들을 알면 특정 함수가 여러 유형을 반환 해야하는지 결정하는 데 도움이됩니다.


미안하지만, 당신이 저의 불쌍한 모범으로 길을 잃었습니다. 내가 처음 언급 한 것을 잊어 버리십시오. 첫 번째 단락이 정해졌습니다. 나는 또한 두 번째 예를 좋아합니다.
Daniel Kaplan

4

실제로는 정적으로 형식이 지정된 언어로도 다른 형식을 반환하는 경우가 드물지 않습니다. 예를 들어, 유니온 타입이있는 이유입니다.

실제로 Java의 메소드는 거의 항상 네 가지 유형 중 하나를 반환합니다. 어떤 종류의 객체 또는 null예외 또는 전혀 반환하지 않습니다.

많은 언어에서 오류 조건은 결과 유형 또는 오류 유형을 리턴하는 서브 루틴으로 모델링됩니다. 예를 들어, 스칼라에서 :

def transferMoney(amount: Decimal): Either[String, Decimal]

물론 이것은 멍청한 예입니다. 반환 유형은 "문자열 또는 10 진수 반환"을 의미합니다. 일반적으로 왼쪽 유형은 오류 유형 (이 경우 오류 메시지가있는 문자열)이고 오른쪽 유형은 결과 유형입니다.

예외도 제어 흐름 구성이라는 사실을 제외하고는 예외와 유사합니다. 그들은 실제로 표현력과 동등하다 GOTO.


Java에서 예외를 반환하는 메서드가 이상하게 들립니다. " 돌아 예외 흠 ..."
모기

3
예외는 Java에서 메소드의 가능한 결과 중 하나입니다. 실제로, 나는 네 번째 유형을 잊어 버렸습니다 : Unit(방법이 전혀 반환 할 필요는 없습니다). 사실, 당신은 실제로 return키워드를 사용하지 않지만 그럼에도 불구하고 그 방법에서 나온 결과입니다. 확인 된 예외를 제외하면 유형 서명에 명시 적으로 언급되어 있습니다.
Jörg W Mittag

내가 참조. 당신의 요점은 약간의 장점이있는 것 같지만, 그것이 제시된 방식으로는 매력적으로 보이지 않습니다 ... 오히려 반대
gnat

4
많은 언어에서 오류 조건은 결과 유형 또는 오류 유형을 리턴하는 서브 루틴으로 모델링됩니다. 예외는 제어 흐름 구조이기도합니다 ( GOTO실제로 표현력과 동일 함 ).
Jörg W Mittag

4

아직까지 SOLID 원칙을 언급 한 답변이 없습니다. 특히 Liskov 대체 원칙을 따라야합니다. 예상되는 유형 이외의 유형을받는 모든 클래스는 어떤 유형이 반환되는지 테스트하기 위해 아무 것도 수행하지 않고도 얻을 수있는 모든 유형으로 계속 작동 할 수 있습니다.

따라서 객체에 추가 속성을 던지거나 원래 함수가 수행하려고했던 것을 여전히 달성하는 데코레이터로 반환 된 함수를 래핑하면 함수를 호출하는 코드가 이것에 의존하지 않는 한 좋습니다. 모든 코드 경로에서 동작

문자열이나 정수를 반환하는 대신 스프링클러 시스템이나 고양이를 반환하는 것이 더 좋은 예입니다. 모든 호출 코드가 수행하려는 경우 functionInQuestion.hiss ()를 호출하는 것이 좋습니다. 실제로 호출 코드가 기대하는 암시 적 인터페이스가 있으며 동적으로 유형이 지정된 언어를 사용하면 인터페이스를 명시 적으로 만들 수 없습니다.

안타깝게도 동료는 아마도 그렇게 할 것입니다. 따라서 인터페이스를 정의 할 때와 같이 보편적으로 받아 들여지고 기계적으로 분석 할 수있는 방법이 없다는 것을 제외하고는 문서에서 동일한 작업을 수행해야 할 것입니다 그것들을 가진 언어로.


3

내가 다른 유형을 보내는 것을 볼 수있는 곳은 "예외적"조건이 예외적이지 않은 잘못된 입력 또는 "가난한 사람 예외"입니다. 예를 들어, PHP 유틸리티 저장소 에서이 간단한 예를 보여줍니다.

function ensure_fields($consideration)
{
        $args = func_get_args();
        foreach ( $args as $a ) {
                if ( !is_string($a) ) {
                        return NULL;
                }
                if ( !isset($consideration[$a]) || $consideration[$a]=='' ) {
                        return FALSE;
                }
        }

        return TRUE;
}

이 함수는 명목상 BOOLEAN을 반환하지만 유효하지 않은 입력에서는 NULL을 반환합니다. 참고 PHP 5.3 이후, 모든 내부 PHP 기능이이 방식으로 작동합니다 . 또한 일부 내부 PHP 함수는 공칭 입력에서 FALSE 또는 INT를 반환합니다.

strpos('Hello', 'e');  // Returns INT(1)
strpos('Hello', 'q');  // Returns BOOL(FALSE)

4
그리고 이것이 내가 PHP를 싫어하는 이유입니다. 어쨌든 이유 중 하나입니다.
Aaronaught

1
누군가가 내가 전문적으로 개발 한 언어를 좋아하지 않기 때문에 공감 비?!? 그들이 내가 유대인이라는 것을 알 때까지 기다리십시오! :)
dotancohen

3
의견을 말한 사람과 공감하는 사람이 항상 같은 사람이라고 가정하지 마십시오.
Aaronaught

1
나는 null(a) 큰 소리로 실패 하기 때문에 개발 / 테스트 단계에서 수정 될 가능성이 높기 때문에 예외 대신을 선호합니다 . (b) 처리하기 쉽습니다. 내 전체 응용 프로그램 (프론트 컨트롤러에 있음)을 로그하고 (보통 개발자 팀에 전자 메일을 보냅니다) 나중에 수정할 수 있습니다. 그리고 실제로 표준 PHP 라이브러리는 대부분 "return null"접근 방식을 사용한다는 점이 싫습니다.-로 모든 것을 검사하지 않으면 PHP 코드가 오류가 발생하기 쉽습니다 isset().
scriptin

1
또한 null오류가 발생하면 docblock (예 :)에서 명확하게 @return boolean|null작성하십시오. 따라서 언젠가 코드를 발견하면 함수 / 메소드 본문을 확인할 필요가 없습니다.
scriptin

3

나는 이것이 나쁜 생각이라고 생각하지 않습니다! 이 가장 일반적인 의견과 달리 Robert Harvey가 이미 지적했듯이 Java와 같은 정적으로 유형이 지정된 언어는 사용자가 묻는 것과 같은 상황에 대해 Generics를 정확하게 도입했습니다. 실제로 Java는 컴파일 타임에 (가능한 경우) 유형 안전을 유지하려고 시도하며 때로는 제네릭이 코드 중복을 피하는 이유는 무엇입니까? 다른 유형을 처리 / 반환하는 동일한 메소드 또는 동일한 클래스를 작성할 수 있기 때문 입니다. 이 아이디어를 보여주는 간단한 예를 들어 보겠습니다.

자바 1.4

public static Boolean getBoolean(String property){
    return (Boolean) properties.getProperty(property);
}
public static Integer getInt(String property){
    return (Integer) properties.getProperty(property);
}

자바 1.5 이상

public static <T> getValue(String property, Class<T> clazz) throws WhateverCheckedException{
    return clazz.getConstructor(String.class).newInstance(properties.getProperty(property));
}
//the call will be
Boolean b = getValue("useProxy",Boolean.class);
Integer b = getValue("proxyPort",Integer.class);

동적 형식 언어에서는 컴파일 타임에 형식 안전성이 없으므로 많은 형식에서 작동하는 동일한 코드를 자유롭게 작성할 수 있습니다. 정적 타입 언어에서도이 문제를 해결하기 위해 제네릭이 도입되었으므로, 동적 언어로 다른 타입을 반환하는 함수를 작성하는 것은 나쁜 생각이 아니라는 힌트입니다.


설명없이 또 다른 공감대! SE 커뮤니티 감사합니다!
thermz

2
동정심을 가지고 +1하십시오. 보다 명확하고 직접적인 답변으로 답변을 열어보고 다른 답변에 대해서는 언급하지 마십시오. (나는 당신과 동의하기 때문에 당신에게 또 다른 +1을 줄 것이지만, 나는 오직 하나만 줄 것입니다.)
DougM

3
제네릭은 동적 형식 언어 (내가 아는)에는 존재하지 않습니다. 그럴 이유가 없었습니다. 대부분의 제네릭은 "컨테이너"가 그 안에있는 것보다 더 흥미로운 특별한 경우입니다 (Java와 같은 일부 언어는 실제로 유형 삭제를 사용하는 이유). 제네릭 형식은 실제로 자체 형식입니다. 일반적인 방법 , 없이 여기 예에서와 같이 실제 제네릭 형식은 거의 항상 단지 구문 설탕 있습니다 할당 및 캐스트 의미. 질문이 실제로 요구하는 것에 대한 특별한 예는 아닙니다.
Aaronaught

1
좀 더 동의어 적이다. "정적으로 유형이 지정된 언어에서도이 문제를 해결하기 위해 제네릭이 도입되었으므로, 동적 언어로 다른 유형을 반환하는 함수를 작성하는 것은 나쁜 생각이 아니라는 힌트이다." 더 나은 지금? Robert Harvey의 답변 또는 BRPocock의 의견을 확인하면 Generics의
예가이

1
기분 나빠 하지마, @thermz. Downvotes는 종종 작가보다 독자에 대해 더 많이 말합니다.
Karl Bielefeldt

2

소프트웨어 개발은 ​​기본적으로 복잡성을 관리하는 기술이자 기술입니다. 감당할 수있는 지점에서 시스템을 좁히고 다른 지점에서는 옵션을 제한하려고합니다. 함수의 인터페이스는 계약으로 모든 코드 작업에 필요한 지식을 제한함으로써 코드의 복잡성을 관리 할 수 ​​있습니다. 다른 유형을 반환하면 반환하는 다른 유형의 모든 인터페이스를 추가하고 반환되는 인터페이스에 대해 명백하지 않은 규칙을 추가하여 함수의 인터페이스를 크게 확장 할 수 있습니다.


1

함수가하는 것은 문맥에 따라 달라지기 때문에 펄은 이것을 많이 사용 한다 . 예를 들어, 함수는 목록 컨텍스트에서 사용되는 경우 배열을 반환하거나 스칼라 값이 필요한 위치에서 사용되는 경우 배열의 길이를 반환 할 수 있습니다. 다음 과 같은 경우 "perl context"에 대한 첫 번째 히트 인 학습서 에서 :

my @now = localtime();

그런 다음 @now는 배열 변수 (@가 의미하는 것)이며 (40, 51, 20, 9, 0, 109, 5, 8, 0)과 같은 배열을 포함합니다.

대신 결과가 스칼라 여야하는 방식으로 함수를 호출하는 경우 ($ 변수는 스칼라 임) :

my $now = localtime();

$ now는 "Fri Jan 9 20:51:40 2009"와 같은 형태가 될 것입니다.

내가 생각할 수있는 또 다른 예는 REST API를 구현하는 것입니다. 여기서 반환되는 형식은 클라이언트가 원하는 것에 따라 다릅니다. 예를 들어, HTML 또는 JSON 또는 XML입니다. 기술적으로 이것들은 모두 바이트 스트림이지만 아이디어는 비슷합니다.


당신은 펄에서이 작업을 수행하는 특정 방법을 언급 할 수 있습니다 - wantarray ... 어쩌면 그 좋은 또는 나쁜 경우 논의에 대한 링크 - wantarray의 사용이 PerlMonks에 유해 고려

우연히, 나는 내가 만들고있는 Java Rest API로 이것을 다루고있다. 하나의 리소스가 XML 또는 JSON을 반환 할 수있게했습니다. 이 경우 가장 작은 공통 분모 유형은입니다 String. 이제 사람들은 반환 유형에 대한 문서를 요구하고 있습니다. 클래스를 반환하면 Java 도구가 자동으로 생성 할 수 있지만 선택했기 때문에 String문서를 자동으로 생성 할 수 없습니다. 이야기의 뒷이야기 / 도덕에서, 나는 방법 당 하나의 유형을 반환하기를 바랍니다.
Daniel Kaplan

엄밀히 말하면 이것은 과부하 형태입니다. 즉, 여러 개의 연합 함수가 있으며 호출의 세부 사항에 따라 하나 이상의 버전이 선택됩니다.
Ian

1

역동적 인 나라에서는 오리 타이핑에 관한 것입니다. 가장 책임있는 노출 / 공개 대상은 잠재적으로 다른 유형을 랩퍼로 랩핑하여 동일한 인터페이스를 제공하는 것입니다.

function ThingyWrapper(thingy){ //a function constructor (class-like thingy)

    //thingy is effectively private and persistent for ThingyWrapper instances

    if(typeof thingy === 'array'){
        this.alertItems = function(){
            thingy.forEach(function(el){ alert(el); });
        }
    }
    else {
        this.alertItems = function(){
            for(var x in thingy){ alert(thingy[x]); }
        }
    }
}

function gimmeThingy(){
    var
        coinToss = Math.round( Math.random() ),//gives me 0 or 1
        arrayThingy = [1,2,3],
        objectThingy = { item1:1, item2:2, item3:3 }
    ;

    //0 dynamically evaluates to false in JS
    return new ThingyWrapper( coinToss ? arrayThingy : objectThingy );
}

gimmeThingy().alertItems(); //should be same every time except order of numbers - maybe

때로는 일반적인 래퍼를 사용하지 않고 7 년 동안 JS를 작성하는 동안 솔직히 다른 유형을 모두 제거하는 것이 합리적 일 수 있습니다. 대부분은 물건이 모이는 물체의 내부와 같은 닫힌 환경에서 할 것입니다. 그러나 모든 예제가 떠오를 정도로 자주 수행 한 것은 아닙니다.

대체로 타입에 대한 생각은 그만두라고 조언합니다. 동적 언어가 필요한 경우 유형을 처리합니다. 더 이상은 없어. 요점입니다. 모든 단일 인수의 유형을 확인하지 마십시오. 그것은 동일한 방법이 불명확 한 방식으로 불일치 한 결과를 줄 수있는 환경에서만하고 싶은 유혹입니다 (따라서 그렇게하지 마십시오). 그러나 그것은 중요한 유형이 아니며, 당신이 나에게주는 것이 무엇이든 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.