Copper: OOP와 제네릭을 갖춘 작고 단순한 저수준 프로그래밍 언어

Copper – A minimal low-level programming language with OOP and generics

tibleiz.net ▲ 203 댓글 118 bogdanoff_2

요약

Copper는 한 개발자가 C 대신 쓰려고 만든, 단순함을 최우선으로 삼은 언어입니다.

개발자 마르크 케르비케가 만들어 BSD 라이선스로 공개한 프로그래밍 언어입니다. 소개 페이지는 사람이 쉽게 이해할 수 있는 언어를 목표로 삼았다고 설명하며, 미니멀리즘을 가장 중요한 기능으로 꼽았습니다.

왜 중요한가

  • C를 대신할 언어를 클래스와 제네릭을 갖추면서도 작게 유지할 수 있는지 보여 주는 사례입니다.
  • HN에 이 글을 올린 이용자는 한 사람이 자기 용도로 만들어 온 언어라는 점을 흥미로운 대목으로 꼽았습니다.
  • 작성자의 블로그와 변경 기록에는 예외 기능을 넣었다가 철회한 설계 과정도 남아 있어 참고할 만하다고 했습니다.

핵심 내용

  • 모든 타입에 타입 상속을 쓸 수 있고, 제네릭과 다중 반환값을 지원합니다.
  • HN 댓글이 인용한 문서에 따르면 객체지향 언어는 아니지만, 객체지향 설계를 돕는 기능을 제공합니다.
  • 헤더 파일 없이 import로 코드를 가져오고, 모든 이름을 전역 네임스페이스에 몰아넣지 않습니다.
  • 지연 실행 구문(나중에 실행할 코드를 미리 적어 두는 문법)과 옵션 타입(값이 없을 수 있음을 타입으로 나타내는 방식)을 갖췄습니다.
  • 문법은 Ruby와 비슷하게 class, def, end 같은 키워드로 구성됩니다.

HN 반응

  • 일부 이용자는 변수 선언과 리터럴의 타입 표기가 어긋난다고 지적했고, 작성자는 문서가 낡았을 수 있다며 반박했습니다.
  • 컴파일러를 Copper로 작성한 점을 두고, 부트스트래핑(언어를 처음부터 빌드하는 과정)을 망친다는 비판과 C 백엔드가 있으면 괜찮다는 반론이 맞섰습니다.

댓글

30개 표시 · 전체 118개
  1. teo_zero HN

    건설적인 의견을 내고 싶은데, 전부 일관성이 없고 낯설게만 느껴집니다...

    예를 들어 변수 선언은 <콜론> <타입> 패턴을 씁니다.

      var a: Int32
    

    그런데 리터럴은 정반대 문법을 씁니다.

      a = Int32: 42
    

    함수의 반환 타입은 func 정의에서는 :로 시작하는데, import한 func 선언에서는 ->로 시작합니다.

      func foo(a:Int):Int
      import func bar(a:Int) -> (Int)
    

    제 습관과 거리가 먼 구문이 또 있습니다.

      var w, h, d = 640, 480, 2
    

    저한테는 아래 쪽이 훨씬 자연스럽습니다.

      var w=640, h=480, d=2
    

    인자는 값이 아니라 참조로 넘어갑니다. 재귀는 행운을 빕니다.

  2. marckerbiquet HN

    제작자입니다. 이 언어에 일관성 없는 부분이 아직 많긴 하지만, 말씀하신 것들은 아닙니다.

    함수 import도 같은 방식으로 합니다.

      func foo(a: Int): Int
      import func foo(Int): Int
    

    문서가 오래됐을 수도 있습니다.

    다중 선언은 대입과 일관되게 만든 겁니다.

      var w, h = 640, 480
      w, h = 640, 680
      w, h = getBoundingBox(obj)
    

    아래 문법은

      var a = Int: 32
    

    다른 많은 언어와 비교하면 특이하긴 한데, 단순한 문법 하나만 쓰기 때문입니다.

      var id = expr
    

    타입을 앞에 붙이는 건 리터럴의 타입을 정하기 위해서일 뿐입니다.

      var a = Int32: 42
      var b = Uint8: 42
    

    제네릭 함수에서 쓸모가 있을 수 있습니다.

      println("The answer is \a", Float32: 42)
    

    다만 초기화하지 않은 변수를 만들 때는 어쩔 수 없이 이 문법을 남겨 뒀습니다.

      var id: Type
    
  3. yxhuvud HN

    병렬 대입은 대체로 루비에서 하는 것과 똑같이 동작해서 저는 이상해 보이지 않습니다(애초에 var가 필요하다는 점만 빼면요).

    나머지는 동의합니다. 다만 재귀에 무슨 문제가 있다는 건지는 모르겠습니다. 정수 같은 기본 타입도 참조로 넘기는 건가요?

  4. teo_zero HN

    정수 같은 기본 타입도 참조로 넘기는 건가요?

    저는 그렇게 이해했는데, 솔직히 제가 문서를 잘못 읽었을 수도 있습니다. 이 대목이 그리 명확하지 않습니다.

    Copper는 객체에 대한 참조만 다룹니다. 정수 같은 단순 데이터 타입은 상태가 없는 객체(즉 메모리에 상태가 없는 객체)에 대한 참조로 봐야 합니다.

  5. yxhuvud HN

    그렇다면 정수를 참조 자체에 담아 두는 것 같네요. 루비도 그렇게 합니다. 다만 루비는 무엇이 무엇인지를 런타임에 판단해야 해서 정수마다 비트를 몇 개씩 떼어 쓰죠.

  6. Muhammad523 HN

    파이썬도 그렇게 해요.

  7. antihero HN

    그건 튜플 구조 분해(destructuring) 아닌가요?

  8. metadat HN

    동감입니다.. 그리고 ! 문법은 대체 뭔가요? 문서를 봐도 모든 경우에 용도가 분명하지는 않습니다.

    https://tibleiz.net/copper/documentation.html#basic-syntax

  9. teo_zero HN

    C++의 &와 반대인 것 같습니다. 즉 T!는 객체이고, T는 객체에 대한 참조입니다.

  10. Joker_vD HN

    의외로 제가 제일 거슬리는 사소한 점은 파일 확장자 선택입니다. 당연히 ".co"가 아니라 ".cu"여야 하지 않나요? 제가 (가령) Iron이라는 프로그래밍 언어를 만든다면(가상의 이야기고, 그런 이름의 언어가 이미 있을지도 모르지만) 망설임 없이 ".fe"로 정했을 겁니다.

    하긴, 저는 제가 만든 장난감 언어의 파일 확장자를 $'.\U0001F9CC'(즉 $'.\xF0\x9F\xA7\x8C')로 정한 사람이긴 합니다만...

  11. vopi HN

    Copper로서는 아쉽게도 .cu는 CUDA와 연결되어 있어서, 그래서 피했을지도 모르겠네요.

  12. mixmastamyk HN

    포르투갈어로 무슨 뜻인지는 묻지 마시고요.

  13. mxkopy HN

    저도 처음에 그 생각을 했어요.

  14. dapperhn HN

    프로그래밍 언어는 아니지만, 제인 스트리트(Jane Street)에는 Iron이라는 코드 리뷰 도구가 있었습니다(지금도 있나요?). 약어는 "fe"입니다.

    https://blog.janestreet.com/code-review-that-isnt-boring/

  15. pdpi HN

    그런 경우가 또 있어요. mercurial은 hg고, the silver searcher는 ag잖아요.

  16. anonymous908213 HN

    생각하시는 방식이 마음에 드네요.

  17. gorgoiler HN

    좀 더 살을 붙인 예제를 만들어 보려 한 점이 좋습니다. 다형성("제네릭")과 인터페이스("OOP")까지 볼 수 있었다면 더 좋았을 겁니다. 특히 언어가 강제하는 가시성 경계(패키지 같은 것)를 넘나드는 경우가 그렇습니다.

    제 경험상 추상 인터페이스에 맞춰 프로그래밍하는 것, 그리고 큰 코드베이스에서는 강제되는 가시성 제어가 "OOP"와 "선생님, 이건 C입니다" 사이에서 모두가 원하는 절충점입니다.

  18. sproutini HN

    서브타이핑과 제네릭이 들어오면 컨테이너가 공변인지 반공변인지 문제가 생깁니다.

  19. CyberDildonics HN

    왜 그렇죠?

  20. owlstuffing HN

    다형성("제네릭")과 인터페이스("OOP")까지 볼 수 있었다면 더 좋았을 겁니다

    맞습니다. 인터페이스 기반의 (진정한) 객체 간 위임이 있다면 저는 그걸 제일 먼저 쓸 겁니다.

  21. CyberDildonics HN

    a more fleshed out exemplar (살을 붙인 예시 모델)

    exemplar랑 example은 뭐가 다른가요?

    between “OOP” and “sir, this is C” ("OOP"와 "선생님, 이건 C입니다" 사이)

    그건 오히려 템플릿, 소유권, 연산자 오버로딩 쪽 얘기죠.

    다형성은 요즘 방식의 프로그래밍이 아닙니다. 의존성을 만들고 포인터를 따라가느라 속도가 크게 떨어지는데, 둘 다 좋은 프로그램에는 독이니까요.

  22. cestith HN

    example은 어떤 개념을 보여 주는 임의의 사례입니다. 문서 하나에 example을 잔뜩 넣어서 가능한 여러 경우를 보여 줄 수 있죠. exemplar는 개념을 모델링하고 설명하는 데 가장 좋다고 골라 둔 방식입니다.

    그래서 새 언어의 프로그래밍 교재라면 문자열이 되는 것들의 example, 선언할 법한 구조체의 example을 쓸 겁니다. 한 문제를 푸는 여러 방법을 example로 볼 수도 있겠죠. 반면 exemplar는 그 언어에서 무언가를 하는 가장 좋은 방법, 하다못해 가장 권장되는 방법 하나를 보여 줍니다.

  23. CyberDildonics HN

    An exemplar is the chosen best way to model and explain a concept. (exemplar는 개념을 모델링하고 설명하는 데 가장 좋다고 골라 둔 방식이다.)

    왜 더 나쁜 예시를 쓰는 거죠? 그리고 지금 보고 있는 예시가 최선이라는 건 어떻게 알죠?

  24. cestith HN

    example을 여러 개 넣는다면 이상적이지 않은 것도 고르게 됩니다. 모든 example이 최선일 수는 없으니까요. 일부러 나쁜 example이라고 표시해서 보여 줄 수도 있고요. exemplar라는 단어는 "exemplary"(모범적인)라는 형태로 더 익숙한 영어 화자가 많을 겁니다.

    내가 든 example이 exemplar인지 알기는 어려울 수 있습니다. 다만 언어 제작자가 예시를 하나만 내놓았다면 적어도 그게 최선이라고 보는 게 합리적입니다. 하나뿐이라면 적어도 문서 안에서는 최선인 거죠.

  25. CyberDildonics HN

    그분은 'a more fleshed out exemplar'(살을 더 붙인 exemplar)라고 했으니, 지금 있는 건 exemplar가 아니라는 뜻이죠.

  26. ricardobeat HN

    Crystal 팬으로서 문법이 정말 마음에 듭니다. 다만 문서만으로는 궁금한 점이 여러 가지 남습니다.

    메모리 모델은 어떻게 되나요? 무엇으로 컴파일되나요? 무엇 때문에 '저수준'이라는 건가요? GC가 있나요? C와 ABI 호환이 되거나 FFI가 있나요?

  27. bogdanoff_2 HN

    제가 만든 건 아니지만, 한 사람이 자기가 쓰려고 만든 언어라는 점에서 아주 흥미로웠습니다.

    제작자의 블로그에 언어 설계 글이 있는 것도 흥미롭습니다(예를 들어 예외 처리에 대한 생각, 그리고 자기 언어에 예외를 넣었다가 결국 접기로 한 이야기). 언어의 변경 이력에서는 진화 과정도 볼 수 있습니다.

    https://tibleiz.net/

    https://tibleiz.net/copper/changes.html

  28. pull_my_finger HN

    먼저 양해를 구해야겠습니다. 저는 foo 이야기를 하는 글에서 다들 bar 이야기로 새는 걸 질색하는데, 그런데도 한마디 하겠습니다.

    이 언어는 객체지향이 아니지만, 객체지향 설계를 쉽게 하는 몇 가지 기능을 제공합니다.

    클래스도 있고 암묵적인 self도 있습니다. 없는 건 아니지만, 그런 점에서 Lua나 JavaScript 같은 범용 언어보다 OOP가 더 낫다고 하기는 어려울 것 같습니다.

    Pony1 같은 언어가 더 성숙하고 기능도 풍부하고 OOP 쪽 완성도도 훨씬 높습니다.

    그건 그렇고, a) 남들이 하면 싫어하는 짓을 제가 한 점은 죄송합니다.

    b) 언어를 만드는 건 큰일인데, 해냈다는 게 정말 멋집니다.

    c) 이미 Copper로 작성되어 있는 것 같은데, 그것도 아주 멋지네요!

  29. stevefolta HN

    "c)"에 대해 말씀드리면, 아닙니다. 셀프 호스팅은 모든 프로그래밍 언어에 가장 큰 유혹이자 최악의 실수입니다. 부트스트래핑에는 죽음이죠. 그래도 유혹에 넘어가 셀프 호스팅을 한다면, Copper처럼 C 백엔드를 두는 게 아마 가장 좋은 대처법일 겁니다.

  30. p1necone HN

    저는 셀프 호스팅 반대론이 이해된 적이 없습니다.

    다음 조건만 충족된다면 말이죠.

    • 컴파일러 개발에 어울리는 종류의 언어일 것

    그리고

    • C 등으로 컴파일하는 기능이 있어서, 부트스트래핑에 불투명한 바이너리가 끼거나 git 커밋 30개를 연달아 컴파일할 필요가 없을 것

    대체 단점이 뭔가요?

Hacker News에서 보기 ↗