PHpullh
언어 비교/Hello World

LANGUAGE COMPARISON

Hello World를 언어별로 비교하기

같은 개념을 실제 예제로 나란히 확인하고, 각 언어의 개별 설명으로 이어갈 수 있습니다.

첫 줄에서 이미 갈라지는 것들

Hello World는 언어의 문법을 보여주는 예제가 아니라, 그 언어가 프로그램의 시작을 어떻게 정의하는지를 보여주는 예제입니다. 아래 코드들을 보면 어떤 언어는 파일에 문장 하나만 있어도 그것이 곧 프로그램이고, 어떤 언어는 클래스와 진입점 함수라는 껍데기를 먼저 요구합니다. 이 차이는 취향이 아니라, 그 언어가 상정한 실행 단위가 스크립트 한 장인지 빌드된 산출물인지에서 옵니다.

실행 방식으로 나누면 네 갈래가 보입니다. Python, JavaScript, PHP는 소스를 그대로 인터프리터에 넘기면 끝납니다. Go, Rust, C++는 먼저 기계어 실행 파일을 만들고 그 파일을 실행합니다. Java와 Kotlin은 바이트코드로 컴파일한 뒤 JVM 위에서 돌리고, C#도 같은 구조를 CLR로 갖습니다. TypeScript는 혼자 실행되지 않고 JavaScript로 변환된 다음에야 런타임을 만납니다. "한 줄이면 되는 언어"와 "다섯 줄이 필요한 언어"의 차이는 대부분 이 단계 수의 차이입니다.

그래서 처음 배울 때 진짜 벽이 되는 것은 print 문법이 아니라 그 앞뒤의 환경입니다. Java는 JDK와 클래스 이름 규칙, Go는 모듈 초기화, Rust는 툴체인과 Cargo, TypeScript는 컴파일러 설정 파일이 먼저 자리를 잡아야 합니다. 각 언어의 환경 준비 과정은 학습 라이브러리의 언어별 문서에서 이어서 확인하실 수 있습니다.

Kotlin

Hello World 출력

Kotlin에서 가장 첫 번째로 배우는 Hello World. JVM 언어이지만 class 없이 top-level 함수로 바로 실행됩니다.

fun main() {
    println("Hello, World!")

    // print()는 줄바꿈 없이 출력
    print("Hello ")
    print("Kotlin!")
    println() // 빈 줄 출력
}

Python

Hello World 출력

Python에서 가장 첫 번째로 배우는 Hello World. 별도의 main 함수나 클래스 없이 한 줄로 실행됩니다.

# 가장 기본적인 출력
print("Hello, World!")

# 여러 값 출력
print("언어:", "Python", "버전:", 3.12)

# sep, end 파라미터
print("a", "b", "c", sep="-")    # a-b-c
print("줄바꿈 없이", end=" ")
print("이어서 출력")

# f-string 출력 (Python 3.6+)
name = "Python"
version = 3.12
print(f"Hello, {name} {version}!")

# f-string 디버깅 (Python 3.8+)
x = 42
print(f"{x = }")   # x = 42

Go

Hello World & 패키지 구조

Go 프로그램의 최소 구조. package main과 func main()이 진입점입니다.

package main

import (
	"fmt"
	"runtime"
)

func main() {
	// 기본 출력
	fmt.Println("Hello, World!")

	// Printf — 포맷 지정
	fmt.Printf("언어: %s, 버전: %s
", "Go", runtime.Version())

	// Sprintf — 문자열 반환
	msg := fmt.Sprintf("GOOS: %s, GOARCH: %s",
		runtime.GOOS, runtime.GOARCH)
	fmt.Println(msg)

	// 여러 값 출력
	fmt.Println("값:", 42, true, 3.14)
}

Java

Hello World — 클래식 & 최신 문법

Java의 전통적인 Hello World부터 Java 21의 간결한 문법까지. 엔트리포인트와 출력 방법을 마스터합니다.

// 전통적인 방법 (Java 1 ~ 현재)
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");

        // 포맷 출력
        String name = "Java";
        int version = 21;
        System.out.printf("언어: %s, 버전: %d%n", name, version);

        // String.format
        String msg = String.format("Hello, %s %d!", name, version);
        System.out.println(msg);

        // formatted() — Java 15+
        String msg2 = "Hi, %s!".formatted(name);
        System.out.println(msg2);
    }
}

// Java 21 — Unnamed Class (Preview)
// 파일명: Hello.java
// void main() {
//     System.out.println("Hello from Java 21!");
// }

// Text Block (Java 15+)
// String json = """
//         {
//             "language": "Java",
//             "version": 21
//         }
//         """;

JavaScript

Hello World 출력

main 안에서 println! 하나로 Hello, World 1! 문자열을 표준 출력에 내보냅니다. 새 프로젝트가 실제로 빌드되고 실행되는지 확인하는 첫 단계로 쓰입니다. println!은 함수가 아니라 매크로여서 포맷 문자열과 인자 개수가 컴파일 시점에 검사되고, 줄바꿈은 자동으로 덧붙습니다.

// Hello World 출력
console.log("Hello, World 1!");

TypeScript

Hello World 출력

main 안에서 println! 하나로 Hello, World 1! 문자열을 표준 출력에 내보냅니다. 새 프로젝트가 실제로 빌드되고 실행되는지 확인하는 첫 단계로 쓰입니다. println!은 함수가 아니라 매크로여서 포맷 문자열과 인자 개수가 컴파일 시점에 검사되고, 줄바꿈은 자동으로 덧붙습니다.

// Hello World 출력
console.log("Hello, World 1!");

C#

Hello World 출력

main 안에서 println! 하나로 Hello, World 1! 문자열을 표준 출력에 내보냅니다. 새 프로젝트가 실제로 빌드되고 실행되는지 확인하는 첫 단계로 쓰입니다. println!은 함수가 아니라 매크로여서 포맷 문자열과 인자 개수가 컴파일 시점에 검사되고, 줄바꿈은 자동으로 덧붙습니다.

// Hello World 출력
using System;

Console.WriteLine("Hello, World 1!");

C++

Hello World 출력

main 안에서 println! 하나로 Hello, World 1! 문자열을 표준 출력에 내보냅니다. 새 프로젝트가 실제로 빌드되고 실행되는지 확인하는 첫 단계로 쓰입니다. println!은 함수가 아니라 매크로여서 포맷 문자열과 인자 개수가 컴파일 시점에 검사되고, 줄바꿈은 자동으로 덧붙습니다.

// Hello World 출력
#include <iostream>

int main() {
    std::cout << "Hello, World 1!\n";
}

Rust

Hello World 출력

main 안에서 println! 하나로 Hello, World 1! 문자열을 표준 출력에 내보냅니다. 새 프로젝트가 실제로 빌드되고 실행되는지 확인하는 첫 단계로 쓰입니다. println!은 함수가 아니라 매크로여서 포맷 문자열과 인자 개수가 컴파일 시점에 검사되고, 줄바꿈은 자동으로 덧붙습니다.

// Hello World 출력
fn main() {
    println!("Hello, World 1!");
}

짧은 코드가 곧 쉬운 언어는 아닙니다

Hello World만 놓고 보면 Python이 이기고 Java가 집니다. 하지만 이 비교는 프로그램이 한 줄일 때만 성립합니다. Java가 요구하는 클래스와 main 서명은 파일 하나짜리 프로그램에서는 잡음이지만, 파일이 수백 개가 되면 "진입점은 정확히 여기 하나"라는 보장으로 바뀝니다. 반대로 Python은 어떤 파일이든 import되는 순간 최상위 코드가 실행되기 때문에, 규모가 커지면 if __name__ == "__main__": 관용구를 직접 붙여 진입점을 방어해야 합니다. 초반의 간결함을 나중에 관례로 되갚는 셈입니다.

비교표에서 줄 수를 세는 습관은 여기서 멈추는 편이 낫습니다. 이 문서들의 목적은 순위표가 아니라, 같은 요구사항을 각 언어가 어디에 밀어 넣는지를 보는 것입니다.

출력 한 줄 뒤에 숨어 있는 실무 차이

  • 표준 출력과 버퍼링 — 대부분의 런타임은 stdout이 터미널이면 줄 단위로, 파일이나 파이프로 리다이렉트되면 블록 단위로 버퍼링합니다. 로그가 안 보인다는 신고의 상당수가 프로그램이 죽으면서 버퍼를 비우지 못한 경우입니다.
  • 줄바꿈 포함 여부 — Python print, Go fmt.Println, Java println은 줄바꿈을 붙여 주지만 fmt.Print, System.out.print, C++의 std::cout는 붙이지 않습니다. 로그를 파싱하는 쪽에서 문제가 되는 지점입니다.
  • 인코딩 — 한글을 출력하는 순간 터미널 인코딩과 소스 파일 인코딩이 둘 다 관여합니다. 소스를 UTF-8로 저장했는데 콘솔이 다른 코드페이지면 깨집니다. 언어 문제가 아니라 환경 문제입니다.
  • 종료 코드 — 출력에 성공해도 프로세스가 0이 아닌 코드로 끝나면 CI는 실패로 봅니다. 스크립트를 자동화에 붙이기 전에 종료 코드를 명시적으로 다루는 습관이 필요합니다.

언어를 옮겨 다닐 때 첫날에 걸리는 함정들입니다. Java는 public 클래스 이름과 파일 이름이 같아야 합니다. Go는 쓰지 않는 import와 지역 변수를 경고가 아니라 컴파일 오류로 처리하므로, 디버깅하려고 잠깐 주석 처리한 코드 때문에 빌드가 깨집니다. PHP는 여는 태그 앞의 공백 한 칸이 그대로 응답 본문에 섞여 헤더 전송을 망칩니다. JavaScript는 같은 코드가 Node에서는 되고 브라우저에서는 console 외에 표준 출력이 없습니다.

다음 단계로는 값을 담고 다루는 방식을 비교한 Variable 비교와, 실행 흐름을 나누는 Function 비교를 함께 보시면 언어별 기본기가 빠르게 정리됩니다.

이 페이지를 읽는 순서

새 언어를 시작하는 상황이라면 코드보다 먼저 확인할 것이 세 가지 있습니다. 첫째, 이 언어를 실행하려면 무엇을 설치해야 하는가입니다. 인터프리터 하나면 되는지, SDK 전체가 필요한지, 별도 빌드 도구가 필요한지에 따라 첫날에 드는 시간이 완전히 달라집니다. 둘째, 파일 하나짜리 프로그램에서 여러 파일짜리 프로젝트로 넘어갈 때 무엇이 바뀌는가입니다. Go의 모듈, Java의 패키지와 클래스패스, Node의 package.json, Rust의 크레이트가 각각 그 경계에 있습니다. 셋째, 표준 포매터와 린터가 있는가입니다. Go와 Rust처럼 공식 포매터가 정해진 언어는 스타일 논쟁 없이 바로 코드를 씁니다.

이미 다른 언어를 아는 상태라면 Hello World는 사실 30초면 끝나는 단계이므로, 여기서 오래 머무르실 필요는 없습니다. 오히려 값이 나오는 곳은 그 다음입니다. 문자열을 다루는 방식, 컬렉션 API의 이름, 오류를 알리는 관례를 먼저 훑어보면 그 언어로 작성된 남의 코드를 읽는 속도가 빨리 붙습니다.