동적 유형 언어가 개발자에게 유형을 지정하지 못하는 이유는 무엇입니까?


14

내가 아는 동적 유형 언어는 개발자가 변수 유형을 지정하지 못하게하거나 최소한 매우 제한적으로 지원합니다.

예를 들어, JavaScript는 편리한 경우 변수 유형을 적용하는 메커니즘을 제공하지 않습니다. PHP는 메소드 인자의 일부 유형을 지정할 수 있지만, 기본 유형 (사용할 수있는 방법이 없습니다 int, string인수 등) 및 인수 이외의 아무것도 유형을 적용 할 수있는 방법은 없습니다.

동시에, 유형 검사를 수동으로 수행하는 대신 동적 유형 언어로 변수 유형을 지정하는 것이 편리한 경우가 있습니다.

왜 그러한 제한이 있습니까? 기술적 / 성능상의 이유 (JavaScript의 경우) 또는 정치적 이유 (PHP의 경우)라고 생각합니까? 내가 익숙하지 않은 다른 동적 유형의 언어의 경우입니까?


편집 : 답변과 의견 다음에 설명을위한 예가 있습니다. 일반 PHP에 다음과 같은 방법이 있다고 가정 해 봅시다.

public function CreateProduct($name, $description, $price, $quantity)
{
    // Check the arguments.
    if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
    if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
    if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
    if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

몇 가지 노력으로 다음과 같이 다시 작성할 수 있습니다 ( PHP 계약에 의한 프로그래밍 참조 ).

public function CreateProduct($name, $description, $price, $quantity)
{
    Component::CheckArguments(__FILE__, __LINE__, array(
        'name' => array('value' => $name, 'type' => VTYPE_STRING),
        'description' => array('value' => $description, 'type' => VTYPE_STRING),
        'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
        'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
    ));

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

그러나 PHP가 선택적으로 인수에 대한 기본 유형을 허용하는 경우 동일한 방법이 다음과 같이 작성됩니다.

public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
    // Check the arguments.
    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

어느 것이 더 짧은가? 어느 것이 더 읽기 쉬운가요?


1
동적으로 형식화 된 일부 언어 (예 : Common Lisp)에서 유형을 선택적으로 지정할 수 있습니다.
SK-logic

동적으로 타이핑 된 몇몇 언어는 캐스트를 사용하여 타입을 강제합니다.
Trezoid

일부는 그렇습니다. 예를 들어, Objective-C는 동적으로 유형이 지정되지만 변수 유형을 선언 할 수 있으며 예상 한 유형을 얻지 못하면 컴파일러에서 경고를 발행합니다.
mipadi

1
Clojure는 일반적으로 동적으로 유형이 지정되는 언어의 예이지만 "유형 힌트"를 통해 변수 유형을 선택적으로 제공 할 수 있습니다 (일반적으로 컴파일 타임 유형 정보의 성능 이점을 얻는 데 필요한 경우에만 수행됨)
mikera

1
Groovy는 형식을 지정할 수있는 동적 형식 언어의 또 다른 예입니다.
Eric Wilson

답변:


17

정적 타이핑의 요점은 프로그램이 유형과 관련하여 정확 하다는 것을 정적으로 증명 하는 능력 입니다 (참고 : 모든 의미에서 완전히 정확하지는 않습니다). 정적 유형 시스템이있는 경우 대부분 유형 오류를 감지 할 수 있습니다.

부분 유형 정보 만있는 경우 유형 정보가 완료된 작은 호출 그래프 조각 만 확인할 수 있습니다. 그러나 불완전한 부품에 대한 유형 정보를 지정하는 데 많은 시간과 노력을 들였으므로 도움이되지 않지만 잘못된 보안 감각을 제공 할 수 있습니다.

유형 정보를 표현하려면 지나치게 단순 할 수없는 언어 부분이 필요합니다. 곧 당신은 같은 정보 int가 충분하지 않다는 것을 알게 될 것입니다 . List<Pair<Int, String>>, 파라 메트릭 유형 등과 같은 것을 원할 것 입니다. 다소 단순한 Java의 경우에도 충분히 혼란 스러울 수 있습니다.

그런 다음 변환 단계 실행 단계 에서이 정보를 처리해야 합니다. 정적 오류 만 확인하는 것은 어리석기 때문입니다. 사용자는 타입 제한이 항상 지정된 경우 항상 유지 될 것으로 기대합니다. 동적 언어는 그다지 빠르지 않으므로 이러한 검사를 수행하면 성능이 훨씬 느려집니다. 정적 언어는 한 번만 수행하기 때문에 유형을 확인하는 데 많은 노력을 기울일 수 있습니다. 역동적 인 언어는 할 수 없습니다.

이제 사람들이 때때로 이러한 기능을 선택적으로 사용하여 유형 오류의 작은 부분 만 감지 하도록이 모든 것을 추가하고 유지한다고 상상해보십시오 . 노력할만한 가치가 없다고 생각합니다.

동적 언어의 요점은 매우 작고 가단성있는 프레임 워크를 사용하는 것입니다. 정적 언어에서 수행 할 때 훨씬 더 관련이있는 작업을 쉽게 수행 할 수 있습니다. 메타 프로그래밍, 조롱 및 매우 역동적 인 스몰 토크와 리스프는 소스에서 빌드하는 대신 환경 이미지를 제공하는 것과 같은 극단적 인 결과를 가져 왔습니다. 그러나 특정 데이터 경로가 형식에 안전한지 확인하려면 어설 션을 추가하고 더 많은 단위 테스트를 작성하십시오.


1
테스트에 따르면 +1이지만 특정 상황에서는 오류가 발생하지 않습니다. (유형) 오류가 불가능하다는 증거를 대체하기에 적합하지 않습니다.
Ingo

1
@ 잉고 : 물론. 그러나 동적 언어는 비교적 간단한 아이디어를 매우 빠르게 표현하는 땜질 및 빠른 프로토 타입 제작에 좋습니다. 방탄 생산 코드를 원하면 안정적인 핵심 구성 요소를 추출한 후 나중에 정적 언어로 전환 할 수 있습니다.
9000

1
@ 9000, 나는 그들이 위대하다는 것을 의심하지 않습니다. 3 또는 4 개의 절름발이 테스트를 작성하는 것이 아니며 유형 안전을 보장 할 수 없음을 지적하고 싶었습니다 .
Ingo

2
@ 9000, True, 그리고 나쁜 소식은 그때조차도 실제로 불가능하다는 것입니다. Haskell 또는 Agda 코드조차도 런타임에 사용되는 라이브러리가 올바른지 등의 가정에 의존합니다. 즉, 약 1000 개의 LOC가 수십 개의 소스 코드 파일에 분산되어있는 프로젝트에서 무언가를 변경할 수있을 때 매우 시원하며 컴파일러가 변경이 영향을 미치는 모든 라인을 가리킬 것임을 알고 있습니다.
Ingo

4
잘못 작성된 테스트는 정적 유형 검사를 대체하지 않습니다. 열등합니다. 잘 작성된 테스트는 정적 유형 검사를 대체하지 않으며 우수합니다.
Rein Henrichs

8

대부분의 동적 언어에서는 최소한 객체 또는 값의 유형을 동적으로 테스트 할 수 있습니다 .

그리고 일부 동적 언어에 대한 정적 형식 유추 자, 검사기 및 / 또는 시행자가 있습니다.

그리고 Perl 6은 정적 타이핑이 있는 옵션 타입 시스템 을 지원합니다 .


그러나 결론은 많은 사람들 이 동적으로 입력 하기 때문에 동적 언어를 사용 한다는 것입니다. 선택적인 정적 입력은 "호허"입니다. 그리고 다른 많은 사람들이 용서하는 자연 역동적 인 타이핑의 결과로, "비 프로그래머가 사용하기 쉬워서"그것들을 사용합니다. 그들에게 선택적인 타이핑은 이해하지 못하거나 사용하기에 방해가되지 않는 것입니다.

냉소적이라면 선택적인 정적 타이핑은 두 세계 중 최악의 상황을 제공한다고 말할 수 있습니다. 정적 유형 zealot에 대해 모든 동적 유형 실패를 막지는 못합니다 . 다이내믹 타입 팬의 경우 스트랩이 꽉 조이지 않아도 여전히 스트레이트 재킷입니다.


2
대부분의 환경에서는 대부분의 커뮤니티에서 유형을 직접 확인하는 것이 어려워집니다. 개체 계층 구조를 다룰 때는 다형성 (특히 "덕 타이핑")을 사용하고 가능한 경우 가능한 유형을 강요하십시오. 유형을 허용하는 것이 타당하지 않은 몇 가지 경우가 남아 있지만 대부분의 언어에서 이러한 경우 대부분 예외가 발생하므로 유형 검사는 거의 유용하지 않습니다.

4
"사람들은 일반적으로 동적으로 입력하기 때문에 동적 언어를 사용합니다" : JavaScript는 대부분의 브라우저에서 지원하는 유일한 언어이기 때문에 사용됩니다. PHP는 인기가 있기 때문에 사용됩니다.
Arseni Mourzenko

2

자바 스크립트는 선택적인 정적 타이핑을 포함 할 계획이었고, 많은 성숙한 동적 언어가 그런 식으로 가고있는 것처럼 보입니다.

그 이유는 처음 코딩 할 때 빠르고 동적으로 입력하기를 원하기 때문입니다. 코드가 확실하고 작동하며 많은 용도가 있으면 디자인을 잠그고 오류를 줄이려고합니다. (이것은 사용자와 개발자 모두에게 유리합니다. 전자는 자신의 호출에서 오류 확인을 받고 후자는 실수로 문제를 해결하지 않기 때문입니다.

나는 일반적으로 프로젝트 시작시 너무 많은 유형 검사가 있고, 사용하는 언어에 관계없이 수명이 끝날 때 너무 적다는 것을 알기 때문에 나에게 의미가 있습니다.


JavaScript에 선택적 정적 입력을 포함하려는 계획에 대해 모르겠습니다. 그러나 그들이 ActiveScript에서 그렇게 끔찍하지 않았기를 바랍니다. JavaScript와 Java 모두 최악입니다.
Javier

JS 4 (또는 ECMAscript 4) 용으로 계획되었지만 논쟁으로 인해 해당 버전이 삭제되었습니다. 나는 앞으로 어떤 언어로 비슷한 것이 나타날 것이라고 확신합니다. (Python에서는 데코레이터를 사용하여 정렬 할 수 있습니다.)
Macke

1
데코레이터 는 일종의 어설 션 인 동적 유형 검사를 추가 합니다. 파이썬에서는 포괄적 인 정적 유형 검사를 할 수 없지만 언어의 역 동성으로 인해 시도하기가 어렵습니다.
9000

@ 9000 : 맞습니다. 그러나 동적 유형 검사가 나쁘지는 않다고 생각합니다 (그러나 JS4와 비교하여 덕 유형 비교를 선호합니다). 특히 단위 테스트와 결합하면 데코레이터를 형식화하는 것이 IDE / 린트 검사기를 더 유용하게 지원할 수 있습니다 표준화.
Macke

물론 나쁘지 않습니다! 이것은 도덕의 문제가 아닙니다. 어떤 시점에서 유형은 어떤 방식 으로든 "확인"되어야합니다. C에 * ((double *) 0x98765E)를 쓰면 CPU가 CPU를 수행하여 0x98765E가 실제로 double에 대한 포인터인지 확인합니다.
Ingo

2

파이썬 객체는 유형을 가지고있다.

객체를 만들 때 유형을 지정합니다.

동시에, 유형 검사를 수동으로 수행하는 대신 동적 유형 언어로 변수 유형을 지정하는 것이 편리한 경우가 있습니다.

실제로 파이썬에서 수동 유형 검사는 거의 항상 시간과 코드를 낭비합니다.

파이썬으로 타입 검사 코드를 작성하는 것은 단순히 나쁜 습관입니다.

일부 악의적 인 소시 오 패스가 부적절한 유형을 사용한 경우, 파이썬의 일반적인 메소드는 유형이 적절하지 않을 때 일반적인 예외를 발생시킵니다.

코드를 작성하지 않아도 프로그램이 여전히 실패합니다 TypeError.

런타임에 유형을 결정해야하는 경우는 매우 드 cases니다.

왜 그러한 제한이 있습니까?

"제한"이 아니기 때문에 질문은 실제 질문이 아닙니다.


2
"Python 객체에는 유형이 있습니다." -아 진짜? 펄 객체, PHP 객체 및 세계의 다른 모든 데이터 항목과 마찬가지로. 정적 형식과 동적 형식의 차이점은 형식을 확인할 때, 즉 형식 오류가 나타날 때만 발생합니다. 컴파일러 오류로 표시되면 정적 입력이고 런타임 오류로 표시되면 동적입니다.
Ingo

@ 잉고 : 설명을 주셔서 감사합니다. 문제는 C ++ 및 Java 객체를 한 유형에서 다른 유형으로 캐스트하여 객체 유형을 다소 어둡게 만들 수 있으므로 해당 컴파일러에서 "유형 검사"도 약간 어둡습니다. 파이썬 유형 검사는 런타임에도 불구하고 훨씬 덜 어둡습니다. 또한 질문은 동적으로 유형이 지정된 언어에 유형이 없다고 말하는 것과 비슷합니다. 좋은 소식은 그것이 일반적인 실수를하지 않는다는 것입니다.
S.Lott

1
당신은 맞습니다. 타입 변환 (타입 변환과 달리 ((double) 42))은 정적 타입을 파괴합니다. 타입 시스템이 충분히 강력하지 않을 때 필요합니다. Java 5 이전에는 Java에 매개 변수화 된 유형이 없었기 때문에 유형 캐스트가 없으면 살 수 없었습니다. 오늘날에는 훨씬 나아지지만 유형 시스템에는 여전히 높은 등급의 유형이 없으며 등급이 높은 다형성에 대해서는 말할 것도 없습니다. 나는 동적으로 타이핑 된 언어가 너무 좁은 타입의 시스템에서 해방되기 때문에 많은 추종자를 정확하게 즐길 수 있다고 생각합니다.
Ingo

2

대부분의 경우 최소한 제안하는 세부 사항 수준이 아니어도됩니다. PHP에서 사용하는 연산자는 인수가 무엇을 기대하는지 완벽하게 명확하게합니다. 문자열을 기대하는 연산에 배열을 전달할 때에도 PHP는 가능한 한 값을 캐스팅하지만, 캐스트가 항상 의미있는 것은 아니기 때문에 때로는 이상한 결과를 얻을 수 있지만 약간의 디자인 감독입니다. 그리고 이것은 정확하게 유형 검사 유용한 곳입니다). 당신이 정수를 추가하는 경우보다 다른, 그것은 중요하지 않습니다 15또는 문자열 "1""5"- 당신은을 사용하고 있다는 단순한 사실을+연산자는 인수를 숫자로 취급하고 싶다고 PHP에 신호하며, PHP가 준수합니다. 흥미로운 상황은 MySQL에서 쿼리 결과를 수신하는 경우입니다. 많은 숫자 값이 단순히 문자열로 반환되지만 PHP는 숫자로 취급 할 때마다 사용자를 위해이를 캐스팅하므로 알 수 없습니다.

파이썬은 타입에 대해 좀 더 엄격하지만, PHP와는 달리, 파이썬은 처음부터 예외를 가지고 일관되게 사용합니다. "권한보다 용서를 구하는 것이 더 쉽다"는 패러다임은 형식 검사없이 작업을 수행하고 형식이 적절하지 않은 경우 예외가 발생하는 것을 제안합니다. 내가 생각할 수있는 유일한 단점은 때로는 유형이 예상 한 것과 일치하지 않는 곳이 있지만 이유를 찾는 것이 지루할 수 있다는 것입니다.

동적 언어가되지 않는 : 그리고 고려해야 할 또 다른 이유가 있다 컴파일 단계. 유형 제약 조건이 있더라도 컴파일 시간이 없기 때문에 런타임에만 실행할 수 있습니다 . 어쨌든 검사로 런타임 오류가 발생하면 그에 따라 모델링하는 것이 훨씬 쉽습니다. 예를 들어 명시 적 검사 (예 : is_XXX()PHP 또는 typeof자바 스크립트) 또는 예외 (예 : Python)와 같은 예외가 발생합니다. 기능적으로 동일한 효과 (유형 검사에 실패하면 런타임에 오류가 표시됨)가 있지만 나머지 언어 의미와 더 잘 통합됩니다. 동적 언어에서 유형 오류를 다른 런타임 오류와 근본적으로 다르게 처리하는 것은 의미가 없습니다.


0

Haskell에 관심이있을 수 있습니다. 유형 시스템은 코드에서 유형을 유추하므로 유형을 지정할 수도 있습니다.


5
하스켈은 훌륭한 언어입니다. 동적 언어와는 정반대입니다. 유형을 설명하는 데 많은 시간을 소비하며 일반적으로 유형을 파악한 후에는 프로그램이 작동합니다. :
9000

@ 9000 : 그렇습니다. 컴파일되면 일반적으로 작동합니다. :)
Macke

@Macke - 서로 다른 값에 대한 보통 물론,. :-) 나에게 타입 시스템과 기능 패러다임의 가장 큰 장점은 다른 곳에서 지적했듯이 변경이 다른 곳의 코드에 자동으로 영향을 미치는지 신경 쓰지 않아도된다는 것입니다. 컴파일러는 유형 오류를 지적합니다 변경 가능한 상태는 존재하지 않습니다.
Ingo

0

다른 답변에서 언급했듯이 프로그래밍 언어를 구현할 때 타이핑하는 두 가지 방법이 있습니다.

  1. 프로그래머에게 모든 변수와 함수가 유형에 사용하는 것을 알려주십시오. 이상적으로는 유형 사양이 정확한지 확인하십시오. 그런 다음 각 위치에 어떤 유형의 항목이 있는지 알기 때문에 적절한 항목이 있다고 가정하고 해당 유형을 직접 구현하는 데 사용하는 모든 데이터 구조를 사용하는 코드를 작성할 수 있습니다.
  2. 변수에 저장되어 함수로 전달되고 함수에서 리턴 될 값에 유형 표시기를 첨부하십시오. 즉, 변수와 함수가 참조하는 객체에 유형이 실제로 속하기 때문에 프로그래머가 변수 나 함수에 대한 유형을 지정할 필요가 없습니다.

두 가지 접근 방식 모두 유효하며 사용할 기능은 부분적으로 성능과 같은 기술적 고려 사항, 부분적으로는 언어의 목표 시장과 같은 정치적 이유에 달려 있습니다.


0

우선 모든 동적 언어는 주로 사용하기 쉽도록 만들어졌습니다. 언급했듯이 유형 변환을 자동으로 수행하고 오버 헤드를 줄이는 것이 좋습니다. 그러나 동시에 성능 문제가 부족합니다.

성능에 대해 걱정하지 않으면 동적 언어를 사용할 수 있습니다. 예를 들어 JavaScript가 프로그램에서 많은 유형 변환을 수행해야 할 때 느리게 실행되지만 코드의 줄 수를 줄이는 데 도움이됩니다.

그리고 프로그래머가 유형을 지정할 수있는 다른 동적 언어도 있습니다. 예를 들어 Groovy 는 JVM에서 실행되는 유명한 동적 언어 중 하나입니다. 그리고 최근에도 매우 유명했습니다. Groovy의 성능은 Java와 동일합니다.

그것이 당신을 돕기를 바랍니다.


-1

그렇게하는 것은 말이되지 않습니다.

왜?

DTL의 타입 시스템은 정확하게 컴파일 타임에 타입을 결정할 수없는 정도이기 때문입니다. 따라서 컴파일러는 지정된 유형이 의미가 있는지 확인할 수 없었습니다.


1
왜? 컴파일러가 기대하는 유형에 대해 힌트를주는 것이 좋습니다. 형식 시스템 제약 조건과 모순되지 않습니다.
SK-logic

1
SK-logic : 동적 유형이 모든 기능 / 방법 / 작업이 "동적", "임의"또는 다른 유형의 객체를 취하고 "동적", "임의"를 반환하는 경우 일반적으로 특정 값을 알 수있는 방법은 없습니다 예를 들어 항상 정수입니다. 따라서 런타임 코드는 어쨌든 유형이 "동적"인 것처럼 정수가 아닌 것을 확인해야합니다. 이것은 정적 유형 시스템이하는 일입니다. 특정 변수, 필드 또는 메소드 리턴이 항상 특정 유형 임을 증명할 수 있습니다.
Ingo

@ Ingo, 아니요, 방법이 있습니다. 예를 들어 Common Lisp에서 어떻게 구현되는지 확인하십시오. 지역 변수에 특히 유용합니다. 모든 타이핑 힌트를 도입하여 성능을 크게 향상시킬 수 있습니다.
SK-logic

@ SK-logic : CL에서 유형 오류가 언제 어떻게 감지되는지 알 수 있습니까? 어쨌든 @MainMa는 자신의 질문에 현 상태를 아주 잘 요약했습니다. "순수하게"동적 인 언어에서 기대할 수있는 것입니다.
Ingo

@ Ingo, 유형이 정적으로 정확성을 입증하는 데 유용하다고 생각하는 이유는 무엇입니까? 검사되지 않은 유형 캐스팅이있는 C와 같은 언어조차도 사실이 아닙니다. 동적 언어의 유형 주석은 성능을 향상 시키거나 구체적인 숫자 표현을 지정하는 컴파일러 힌트로 주로 유용합니다. 대부분의 경우 주석이 코드의 의미를 변경해서는 안된다는 데 동의합니다.
SK-logic

-1

정적으로 유형이 지정된 표면에서 Go를 살펴보십시오. 그러나 이러한 유형은 본질적으로 동적 인 인터페이스 일 수 있습니다.

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