새 아픔을 찾으려면 도메인을 바꾼다

네 dogfood 애플리케이션은 모두 같은 나라에 살았다 —— 입력과 출력에 묶인 string과 record의 일 —— 그리고 새 종류의 아픔을 내는 것을 그만두었다. 그래서 다음 것은 의도해 수치로 했다: CSV 열에 걸친 통계 도구. 그것은 새 부류의 마찰을 즉시 찾았고, 가장 날카로운 것은 부동소수점 수에 infix 연산자가 전혀 없다는 것이었다. 수정은 JSON 가족이 세워진 바로 그 기구를 재사용했고, 한 충돌은 이전의 수정을 이름으로 떠올리게 했고, 그리고 아크는 정직하게 열린 채 남겨진 가장자리에서 닫혔다 —— ad-hoc 다상의 순서의 절반, 아직 세워지지 않은.

meredogfoodnumericoperatorslanguage-design

이제 dogfood 방법에는 이름 지을 값이 있는 약점이 있었다. 네 애플리케이션이 언어의 거친 가장자리를 찾기 위해 세워졌다 —— web과 database 앱, realtime 노트 서버, 커맨드라인 쿼리 도구, awk 풍의 평가기 —— 그리고 그것들은 모두 같은 나라에 살았다. 그 어느 것도 string과 record의 일이었고, 입력과 출력에 묶이고, 그 산술은 부수적이었다. 그것들은 그 나라의 아픔에 대해 철저했고, 그리고 조용해졌다, 왜냐하면 프로그램은 자기 자신의 형태가 닿는 아픔만 surface할 수 있기에. 새 아픔을 찾는 길은 넷 같은 다섯째 애플리케이션을 세우는 게 아니라; 완전히 다른 도메인으로 옮기는 것이고, 명백한 미답의 하나는 수치였다.

아무도 치르지 않았던 세금

그래서 다섯째 dogfood는 통계 도구였다: CSV 파일에서 수의 열을 읽고, count, mean, median, 최소, 최대, 표준편차를 보고한다. 그리고 그것은 거의 즉시 새 나라의 국경에 부딪혔다. 부동소수점 수에는, 판명된바, infix 연산자가 전혀 없었다. 덧셈과 그 나머지는 prefix 함수 호출이었고, 비교 연산자는 정수에만 정의되어, 그래서 두 float의 비교는 타입 에러였다. 도구의 수치 코어, 산술처럼 읽혀야 할 부분은, 대신 함수 적용의 이어짐처럼 읽혔다 —— 달리는 합계는 plus가 아니라 call이었다. 이것은 수치 프로그램이 치르도록 요구받을 수 있는 최대의 ergonomic한 세금이고, 그리고 그것은 전혀 눈치채이지 않고 왔다, 왜냐하면 이전 네 애플리케이션의 어느 것도, 그것을 느낄 만큼의 산술을 소수에 하지 않았기에. 아픔은 늘 거기 있었다; 어느 프로그램도 그것에 다칠 올바른 곳에 선 적이 없었을 뿐이다.

가족을, 다시 한번 확장한다

수정은 새 기구를 요하지 않았고, 그것이 멈춰 설 값이 있는 부분이다. 연산자를 부동소수점 수에서 동작하게 하는 것은, 이전 Part가 그림과 JSON과 등가를 위해 세운 바로 그 기구를 썼다: 연산자를 overload하고, 코드 생성기에 operand의 타입에서 올바른 구현을 컴파일 타임에 고르게 한다, runtime dispatch 없이, trait 선언 없이. 산술 연산자는 같은 컴파일 타임 특수화된 가족의 새 멤버가 그저 되었다 —— 하나의 이름, 정수의 거동이나 부동소수점의 거동, 이미 알려진 타입으로 골라지는. 그것들을 데려오는 것은, 밑에 숨어 있던 잠복 버그마저 씻어냈다: 정수값의 부동소수점 리터럴이, 컴파일러가 그것을 정수로 읽어 되돌리는 형태로 print 되고 있어, 그래서 두 그런 리터럴의 나눗셈이 조용히 정수 나눗셈이었다. 수치 도구의 코어는, 연산자가 착지하자, prefix 호출이 하나도 남지 않은 평범한 산술로 읽혔다.

가족을 가졌던 충돌

한 마찰은 정신에서 이미 풀려 도착했다, 왜냐하면 그것은 연재가 이전에 만난 가족에 속했기에. 표준 수학 라이브러리의 함수와 같은 이름의 헬퍼 함수가, 컴파일되면 그것과 충돌하고, C 컴파일러가 하나의 이름의 두 모순되는 정의를 거부했다 —— 커맨드라인 도구가 스레드 primitive로 한 나라 전에 뛰어든 섀도잉 문제의 바로 그 형태. 처치는 같았다: backend에, 이 라이브러리 이름들도, 프로그램 자신의 정의에 양보해 방해되지 않도록 리네임되어야 한다고 가르친다. 재발하는 가족의 버그를 찾는 것은 기를 꺾는 일이 아니다. 그것은 수정이 패턴이 되어 가고 있음을 의미하고, 패턴은 두 번째로 적용하는 편이 싸다.

의도해 열린 채의 가장자리

아크의 가장 정직한 부분은, 그것이 완전히는 고치지 않은 아픔이다. list를 정렬하는 것은 통계 도구가 원하는 자연스러운 다음 것이고, 편리한 기본 정렬은 비교 연산자의 관점에서 정의되어 있었다 —— 그것은 이제 float에서 동작했지만, 값이 구체적으로 타입 지어졌을 때뿐. 기본 정렬은 쓰인 시점에 정수의 비교를 구워 넣어, 그래서 float의 list를 정렬하려면 아직 주석 붙은 비교를 손으로 적을 필요가 있었다. 이 밑에 있는 것은 genuine히 미완성의 프런티어다: 언어는 형태를 걸어 임의의 타입에서 동작하는 구조적 등가를 가지지만, 그에 맞는 구조적 순서를 가지지 않는다 —— 구조적 등가가 있는 것과 같이 record와 tuple을 위한 도출된 less-than이 없다. 그것이 ad-hoc 다상의 순서의 절반이고, 그것은 실이고, 그리고 세워지지 않았다. 그것을 평명히, 숨은 가장자리가 아니라 알려진 가장자리로 이름 짓는 것이, 그것을 남기는 유일한 정직한 방식이고 —— 그리고 그것을, 설계를 서두르는 게 아니라 남기는 것은, 연재가 해 온 모든 것과 일관된다: feature는 그 부재를 견딜 수 없게 만드는 프로그램을 기다리고, 주석 하나 더로 정렬할 수 있는 통계 도구는 아직 그 프로그램이 아니다.

다섯째 나라가 가르친 것

연습 통째의 교훈은 방법 자신에 대한 사실이다. 언어가 줄 채 남긴 아픔은, 그것에 대해 쓰인 프로그램의 함수이고, 같은 도메인의 네 프로그램은 이윽고 언어는 문제없다고 합의한다 —— 그것이 그래서가 아니라, 결코 닿지 않는 것을 더는 느낄 수 없기에. 수치로 옮기는 것이 첫날에 다시 언어의 입을 열게 했고, 그것이 말한 것들은 네 string 도구가 결코 말할 수 없던 것들이었다. 그것은 또 테이블 위에 깨끗한, 이름 지어진 물음을 남겼다 —— 구조적 등가 곁에 앉는 구조적 순서 —— 그것은 바로 살아 있는 언어가 있어야 할 자세다. dogfood 루프는 이제 다섯 도메인에서 돌려졌고, 그 휴식을 얻었다, 왜냐하면 언어가 증명할 채 남긴 다음 것은 어느 애플리케이션에 대해서도 전혀 아니었기에. 그것은 컴파일러 자신에 대해서였고, 이 다섯 전부를 컴파일해 온 것이, 마침내, 그것이 한 번도 진정 돌린 적 없는 하나의 프로그램을 올바로 컴파일할 수 있는가 —— 자기 자신을, 이었다.

← Back to Mere: 언어를 만들다