약한 유형의 언어와 관련하여 명백한 모순에 대해 설명하기


178

필자는 강력한 타이핑을 이해한다고 생각 하지만 약한 타이핑에 대한 예제를 찾을 때마다 유형을 자동으로 강제 변환 / 변환하는 프로그래밍 언어의 예제를 찾습니다.

예를 들어, Typing : Strong vs. Weak 라는 기사 에서 Static vs. Dynamic 은 다음 과 같은 경우 예외가 발생하므로 Python이 강력하게 입력된다고 말합니다.

파이썬

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

그러나 Java와 C #에서는 그러한 일이 가능하며 그 유형에 대해서만 약한 유형으로 간주하지는 않습니다.

자바

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

씨#

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

Weakly Type Languages 라는 다른 기사 에서 저자는 Perl이 명시 적으로 변환되지 않고 문자열을 숫자로 또는 그 반대로 연결할 수 있기 때문에 약하게 유형이 지정되었다고 말합니다.

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

따라서 동일한 예제는 Perl을 약하게 입력했지만 Java 및 C #은 아닙니다.

이봐, 혼란스러워 여기에 이미지 설명을 입력하십시오

저자는 다른 유형의 값에 대한 특정 작업의 적용을 방해하는 언어가 강력하게 입력되고 반대로 의미가 약한 유형임을 암시하는 것으로 보입니다.

따라서 언젠가는 언어가 많은 자동 변환을 제공하거나 유형 사이의 강제 변환이 (약식으로) 약한 유형으로 간주 될 수 있지만, 약간의 변환 만 제공하는 다른 언어는 결국에는 강력하게 입력 된 것으로 간주됩니다.

그러나 나는이 해석에있어서 틀렸다는 것을 믿기를 원한다. 나는 왜 그것을 어떻게 설명해야하는지 모른다.

그래서 내 질문은 :

  • 언어가 실제로 약하게 입력되었다는 것은 실제로 무엇을 의미합니까?
  • 언어에 의한 자동 변환 / 자동 강제와 관련이없는 약한 타이핑의 좋은 예를 언급 할 수 있습니까?
  • 언어를 약하고 타이핑 할 수 있습니까?

8
: 약한 입력 대 강한 당신이 "매우"약한 언어의 예를 원하는 경우,이 시계 (? 다른 무엇에 대해 할 수있는) 모든 유형의 변환에 관한 destroyallsoftware.com/talks/wat을 .
Wilduck

2
@Wildduck 모든 언어는 형식 변환을 제공하지만 모두 약한 형식으로 간주되는 것은 아닙니다. 아래에 나와있는 예제는 프로그래머가 강력하게 입력 된 다른 언어에서 가능한 것과 동일한 예제를 기반으로 약한 유형의 언어를 어떻게 고려하는지 보여줍니다. 따라서 내 질문은 여전히 ​​우세합니다. 차이점은 무엇입니까?
Edwin Dalorzo

1
짧은 대답은 "Typedness"가 이진 상태가 아니라는 것입니다. Java와 C #은 더 강력하게 입력되지만 절대적으로는 아닙니다.
Jodrell

3
이것이 소프트웨어 공학에 더 적합하다고 생각합니다 .
zzzzBov 2016 년

4
@Brendan 부동 소수점과 정수를 합산하는 것은 어떻습니까? 파이썬에서 정수가 float로 강제 변환되지 않습니까? 파이썬이 절대적으로 강력하게 타이핑되지 않았다고 말할 수 있습니까?
Edwin Dalorzo

답변:


210

업데이트 : 이 질문은 2012 년 10 월 15 일에 제 블로그의 주제였습니다. 훌륭한 질문에 감사드립니다!


언어가 "약하게 입력 된"다는 것은 무엇을 의미합니까?

"이 언어는 내가 싫어하는 타입 시스템을 사용합니다"라는 의미입니다. 대조적으로 "강력한 유형의"언어는 유쾌한 유형 시스템을 갖춘 언어입니다.

용어는 본질적으로 의미가 없으므로 피해야합니다. Wikipedia 에는 "강력한 유형"에 대한 11 가지 다른 의미가 나열되어 있으며 그 중 일부는 모순됩니다. 이는 "강력한 유형"또는 "약한 유형"이라는 용어가 포함 된 대화에서 혼동이 발생할 가능성이 높다는 것을 나타냅니다.

실제로 확실하게 말할 수있는 것은 논의중인 "강력한 유형의"언어가 런타임 또는 컴파일 타임에 유형 시스템에 추가 제한이 있다는 점입니다. 추가 제한 없이는 그러한 제한을 결정할 수 없습니다.

"강력한 유형"및 "약한 유형"을 사용하는 대신 어떤 종류의 유형 안전을 의미하는지 자세히 설명해야합니다. 예를 들어 C #은 대부분 정적으로 형식이 지정된 언어이며 형식이 안전한 언어이며 메모리가 안전한 언어 입니다.. C #을 사용하면 이러한 세 가지 "강력한"타이핑 형식을 모두 위반할 수 있습니다. 캐스트 연산자는 정적 입력을 위반합니다. 컴파일러에게 "이 표현식의 런타임 유형에 대해 더 많이 알고 있습니다"라고 말합니다. 개발자가 잘못된 경우 형식 안전성을 보호하기 위해 런타임에서 예외가 발생합니다. 개발자가 유형 안전 또는 메모리 안전을 중단하려면 "안전하지 않은"블록을 만들어 유형 안전 시스템을 끄면됩니다. 안전하지 않은 블록에서는 포인터 매직을 사용하여 int를 float (유형 안전 위반)로 취급하거나 소유하지 않은 메모리에 쓸 수 있습니다. (메모리 안전 위반)

C #에서는 컴파일 타임과 런타임에 모두 확인되는 형식 제한을 적용하여 컴파일 타임 확인이 적거나 런타임 확인이 적은 언어와 비교하여 "강력한 형식의"언어로 만듭니다. 또한 C #을 사용하면 특수한 상황에서 이러한 제한 사항에 대한 최종 실행을 수행 할 수 있으므로 이러한 최종 실행을 수행 할 수없는 언어와 비교하여 "약한 형식의"언어가됩니다.

어느 것이 진짜입니까? 말하는 것은 불가능합니다. 그것은 화자의 관점과 다양한 언어 기능에 대한 그들의 태도에 달려 있습니다.


14
@edalorzo : (1) 유형 이론의 어떤 측면이 관련이 있고 관련이 없는지, (2) 언어가 유형 제한 을 시행 해야하는지 또는 단순히 조장 해야하는지에 대한 취향과 개인적 의견에 근거합니다 . 내가 지적했듯이 C #은 정적 입력을 허용하고 장려 하기 때문에 C #이 강력하게 입력 되었다고 합리적으로 말할 수 있으며 유형 안전을 위반 할 있기 때문에 약하게 입력되었다고 합리적으로 말할 수 있습니다 .
Eric Lippert

4
@edalorzo : 조립은 다시 한 번 의견의 문제입니다. 어셈블리 언어 컴파일러를 사용하면 스택에서 32 비트 레지스터로 64 비트 이중을 이동할 수 없습니다. 스택에서 32 비트 레지스터로 32 비트 포인터를 64 비트 이중으로 이동할 수 있습니다. 그런 의미에서 언어는 "유형 안전"입니다. 데이터의 유형 분류를 기반으로 프로그램의 적법성을 제한합니다. 이러한 제한이 "강한"또는 "약한"인지 여부는 의견의 문제이지만 분명히 제한입니다.
Eric Lippert

2
나는 당신의 요점을 지금 본다고 생각합니다. 진정으로 약한 유형의 언어는 완전히 유형화되지 않았거나 단일 유형이어야합니다. 실제로는 불가능합니다. 따라서 모든 언어에는 안전한 유형에 대한 특정 정의가 있으며, 언어가 제공하는 데이터 또는 데이터 유형을 위반하거나 조작하기 위해 제공하는 구멍 수에 따라 다소 약한 유형으로 간주 될 수 있습니다. 특정 상황에서만.
Edwin Dalorzo

7
@edalorzo : 맞습니다. 예를 들어, 형식화되지 않은 람다 미적분은 얻을 수있는만큼 약한 형식입니다. 모든 함수는 함수에서 함수까지의 함수입니다. 모든 것이 "동일한 유형"이므로 모든 데이터를 제한없이 모든 함수에 전달할 수 있습니다. 유형이 지정되지 않은 람다 미적분학에서 표현의 유효성은 특정 표현을 특정 유형으로 분류하는 의미 론적 분석이 아니라 구문 형태에만 의존합니다.
Eric Lippert

3
@ Mark 나는 그에게 모든 사람이 주제에 대해 다른 해석을 제공 할 것이라고 예측하여 +1을 줄 것입니다. 이 "약한 타이핑"은 "신화적인 개념"또는 "도시의 전설"인 것 같습니다. 모두가 그것을 보았지만 아무도 그것이 존재한다는 것을 증명할 수는 없습니다 :-)
Edwin Dalorzo

64

다른 사람들이 지적했듯이, "강력한 유형"과 "약한 유형"이라는 용어는 매우 다양한 의미를 지니므로 귀하의 질문에 대한 단일 답변이 없습니다. 그러나 질문에 Perl을 구체적으로 언급했기 때문에 Perl이 약하게 입력 된 의미를 설명하려고합니다.

요점은 Perl에는 "정수 변수", "부동 변수", "문자열 변수"또는 "부울 변수"와 같은 것이 없다는 것입니다. 사실, 사용자가 (보통) 말할 수있는 한, 정수, 부동 소수점, 문자열 또는 부울 값도 없습니다 . "스칼라"만 있으면됩니다. 예를 들어 다음과 같이 쓸 수 있습니다.

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

물론, 당신이 올바르게 지적했듯이,이 모든 것은 단지 유형 강제라고 볼 수 있습니다. 그러나 요점은 Perl에서 유형은 항상 강제 된다는 것 입니다. 사실, 사용자는 변수의 내부 "유형"이 무엇인지 말하기가 매우 어렵습니다. 위의 예제에서 2 행에서 값이 $bar문자열 "9"인지 또는 숫자 9인지는 거의 의미가 없습니다. Perl에 관한 한, 그것들은 같습니다 . 실제로, 내부적으로이에 펄 스칼라에 대해서도 가능 모두 로의 경우를 예입니다, 문자열과 같은 시간에 숫자 값을 $foo줄이 후 위.

이것의 단점은 Perl 변수가 형식화되지 않았기 때문에 (또는 내부 유형을 사용자에게 노출시키지 않기 때문에) 연산자가 다른 유형의 인수에 대해 다른 작업을 수행하도록 오버로드 될 수 없다는 것입니다. "이 연산자는 숫자에 대해 X를, 문자열에 대해 Y를 수행 할 것"이라고 말할 수는 없습니다. 연산자는 인수가 어떤 종류의 값인지 알 수 없기 때문입니다.

예를 들어, Perl에는 숫자 덧셈 연산자 ( +)와 문자열 연결 연산자 ( .) 가 모두 필요합니다. 위에서 보았 듯이 문자열 ( "1" + "2" == "3") 을 추가 하거나 숫자 ( 1 . 2 == 12) 를 연결하는 것이 좋습니다. 마찬가지로, 수치 비교 연산자 ==, !=, <, >, <=, >=그리고 <=>그들의 인수의 숫자 값을 비교, 문자열 비교 연산자는 동안 eq, ne, lt, gt, le, gecmp문자열로 사전 식을 비교합니다. 그래서 2 < 10, 그러나 2 gt 10(그러나 "02" lt 10, "02" == 2). ( 자바 스크립트와 같은 다른 언어는 Perl과 같은 약한 입력을 수용하려고합니다.또한 연산자 오버로드를 수행합니다. 이것은 종종 연관성을 잃는 것과 같이 추함을 초래합니다 +.)

(여기서 연고의 비행은 역사적 이유로 Perl 5에는 비트 논리 연산자와 같이 몇 가지 모퉁이가 있으며, 그 논리적 인 동작은 인수의 내부 표현에 따라 달라집니다. 내부 표현은 놀라운 이유로 변경 될 수 있으므로 주어진 상황에서 해당 운영자가 수행하는 작업을 예측하는 것은 까다로울 수 있습니다.)

모든 사람이 펄이 주장 할 수, 말했다 않는 강한 유형이있다; 그들은 당신이 기대할 수있는 종류의 유형이 아닙니다. 특히, 위에서 설명한 "scalar"유형 외에도 Perl에는 "array"및 "hash"라는 두 가지 구조화 된 유형이 있습니다. 스칼라와 는 매우 다르며, Perl 변수 의 유형 ( 스칼라, 배열, 해시) 1을 나타내는 서로 다른 시길이 있습니다. 이 있습니다 당신은 그래서 이러한 유형의 사이에 강제 변환 규칙은 할 수 예를 들어, 쓰기 ,하지만 그들 중 많은 사람들이 매우 손실이 있습니다 : 예를 들어, 할당 길이 배열 로를$@%%foo = @bar$foo = @bar@bar$foo내용이 아닙니다. (또한 typeglobs 및 I / O 핸들과 같이 자주 노출되지 않는 몇 가지 다른 이상한 유형이 있습니다.)

또한이 멋진 디자인의 약간의 단점은 특수 유형의 스칼라 (및 연산자를 사용하여 일반 스칼라와 구별 할 수 있는) 참조 유형의 존재입니다 ref. 참조를 일반 스칼라로 사용할 수 있지만 문자열 / 숫자 값은 특히 유용하지 않으며 일반 스칼라 연산을 사용하여 수정하면 특수 참조가 손실되는 경향이 있습니다. 또한 모든 Perl 변수 2bless클래스에 연결되어 해당 클래스의 객체로 바뀔 수 있습니다 . Perl의 OO 클래스 시스템은 위에서 설명한 기본 유형 (또는 유형이없는) 시스템과 다소 직교하지만 오리 입력 을 따르는 의미에서 "약한"어형 변화표. 일반적인 의견은 Perl에서 객체의 클래스를 확인하면 무언가 잘못하고 있다는 것입니다.


1 실제로, sigil은 액세스되는 값의 유형을 @foo나타내 므로 배열의 첫 번째 스칼라 가 표시 $foo[0]됩니다. 자세한 내용은 perlfaq4 를 참조하십시오.

2 Perl의 객체는 일반적으로 객체에 대한 참조를 통해 액세스되지만 실제로 얻는 bless것은 참조가 가리키는 (익명) 변수입니다. 그러나 축복은 실제로 그 가치가 아니라 변수의 속성입니다. 예를 들어, 실제 축복 변수를 다른 변수에 할당하면 변수의 얕고 축복 되지 않은 사본 만 얻게됩니다. 자세한 내용은 perlobj 를 참조하십시오.


19

Eric이 말한 것 외에도 다음 C 코드를 고려하십시오.

void f(void* x);

f(42);
f("hello");

Python, C #, Java 등과 같은 언어와 달리 위의 내용 유형 정보 가 손실 되기 때문에 약하게 입력 됩니다 . Eric은 C #에서“캐스팅을 통해 컴파일러를 우회하여“이 변수의 유형에 대해 더 많이 알고 있습니다”라고 효과적으로 지적했습니다.

그러나 그럼에도 불구하고 런타임은 여전히 ​​유형을 검사합니다! 캐스트가 유효하지 않으면 런타임 시스템이 캐스트를 포착하여 예외를 처리합니다.

유형 삭제를 사용하면 이런 일이 발생하지 않습니다. 유형 정보가 삭제됩니다. void*C 로의 캐스트 는 정확히 그렇게합니다. 이와 관련하여 위의 내용은와 같은 C # 메서드 선언과 근본적으로 다릅니다 void f(Object x).

기술적으로 C #에서는 안전하지 않은 코드 나 마샬링을 통해 형식을 지울 수도 있습니다.

이것은 약한 유형입니다. 다른 모든 정적 대의 동적 유형 검사, 즉 시간의 문제이다 타입이 선택된다.


1
+1 좋은 지적, 이제 유형 소거를 "약한 유형"을 암시 할 수있는 기능으로 생각하게 만들었습니다. Java에서도 유형 삭제가 있으며 런타임시 유형 시스템을 사용하면 컴파일러가 승인하지 않는 제약 조건을 위반할 수 있습니다. C 예제는 요점을 잘 보여줍니다.
Edwin Dalorzo

1
동의, 양파 또는 지옥에 층이 있습니다. 이것들은 유형 약점에 대한 더 중요한 정의로 보입니다.
Jodrell

1
@edalorzo 나는이 생각하지 않습니다 매우 자바 컴파일러를 회피 할 수에도 불구하고, 실행시의 형태의 시스템이 여전히 위반을 잡을 것 때문에 같은. 따라서 Java 런타임 유형 시스템은 이와 관련하여 강력하게 유형이 지정됩니다 (예 : 액세스 제어를 피하기 위해 리플렉션을 사용할 수있는 예외).
Konrad Rudolph

1
@edalorzo 런타임 시스템이 아닌 컴파일러를 이런 식으로 만 피할 수 있습니다. Java 및 C # (및 어느 정도 C ++)과 같은 언어에는 컴파일시 한 번과 런타임에서 한 번, 두 번 보장되는 유형 시스템이 있다는 것을 인식하는 것이 중요합니다. void*두 가지 유형 검사를 모두 수행합니다. 제네릭 형식 지우기는 컴파일 타임 검사를 우회하지 않습니다. 이와 관련하여 명시 적 캐스트 (에릭이 언급 한 것)와 정확히 같습니다.
Konrad Rudolph

1
@edalorzo 당신의 혼란을 다시 : 우리는해서는 안됩니다. 구별이 유창합니다. 그리고 네, 타입 삭제는 이와 관련하여 Java를 약하게 타이핑합니다. 내 요점은 심지어 제네릭 형식의 삭제와 함께 당신이이었다 여전히 실행시의 형태 검사를 회피 할 수없는 당신은 또한 반사를 사용하지 않는 .
Konrad Rudolph

14

강력한 타이핑 위키피디아 기사 에서 완벽한 예를 들어 보자 .

일반적으로 강력한 타이핑은 프로그래밍 언어가 허용되는 혼합에 심각한 제한을가한다는 것을 의미합니다.

약한 타이핑

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

강력한 타이핑

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

타이핑 언어가 약하면 오류없이 여러 유형을 혼합 할 수 있습니다. 강력한 형식 언어를 사용하려면 입력 형식이 예상 형식이어야합니다. 강력한 유형의 언어에서 유형을 변환 ( str(a)정수를 문자열로 변환)하거나 캐스트 ( int(b)) 할 수 있습니다.

이것은 모두 타이핑 해석에 달려 있습니다.


3
그러나 이것은 질문에 제공된 모순적인 예들로 이어집니다. Strongly Typed 언어에는 두 가지 "Type Error"예제 중 하나 (또는 ​​둘 다)가 두 번째 두 예제의 관련 항목으로 자동 변환되지만 일반적으로 해당 언어는 여전히 Strongly Typed라는 암시 적 강제가 포함될 수 있습니다.
Mark Hurd

3
진실. 강력한 타이핑과 약한 타이핑의 정도가 다양하다고 말할 수 있습니다. 암시 적 변환은 암시 적 변환을 수행하지 않는 언어보다 언어가 덜 강력하게 입력되었음을 의미 할 수 있습니다.
SaulBack

4

다른 사람들이 의견을 밝히고 의견을 밝히면서 주제에 대한 저 자신의 연구와의 토론에 기여하고 싶습니다. 나는 그들의 답변을 읽고 그들의 참조를 따르고 흥미로운 정보를 찾았습니다. 제안 된 바와 같이,이 중 대부분은 실제적인 것보다 이론적 인 것으로 보이므로 프로그래머 포럼에서 더 잘 논의 될 가능성이 높습니다.

이론적 인 관점에서 Luca Cardelli와 Peter Wegner의 기사에서 유형 이해, 데이터 추상화 및 다형성에 관한 기사 는 내가 읽은 최고의 주장 중 하나라고 생각합니다.

유형은 기본 유형화되지 않은 표현을 임의적이거나 의도하지 않은 사용으로부터 보호하는 옷 세트 (또는 갑옷)로 볼 수 있습니다 . 기본 표현을 숨기고 객체가 다른 객체와 상호 작용하는 방식을 제한하는 보호 덮개를 제공합니다. 형식화되지 않은 시스템에서 지정되지 않은 객체는 알몸 모두가 볼 수 있도록 기본 표현이 노출되도록한다. 유형 시스템을 위반하는 것은 보호 복 세트를 제거하고 알몸으로 직접 작업하는 것을 포함합니다.

이 문장은 약한 타이핑으로 유형의 내부 구조에 액세스하여 다른 유형 (다른 유형) 인 것처럼 조작 할 수 있다고 제안합니다. 안전하지 않은 코드 (Eric에서 언급 한) 또는 Konrad에서 언급 한 c 유형의 지워진 포인터로 수행 할 수있는 작업 일 수 있습니다.

기사는 계속됩니다 ...

모든식이 형식이 일치 하는 언어를 강력한 형식의 언어라고합니다. 언어가 강력하게 형식화 된 경우 컴파일러는 허용되는 프로그램이 형식 오류없이 실행되도록 보장 할 수 있습니다. 일반적으로 강력한 타이핑을 위해 노력하고 가능할 때마다 정적 타이핑을 채택해야합니다. 정적으로 유형이 지정된 모든 언어는 강력하게 유형이 지정되지만 그 반대의 경우는 아닙니다.

따라서 강력한 타이핑은 유형 오류가 없음을 의미하며, 약한 타이핑은 반대로 유형 오류가 있음을 의미한다고 가정 할 수 있습니다. 런타임 또는 컴파일 타임? 여기에 관련이없는 것 같습니다.

이 정의에 따르면 Perl과 같은 강력한 유형 강제 변환을 사용하는 언어는 시스템이 실패하지 않기 때문에 강력하게 유형화 된 것으로 간주되지만 유형을 적절하고 잘 정의 된 동등성으로 강제 처리하여 유형을 처리합니다.

반면에, 나는의 수당보다 말할 수 ClassCastExceptionArrayStoreException와 (자바) InvalidCastException,ArrayTypeMismatchException 컴파일시에 적어도 약하게 입력의 수준을 나타냅니다 (C #에서)? 에릭의 대답은 이것에 동의하는 것 같습니다.

Luca Cardelli는이 질문에 대한 답변 중 하나에 제공된 참고 문헌 중 하나에서 제공되는 Typeful Programming 이라는 두 번째 기사 에서 유형 위반의 개념을 탐구합니다.

대부분의 시스템 프로그래밍 언어는 임의의 유형 위반을 허용하며, 일부는 무차별 적으로, 일부는 프로그램의 제한된 부분에서만 허용됩니다. 형식 위반과 관련된 작업을 소리가 나지 않습니다. 유형 위반은 몇 가지 클래스로 나뉩니다.

기본 값 강제 : 여기에는 정수, 부울, 문자, 집합 등의 변환이 포함됩니다. 여기에서는 유형 사운드 방식으로 강제를 수행하기 위해 내장 인터페이스를 제공 할 수 있기 때문에 유형 위반이 필요하지 않습니다.

따라서 운영자가 제공하는 것과 같은 유형 강제는 유형 위반으로 간주 될 수 있지만 유형 시스템의 일관성을 위반하지 않으면 유형이 약한 시스템으로 이어지지 않는다고 말할 수 있습니다.

이를 기반으로 Python, Perl, Java 또는 C #은 약하게 입력되지 않습니다.

Cardelli는 실제로 타이핑이 약한 두 가지 유형의 위반을 언급합니다.

주소 산술. 필요한 경우, 내장 된 (소리가 들리지 않는) 인터페이스가 있어야 주소 및 유형 변환에 대한 적절한 작업을 제공 할 수 있습니다. 다양한 상황에는 힙에 대한 포인터 (콜렉터 재배치에 매우 위험), 스택에 대한 포인터, 정적 영역에 대한 포인터 및 다른 주소 공간에 대한 포인터가 포함됩니다. 때때로 배열 인덱싱이 주소 산술을 대체 할 수 있습니다. 메모리 매핑. 여기에는 구조화 된 데이터가 포함되어 있지만 메모리 영역을 구조화되지 않은 배열로 보는 것이 포함됩니다. 이것은 일반적인 메모리 할당 자 및 수집기입니다.

C (Konrad에 의해 언급 된)와 같은 언어 나 .Net (에릭에 의해 언급 된)의 안전하지 않은 코드를 통해 가능한 이런 종류의 것들은 실제로 타이핑이 약하다는 것을 의미합니다.

나는이 개념의 정의가 매우 이론적이며 특정 언어에 관해서는 이러한 모든 개념의 해석이 다른 논쟁의 여지가있는 결론으로 ​​이어질 수 있기 때문에 지금까지 가장 좋은 대답은 Eric의 것이라고 믿는다.


4

타이핑이 약하다는 것은 실제로 높은 비율의 유형이 암묵적으로 강제되어 코더의 의도를 추측하려고 시도한다는 것을 의미합니다.

강력한 타이핑은 유형이 강요되지 않거나 최소한 강요되지 않음을 의미합니다.

정적 타이핑은 컴파일시 변수 유형이 결정됨을 의미합니다.

많은 사람들이 최근에 "매니 컬 타이핑"과 "강력 타이핑"을 혼동하고 있습니다. "매니페스트 유형"은 변수 유형을 명시 적으로 선언 함을 의미합니다.

부울 컨텍스트에서 거의 모든 것을 사용할 수 있지만 부울은 정수 컨텍스트에서 사용할 수 있으며 부동 컨텍스트에서 정수를 사용할 수 있지만 파이썬은 대부분 강력하게 유형이 지정됩니다. 타입을 선언 할 필요가 없기 때문에 명시 적으로 타이핑되지는 않습니다 (전적으로 파이썬은 아니지만 Cython은 제외). 또한 정적으로 입력되지 않습니다.

C 및 C ++는 명시 적으로 형식화되고 정적으로 형식화되고 다소 강력하게 형식화됩니다. 유형을 선언하고 컴파일 타임에 형식이 결정되며 정수와 포인터 또는 정수와 복식을 혼합하거나 한 유형에 대한 포인터를 캐스트 할 수 있기 때문에 다른 유형에 대한 포인터

Haskell은 명백하게 입력되지 않았지만 정적으로 강력하게 입력되기 때문에 흥미로운 예입니다.


+1 "manfestly typed"라는 용어가 마음에 듭니다. Java 및 C #과 같은 언어를 명시 적으로 분류하여 형식을 명시 적으로 선언하고 형식 유추가 중요한 역할을하는 Haskell 및 Scala와 같은 다른 정적 유형 언어와 구분해야하는 언어를 분류합니다. 당신이 말하는 것처럼 사람들을 혼란스럽게 만들고, 이들 언어가 동적으로 형식화되었다고 믿게합니다.
에드윈 달로 조

3

강한 <=> 약한 타이핑은 한 데이터 유형의 언어가 다른 데이터 유형에 대한 언어에 의해 자동으로 강요되는 양 또는 양에 대한 연속성뿐만 아니라 실제 이 얼마나 강하거나 약하게 입력 되는지에 관한 것 입니다. Python과 Java 및 대부분 C #에서 값의 유형은 스톤으로 설정됩니다. Perl에서는 그다지 많지 않습니다. 변수에 저장할 소수의 다른 값 유형이 실제로 있습니다.

사례를 하나씩 열어 봅시다.


파이썬

파이썬 예제 1 + "1"에서+ 연산자는 __add__for 유형 int을 호출하여 문자열 "1"을 인수로 제공 하지만 NotImplemented가됩니다.

>>> (1).__add__('1')
NotImplemented

다음으로 통역사는 __radd__str을 시도합니다 .

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

실패하면 + 연산자는 결과와 함께 실패합니다 TypeError: unsupported operand type(s) for +: 'int' and 'str'. 따라서 예외는 강력한 타이핑에 대해 많이 말하지 않지만 연산자 가 강제하지 않는다는 사실+ 인수를 동일한 유형으로 자동으로 사실은 파이썬이 연속체에서 가장 약한 유형의 언어가 아니라는 사실에 대한 포인터입니다.

반면에 파이썬에서는 'a' * 5 구현됩니다.

>>> 'a' * 5
'aaaaa'

그건,

>>> 'a'.__mul__(5)
'aaaaa'

작업이 다르다는 사실은 약간의 타이핑이 필요합니다. * 곱하기 전에 값을 숫자 강제 변환하는 값을 약하게 입력 할 필요는 없습니다.


자바

Java 예제 String result = "1" + 1;는 편의상 연산자 +가 문자열에 과부하되어 있기 때문에 작동합니다 . 자바 +연산자는을 만드는 순서를 대체 StringBuilder합니다 ( )

String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()

이것은 실제 강제 StringBuilder가 없는 매우 정적 인 타이핑의 예입니다- append(Object)여기에 특별히 사용되는 방법 이 있습니다. 설명서는 다음과 같이 말합니다.

Object인수 의 문자열 표현을 추가합니다 .

전체적인 효과는 마치 인수가 메소드에 의해 문자열로 변환 된 것과 똑같이 String.valueOf(Object)해당 문자열의 문자가이 문자 시퀀스에 추가 된 것과 같습니다.

어디 String.valueOf다음

Object 인수의 문자열 표현을 리턴합니다. 인수가이면 null문자열이 "null"; 그렇지 않으면의 값 obj.toString()이 반환됩니다.

따라서 이것은 언어에 의한 강요가 전혀없는 경우입니다-모든 관심사를 객체 자체에 위임하십시오.


씨#

Jon Skeet의 답변 에 따르면 연산자 +string클래스와 Java와 비슷하게 오버로드되지 않으며 정적 및 강력한 타이핑 덕분에 컴파일러가 생성하는 편의성입니다.


perldata가 설명 하듯이

Perl에는 세 개의 기본 제공 데이터 유형 (스칼라, 스칼라 배열 및 "해시"라고하는 스칼라 배열)이 있습니다. 스칼라는 단일 문자열 (사용 가능한 메모리로만 제한되는 모든 크기), 숫자 또는 무언가에 대한 참조 (perlref에서 설명)입니다. 일반 배열은 0부터 시작하여 숫자로 색인화 된 스칼라 목록입니다. 해시는 연관된 문자열 키로 색인화 된 스칼라 값의 정렬되지 않은 콜렉션입니다.

그러나 Perl은 숫자, 부울, 문자열, null, undefineds, 다른 객체에 대한 참조 등에 대한 별도의 데이터 유형을 가지고 있지 않습니다 . 0은 "0"만큼의 스칼라 값입니다. 문자열로 설정된 스칼라 변수 는 실제로 숫자로 변경 될 수 있으며 숫자 컨텍스트에서 액세스하는 경우 "문자열"과 다르게 동작합니다.. 스칼라는 Perl에서 무엇이든 가질 수 있으며 시스템에 존재하는만큼의 오브젝트입니다. 파이썬에서 이름은 단지 객체를 참조하고, Perl에서 이름의 스칼라 값은 변경 가능한 객체입니다. 또한 객체 지향 유형 시스템은이 위에 붙어 있습니다. 스칼라, 목록 및 해시에는 3 가지 데이터 유형이 있습니다. Perl의 사용자 정의 객체 대한 참조 (이전 3 개 중 하나에 대한 포인터)입니다.bless패키지에 연결된 -이러한 값을 가져 와서 원하는 순간에 모든 클래스에 축복 할 수 있습니다.

펄은 심지어 값의 클래스를 변덕스럽게 바꿀 수 있습니다-파이썬에서 일부 클래스의 값을 생성하는 곳에서는 불가능합니다 object.__new__. 파이썬에서는 생성 후 객체의 본질을 실제로 바꿀 수 없으며, Perl에서는 많은 것을 할 수 있습니다.

package Foo;
package Bar;

my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n"; 
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";

따라서 타입 아이덴티티는 변수에 약하게 묶여 있으며, 어떤 참조를 통해서든 변경 될 수 있습니다. 사실, 당신이 할 경우

my $another = $val;

\$another\$val여전히 축복받은 참조를 줄 지라도, 학급 정체성이 없습니다 .


TL; DR

자동 강제보다는 Perl에 대한 약한 타이핑에 대해 훨씬 더 많은 것이 있으며, 동적이지만 매우 강력한 유형의 언어 인 Python과 달리 값 자체의 유형은 돌로 설정되지 않습니다. 파이썬이 제공 TypeError하는 1 + "1"것은 Java 또는 C #에서 강력하게 유형이 지정되는 언어를 배제하지 않는 것처럼 유용한 무언가를 수행하는 것과 반대로 언어가 강력하게 유형화되었음을 나타냅니다.


이것은 완전히 혼란 스럽다. Perl 5 변수 에는 유형이 없으며 에는 항상 유형이있는 이 없습니다 .
Jim Balter 2016 년

@JimBalter 예, 값은 문자열 또는 숫자라는 유형을 가지고 있으며 스칼라 변수에 문자열 또는 숫자가 포함되어 있는지 여부에 따라 일부 컨텍스트에서 다르게 작동 할 수 있습니다. 그러나 값은 변수에 액세스하여 유형을 변경할 수있는 변수에 포함 된, 값 자체가 생활 이후 변수의 값 자체는 타입과 가변 간주 될 수있다.
Antti Haapala 2016 년

값은 유형을 변경하지 않습니다. 일관성이 없습니다. 값은 항상 유형 입니다. 변수에 포함 된 값은 변경 될 수 있습니다. 1에서 "1"로의 변화는 1에서 2 로의 변화만큼이나 가치의 변화입니다.
Jim Balter

Perl과 같이 약한 유형의 언어를 사용하면 컨텍스트에 따라 이전 유형의 값 변경이 암시 적 으로 발생할 수 있습니다 . 그러나 C ++에서도 연산자 정의를 통한 암시 적 변환이 가능합니다. 에릭 리퍼 (Eric Lippert)가 지적한 것처럼 약한 타이핑은 매우 비공식적 인 속성이며 언어를 설명하는 유용한 방법이 아닙니다.
Jim Balter 2016 년

PS Perl에서도 <digits>와 "<digits>"는 다른 유형뿐만 아니라 다른 값을 가지고 있음을 알 수 있습니다. Perl은 대부분의 경우 암시 적 변환을 통해 <digits>와 "<digits>"의 값이 동일한 것으로 보이지만 환상은 완전하지 않습니다. 예 : "12"| "34"는 36이지만 12 | 또 다른 예로 "00"은 대부분의 컨텍스트에서 숫자 적으로 00과 같지만 부울 컨텍스트에서는 그렇지 않습니다. 여기서 "00"은 true이지만 00은 false입니다.
Jim Balter 2016 년

1

다른 많은 사람들이 말했듯이 "강한"대 "약한"타자라는 전체 개념은 문제가 있습니다.

아키 타입으로서 스몰 토크는 매우 강력하게 타이핑됩니다 . 두 객체 간의 작업이 호환되지 않으면 항상 예외가 발생합니다. 그러나,이 목록에서 스몰 토크가 동적으로 형식화 되기 때문에 강력하게 형식화 된 언어라고 부르는 사람은 거의 없을 것 입니다.

"정적"대 "동적"타이핑 개념이 "강한"대 "약한"보다 더 유용하다는 것을 알았습니다. 정적으로 타입이 지정된 언어는 컴파일 타임에 알아 낸 모든 타입을 가지고 있으며, 프로그래머는 그렇지 않으면 명시 적으로 선언해야합니다.

런타임에 입력이 수행되는 동적 형식 언어와 대조됩니다. 이것은 일반적으로 다형성 언어에 대한 요구 사항이므로 두 객체 간의 작업이 합법적인지 여부에 대한 결정은 프로그래머가 미리 결정하지 않아도됩니다.

스몰 토크 및 루비와 같은 다형성의 동적 형식 언어에서 "유형"을 "프로토콜에 대한 적합성"으로 생각하는 것이 더 유용합니다. 개체가 상속이나 믹스 인 또는 다른 부두를 공유하지 않더라도 다른 개체와 동일한 방식으로 프로토콜에 순종하는 경우 런타임 시스템에서 동일한 "유형"으로 간주합니다. 보다 정확하게는 이러한 시스템의 객체는 자율적이며 특정 인수를 참조하는 특정 메시지에 응답하는 것이 적합한 지 결정할 수 있습니다.

파란색을 나타내는 개체 인수를 사용하여 "+"메시지에 의미있는 응답을 줄 수있는 개체를 원하십니까? 동적 형식 언어에서는 그렇게 할 수 있지만 정적 형식 언어에서는 어려움이 있습니다.


3
동적 대 정적 입력의 개념은 논의 중이 아니라고 생각합니다. 나는 다형성이 어쨌든 정적으로 유형의 언어로 장애가 있다고 믿지 않는다고 말해야하지만. 궁극적으로 타입 시스템은 주어진 연산이 런타임 또는 컴파일 타임에 주어진 피연산자에 적용 가능한지 검증합니다. 또한 파라 메트릭 함수 및 클래스와 같은 다른 형태의 다형성은 유형이 유추 된 경우 동적 유형과 비교할 때 매우 어려운 방식으로 정적 유형 언어의 유형을 결합 할 수 있습니다.
Edwin Dalorzo

0

@Eric Lippert의 답변이 마음에 들지만 질문을 처리하기 위해 강하게 유형이 지정된 언어는 일반적으로 프로그램의 각 지점에서 변수 유형에 대한 명확한 지식을 가지고 있습니다. 약한 유형의 언어는 그렇지 않으므로 특정 유형에서는 불가능한 작업을 수행 할 수 있습니다. 이것을 보는 가장 쉬운 방법은 함수에 있다고 생각합니다. C ++ :

void func(string a) {...}

변수 a는 문자열 유형 인 것으로 알려져 있으며 컴파일 할 때 호환되지 않는 작업이 포착됩니다.

파이썬 :

def func(a)
  ...

변수 a는 무엇이든 될 수 있으며 우리는 유효하지 않은 메소드를 호출하는 코드를 가질 수 있습니다.


12
동적 타이핑 대 정적 타이핑을 강력한 타이핑 대 약한 타이핑과 혼동하고 있다고 생각합니다. 두 버전의 코드에서 런타임 유형 시스템은 a가 문자열임을 잘 알고 있습니다. 첫 번째 경우에는 컴파일러가 두 번째 경우에는 할 수 없다는 것을 알 수 있습니다. 그러나 이것은이 언어들 중 어떤 것도 약한 유형으로 만들지 않습니다.
Edwin Dalorzo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.