💭
Booleanとは何なのかをRuby, Rust, Pythonで掘り下げる
はじめに
私のソフトウェアのエンジニアとしての入りはC言語でした。次にPythonを触り、Booleanを見たときに衝撃を覚えたのを思い出します。
今回は、普段使用しているBooleanをRuby, Rust, Pythonで掘り下げてみます。
マシンスペック
MacBook Air M2 arm64
Docker上で実施
準備
Dockerの起動
mkdir bool_deepdive && cd $_
mkdir -p ruby python rust
vim Dockerfile
# ================================================================
# Boolean Deep‑Dive Lab (Ubuntu 24.04, arm64/amd64 共通)
# - ruby-dev (debug build, libffi/fiddle 有り)
# - python-dev (CPython 3.12.11, --with-pydebug)
# - Rust stable (cargo/rustc) ← dev ユーザ HOME にインストール
# - gdb / lldb / clang
# ================================================================
#############################
# Stage 0 : Base OS + build tools
#############################
FROM ubuntu:24.04 AS base
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential git autoconf automake libtool pkg-config \
zlib1g-dev libssl-dev libreadline-dev libffi-dev \
wget curl ca-certificates \
gdb lldb clang \
python3.12 python3.12-venv python3.12-dev python3-pip \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
#############################
# Stage 1 : Rust install (non‑root dev user)
#############################
FROM base AS rust-layer
RUN useradd -ms /bin/bash dev
USER dev
WORKDIR /home/dev
# rustup-init をユーザー権限で実行
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --default-toolchain stable --no-modify-path
# dev ユーザーの cargo/bin を PATH に
ENV PATH="/home/dev/.cargo/bin:${PATH}"
#############################
# Stage 2 : Build CPython (debug)
#############################
FROM rust-layer AS build-python
USER root
WORKDIR /opt
RUN git clone --depth 1 --branch v3.12.11 https://github.com/python/cpython.git
WORKDIR /opt/cpython
RUN ./configure --with-pydebug && make -j$(nproc)
#############################
# Stage 3 : Build Ruby (debug + fiddle)
#############################
FROM rust-layer AS build-ruby
USER root
WORKDIR /opt
RUN git clone --depth 1 https://github.com/ruby/ruby.git \
&& chown -R root:root ruby
WORKDIR /opt/ruby
RUN wget -O tool/config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess' \
&& wget -O tool/config.sub 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub'
RUN apt-get update && apt-get install -y ruby-full
RUN autoconf \
&& ./configure --enable-shared --disable-install-doc --enable-debug-env --with-libffi BASERUBY=$(which ruby) \
&& make -j$(nproc)
#############################
# Stage 4 : Final dev image
#############################
FROM rust-layer
LABEL purpose="boolean-deep-dive"
# --- interpreters & sources ---
COPY /opt/cpython/python /usr/local/bin/python-dev
COPY /opt/cpython /opt/cpython-src
COPY /opt/ruby/miniruby /usr/local/bin/ruby-dev
COPY /opt/ruby /opt/ruby-src
# dev ユーザは rustup & cargo を既に PATH で使える
WORKDIR /home/dev
CMD ["bash"]
# ビルド
docker build -t bool-lab .
# 起動(ソース共有)
docker run -it --rm \
-v "$PWD/demo:/home/dev/demo" \
-v "$PWD/article:/home/dev/article" \
bool-lab
各ファイルの準備
Ruby
puts "Ruby Boolean Exploration"
puts "\n== true / false のクラス =="
p true.class
p false.class
puts "\n== object_id で即値確認 =="
p true.object_id # 常に20 (0x14)
p false.object_id # 常に0
puts "\n== true / false の内部表現 (整数として) =="
puts "trueの内部値: #{true.inspect} → #{true.object_id} (0x#{true.object_id.to_s(16)})"
puts "falseの内部値: #{false.inspect} → #{false.object_id} (0x#{false.object_id.to_s(16)})"
puts "\n== nil は falsy? =="
p !!nil # false
p !!0 # true
Python
print("Python Boolean Exploration\n")
print("== type(True), type(False) ==")
print(type(True), type(False)) # <class 'bool'>
print("\n== True, False は int のサブクラス? ==")
print(isinstance(True, int), isinstance(False, int)) # True, True
print("\n== id(True), id(False) を確認(シングルトンか?)==")
print(id(True), id(False))
print("\n== sys.getsizeof(True) のサイズ ==")
import sys
print(sys.getsizeof(True))
print("\n== falsyの観察 ==")
print(bool(None), bool(0), bool([]), bool({}))
Rust
cargo new rust_bool_demo && cd rust_bool_demo
fn main() {
println!("Rust Boolean Exploration\n");
println!("== boolのサイズ(メモリ上のサイズ) ==");
println!("size_of::<bool> = {}", std::mem::size_of::<bool>());
println!("\n== boolを整数へ変換 ==");
let t: bool = true;
let f: bool = false;
println!("true as u8 = {}", t as u8);
println!("false as u8 = {}", f as u8);
println!("\n== boolのメモリアドレスを確認 ==");
println!("&true = {:p}", &t);
println!("&false = {:p}", &f);
}
実行
Ruby
demo/demo.rb | tee ~/article/ruby_out.txt
Ruby Boolean Exploration
== true / false のクラス ==
TrueClass
FalseClass
== object_id で即値確認 ==
20
0
== true / false の内部表現 (整数として) ==
trueの内部値: true → 20 (0x14)
falseの内部値: false → 0 (0x0)
== nil は falsy? ==
false
true
Python
demo/demo.py | tee ~/article/python_out.txt
Python Boolean Exploration
== type(True), type(False) ==
<class 'bool'> <class 'bool'>
== True, False は int のサブクラス? ==
True True
== id(True), id(False) を確認(シングルトンか?)==
187650042234048 187650042234080
== sys.getsizeof(True) のサイズ ==
28
== falsyの観察 ==
False False False False
Rust
cd demo/rust_bool_demo
cargo run --release | tee ~/article/rust_out.txt
Compiling rust_bool_demo v0.1.0 (/home/dev/demo/rust_bool_demo)
Finished `release` profile [optimized] target(s) in 0.15s
Running `target/release/rust_bool_demo`
Rust Boolean Exploration
== boolのサイズ(メモリ上のサイズ) ==
size_of::<bool> = 1
== boolを整数へ変換 ==
true as u8 = 1
false as u8 = 0
== boolのメモリアドレスを確認 ==
&true = 0xffffe0c3f228
&false = 0xffffe0c3f22c
結果
言語 | Boolean型の特徴(メモリ表現) | 表現形式 | サイズ | 値の扱い方 |
---|---|---|---|---|
Ruby | 「即値」として特殊なタグ付き整数値で表現(ポインタでなく整数値) | 即値(特殊整数) | ポインタサイズ (64bit環境なら8byte) |
true=20 (0x14) 、false=0 と固定 |
Python |
bool 型はint 型のサブクラスで、True / False は固定されたシングルトンオブジェクト |
シングルトンオブジェクト | オブジェクトヘッダを含めて28byte | 常に同じアドレスに格納される |
Rust | 独立した「真偽値型」として定義され、1byteの整数値として表現 | 強型の独立した型 | 1 byte | true=1, false=0 と明確 |
まとめ
今回は、各言語のBooleanについて深掘りしました。
皆さんの学習の一助になれば幸いです。
Discussion