2 poin oleh GN⁺ 2024-07-16 | 1 komentar | Bagikan ke WhatsApp
  • Pada LSFMM+BPF Summit 2024, dibahas cara menerapkan Rust pada sistem berkas Linux, dan patch RFC kedua yang muncul setelah RFC Desember 2023 menjadi pusat diskusi
  • Pihak Rust-for-Linux ingin memasukkan kebutuhan API sistem berkas ke dalam sistem tipe Rust untuk mendeteksi kesalahan saat kompilasi, mengotomatiskan pembersihan sumber daya, dan mengurangi kerentanan terkait memori
  • Contoh iget_locked() menunjukkan arah di mana get_or_create_inode() di Rust berupaya memaksa pemeriksaan null, pembedaan status inode, dan penanganan kegagalan yang sebelumnya ditangani langsung oleh pemanggil C melalui tipe dan pembersihan otomatis
  • Dave Chinner, Christian Brauner, James Bottomley, Ted Ts'o, dan lainnya mengkhawatirkan ketidaksesuaian nama antara API C dan Rust, sinkronisasi API, perbedaan siklus hidup objek, serta beban pemeliharaan dengan mempertimbangkan lebih dari 50 sistem berkas
  • Inti konfliknya bukan pada keunggulan abstraksi Rust itu sendiri, melainkan siapa yang akan menanggung beban untuk menyesuaikan binding dan abstraksi Rust ketika kode C terus berubah

Sesi Rust untuk sistem berkas di LSFMM+BPF

  • Pada Linux Storage, Filesystem, Memory Management, and BPF Summit 2024, Wedson Almeida Filho dan Kent Overstreet membahas cara menggunakan Rust pada sistem berkas Linux
  • Almeida mengunggah rangkaian patch RFC abstraksi Rust untuk sistem berkas pada Desember 2023, dan ada perbedaan pendapat seputar pendekatan ini
  • Pada hari yang sama di pertengahan Mei saat sesi berlangsung, Almeida mengunggah versi patch RFC kedua untuk didiskusikan bersama topik Rust lainnya

Tujuan abstraksi sistem berkas di Rust-for-Linux

  • Abstraksi sistem berkas yang diusulkan mencerminkan arah yang dikejar oleh proyek Rust-for-Linux
  • Intinya adalah mengekspresikan lebih banyak kebutuhan API sistem berkas ke dalam sistem tipe Rust agar kesalahan bisa ditangkap pada waktu kompilasi
  • Juga ingin mengotomatiskan hal-hal yang sulit disediakan dengan mudah dalam kode C
    • Contoh: pembersihan sumber daya
  • Tujuannya adalah membuat pengalaman pengembangan sistem berkas lebih produktif, mengurangi waktu debugging untuk masalah yang bisa ditemukan compiler, dan menurunkan kerentanan terkait memori
  • Overstreet mengatakan ia terlalu sering mengalami pelacakan bug selama dua minggu di bcachefs, dan menilai Rust menawarkan lebih banyak daripada C
    • Rust menghilangkan undefined behavior
    • Rust menyediakan kemampuan untuk melihat apa yang terjadi di dalam kode
    • Jika kebenaran kode Rust dapat dibuktikan, ia memperkirakan bug yang menghambat pengembangan fitur akan jauh berkurang

Contoh sistem tipe seputar iget_locked()

  • Almeida memberi contoh dalam slide bahwa iget_locked() di kernel saat ini memiliki kebutuhan yang kompleks
  • Pemanggil C harus menangani sendiri berbagai kondisi
    • Harus memeriksa apakah nilai kembalian null
    • Harus memeriksa apakah struct inode yang dikembalikan adalah inode baru atau inode yang sudah ada
    • Jika inode baru, harus diinisialisasi sebelum digunakan
    • Jika inisialisasi gagal, harus memanggil iget_failed()
  • Al Viro tidak setuju dengan sebagian kebutuhan pemanggil iget_locked() yang ada di slide Almeida, dan perdebatan berlanjut mengenai detail perilakunya
  • Overstreet menilai bahwa jika aturan semacam ini dikapsulkan ke dalam tipe dan abstraksi Rust, compiler dapat memaksa penanganan yang benar
  • Fungsi padanan di sisi Rust yang diajukan Almeida adalah get_or_create_inode()
    • Seperti di C, kegagalan tetap harus diperiksa
    • Jika berhasil, pemanggil akan menerima inode dengan reference count biasa atau inode baru
    • Untuk inode biasa, reference count akan berkurang secara otomatis saat objek tidak lagi direferensikan
    • Untuk inode baru, jika tidak diinisialisasi maka penanganan setara iget_failed() akan dipanggil secara otomatis
    • Setelah inode baru diinisialisasi satu kali, ia menjadi inode biasa, dan setelah itu pengurangan reference count otomatis akan berlaku
    • Perilaku-perilaku ini dipaksakan oleh sistem tipe
  • Viro mempertanyakan di mana tepatnya batasan-batasan ini akan didefinisikan dalam kode sumber nyata
  • Almeida menjawab bahwa setelah memahami batasan dari Viro dan pengembang sistem berkas lain, ia ingin membuat tipe dan abstraksi yang memaksakan batasan tersebut

Kesenjangan antara API C dan API Rust

  • Dave Chinner menilai bahwa jika nama API C dan API Rust berbeda, pengembang lama akan sulit mengetahui padanan pemanggilan Rust hanya dengan melihat kode C
  • Muncul juga kekhawatiran bahwa jika tidak menggunakan nama yang sama, API tersebut bisa menjadi benar-benar asing bagi komunitas pengembang yang ada
  • Karena kode C akan berubah, kode Rust juga harus mengikutinya, sehingga pertanyaan tentang siapa yang akan menangani pekerjaan itu tetap ada
  • Almeida mengakui bahwa ini adalah hal yang perlu didiskusikan
    • Ia tidak menentang penggantian nama
    • Namun ia juga tidak menganggap iget_locked() sebagai nama yang baik, dan mengatakan ini bisa dilihat sebagai kesempatan untuk membuat nama yang lebih baik
  • Viro menilai pemilihan contoh kurang tepat karena iget_locked() bukan metode anggota objek superblock, melainkan fungsi library
  • Almeida menjawab bahwa get_or_create_inode() juga bisa diubah menjadi fungsi library, dan contoh itu dimaksudkan untuk menunjukkan cara mengenkodekan batasan ke dalam tipe

Pilihan antara abstraksi umum dan pendekatan yang berpusat pada sistem berkas sederhana

  • Christian Brauner menilai bahwa pertama-tama harus diputuskan apakah abstraksi Rust ini adalah abstraksi umum untuk semua sistem berkas kernel, atau berfokus pada fungsi yang diperlukan untuk sistem berkas yang lebih sederhana dan ditulis dalam Rust
  • Dalam jangka panjang, jika fungsi seperti get_or_create_inode() memuat jauh lebih banyak batasan daripada iget_locked(), hal itu bisa menimbulkan masalah
  • Kode C, terutama pada awalnya, bisa berevolusi lebih cepat daripada kode Rust, sehingga kedua API harus terus disinkronkan
  • Overstreet melihat inti persoalannya adalah apakah penambahan abstraksi Rust akan disertai refactoring dan perapian, dan ia sangat yakin itu perlu
  • James Bottomley menilai bahwa siklus hidup objek dienkodekan dalam API Rust, tetapi tidak ada representasi yang setara di C
    • Jika siklus hidup objek berubah di satu sisi, bug bisa muncul di sisi lain
  • Chinner mengatakan bahwa siklus hidup objek inode kadang berbeda menurut sistem berkas
    • Jika satu pemahaman tunggal tentang siklus hidup dimasukkan ke API, fungsi-fungsi itu mungkin tidak akan bekerja pada beberapa sistem berkas
  • Almeida menjawab bahwa contoh tersebut hanya akan digunakan pada sistem berkas yang saat ini memanggil iget_locked() dan bisa memperoleh manfaat darinya
    • Pengembang Rust tidak sedang berusaha memaksa sistem berkas mengubah cara kerjanya saat ini

“Siapa yang akan menanggung beban”

  • Ted Ts'o mengatakan bahwa tampaknya ada upaya untuk mengonversi semua orang ke “agama” Rust, tetapi Linux memiliki lebih dari 50 sistem berkas dan transisi itu tidak akan terjadi seketika
  • Kode C akan terus ditingkatkan, dan jika perubahan itu merusak binding Rust, sistem berkas yang bergantung pada binding tersebut juga bisa rusak
  • Ts'o menilai bahwa untuk sementara binding Rust adalah warga kelas dua, dan binding Rust yang rusak adalah masalah pengembang Rust-for-Linux, bukan masalah seluruh komunitas sistem berkas
  • Ia menilai bahwa dalam 1–2 tahun ke depan akan terlihat apakah pendekatan mengembangkan binding Rust sambil membiarkan evolusi kode C berjalan paralel, serta memasukkan banyak makna ke sistem tipe, adalah pendekatan yang baik atau buruk
  • Bagi Ts'o, perubahan besar pada akhirnya adalah soal pembagian beban
    • Pengembang yang mengubah API C mungkin akan memperbaiki kode C yang terdampak, tetapi karena tidak memahami Rust, mereka bisa saja mengatakan tidak akan memperbaiki binding Rust
  • Almeida menjawab bahwa ia tidak berusaha membekukan API C, melainkan ingin mengenkodekan ke Rust makna yang dijelaskan oleh pengembang sistem berkas tentang API tersebut
  • Bottomley menilai bahwa semakin banyak makna dienkodekan ke binding, semakin rentan binding itu dari sudut pandang sinkronisasi
  • Almeida menjawab bahwa jika API berubah, pengguna API memang harus diperbarui, sama seperti pengguna lainnya

Apa yang harus dimasukkan ke metode, fungsi, dan tipe

  • Viro kembali mempersoalkan bahwa pengganti iget_locked() bergantung pada metode
    • Ia menilai bahwa dengan metode, argumen tidak ditentukan secara eksplisit
  • Overstreet menilai bahwa keluhan terhadap metode berasal dari bahasa seperti C++ yang terlalu bergantung pada pewarisan
    • Rust tidak demikian, dan menurutnya metode di Rust pada dasarnya adalah unsur sintaksis
  • Jan Kara membedakan antara perilaku yang mengikuti inode itu sendiri dan perilaku yang melekat pada fungsi iget_locked()
    • Inode memiliki perilaku seperti reference count dan penanganannya
    • Fungsi iget_locked() memiliki perilaku terpisah yang melekat padanya
  • Overstreet dan Almeida menjawab bahwa kedua bagian itu sama-sama dienkodekan dalam tipe, tetapi tetap dipisahkan, dan fungsi lain yang menggunakan tipe inode dapat memiliki nilai kembalian dengan sifat berbeda
  • Viro menjelaskan mengapa inode di VFS bekerja dengan cara seperti sekarang, dan setuju untuk memulai dari hal kecil lalu melihat arah perkembangannya
  • Overstreet mengatakan bahwa contoh kali ini mungkin terlalu kompleks sehingga kurang cocok sebagai titik awal, dan Viro menjawab, “tidak, bukan begitu,” menutup sesi tersebut

1 komentar

 
GN⁺ 2024-07-16
Opini Hacker News
  • Sulit dipahami bahwa tiap sistem berkas memiliki siklus hidup inode kustom, tetapi tetap memakai fungsi manajemen siklus hidup yang sama dan hanya semantiknya yang berbeda
    Jika fungsi yang sama harus digunakan secara berbeda tergantung detail implementasi, itu terdengar seperti kebalikan dari lapisan abstraksi
    Jika siklus hidup inode berbeda untuk tiap sistem berkas, seharusnya dikelola dengan fungsi per sistem berkas

    • Saya juga punya pertanyaan yang sama, dan tampaknya mereka berusaha memahami atau mendokumentasikan semua C API untuk pekerjaan Rust
      Saat mengumpulkan informasi semacam itu, titik-titik yang bisa direfaktor agar pertanyaan seperti ini tidak muncul sejak awal bisa terlihat, dan itu hal yang baik
    • Jika ini materi yang baru pertama kali dilihat, https://www.kernel.org/doc/html/latest/filesystems/vfs.html bisa membantu
      Ini adalah ringkasan lapisan VFS yang mempertahankan antarmuka konsisten di sisi kernel sambil menangani perilaku khusus tiap sistem berkas
    • Pemahaman saya, bagian yang bisa digeneralisasi diabstraksikan semaksimal mungkin di lapisan VFS, sedangkan pengecualian yang tidak cocok ditangani di lapisan per sistem berkas
      Siklus hidup inode mungkin hanya contoh awal untuk memulai diskusi
    • Sepertinya mereka ingin membuat kompiler bekerja dengan cara melacak masa hidup inode
      Kompiler membantu referensi sementara, tetapi sistem berkas tetap harus menyimpan jumlah tautan di disk
    • Ada beberapa fungsi yang bisa dipakai untuk membuat inode dan memasukkannya ke cache, dan iget_locked() yang menjadi fokus di sini adalah salah satu pola tertentu
      Tidak semua sistem berkas menggunakan cara itu, dan dalam situasi tertentu juga tidak digunakan
      Misalnya, FAT tidak menggunakannya karena membuat nomor inode dan mempertahankan pemetaan sendiri dari lokasi FAT ke inode
      Ada juga sistem berkas seperti proc yang tidak menyimpan objek inode di cache
      Objek inode itu sendiri tampaknya memiliki alur status yang sama dari mana pun asalnya, jadi dari sudut pandang konsumen, cara menggunakan inode tidak berubah
      Yang berubah adalah cara lapisan sistem berkas membuat dan menangani objek inode secara internal
  • Saya bertanya-tanya apakah pertanyaannya justru keliru
    Apakah Rust harus diubah agar lebih mudah memanggil C?
    Saya sudah sedikit mencoba Rust, tetapi dari sudut pandang developer hobi, masih belum jelas bagaimana harus berinteroperasi dengan C
    Sebaliknya, di C++ atau Objective C, cukup menyertakan header yang benar dan memanggil fungsi
    Swift bisa menyertakan file Objective C, lalu dari sana bisa memanggil C
    Dalam kasus ini, alih-alih mengharapkan developer kernel menyesuaikan diri dengan bahasa, bukankah bahasa Rust sendiri seharusnya menjadi sedikit lebih fleksibel?

    • Memanggil C dari Rust cukup sederhana
      Cukup deklarasikan fungsi eksternal lalu panggil
      Misalnya, seperti yang ditunjukkan di Rust book https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#usin..., fungsi bisa dideklarasikan dengan extern "C"
      Jika tidak ingin menulis semua deklarasi secara manual untuk library yang kompleks, bisa memakai alat seperti bindgen yang otomatis menghasilkan deklarasi extern dari file header C: https://github.com/rust-lang/rust-bindgen
      Bisa saja berargumen bahwa akan bagus jika sesuatu seperti bindgen disertakan dalam Rust sehingga bisa dipakai tanpa dependensi pihak ketiga atau konfigurasi build.rs, tetapi inti tulisan ini bukan itu
      Masalahnya bukan binding level rendah, melainkan wrapper level tinggi yang idiomatis Rust, dan tidak mungkin ada alat umum yang otomatis membuat wrapper seperti itu dari sembarang kode C
    • Ini bukan kesulitan penting dalam Rust dan juga tidak terkait dengan topik tulisan
      Tulisan itu membahas cara benar-benar mengimplementasikan driver filesystem kernel dan semacamnya dengan Rust
      Penting juga bahwa kode Rust di dalam kernel niscaya mengonsumsi antarmuka C
      Untuk use case yang saya bayangkan, bindgen cukup cocok: https://github.com/rust-lang/rust-bindgen
    • Dalam praktiknya cukup mudah
      Untuk memanggil dari Rust, deklarasikan extern "C" fn foo() -> T, lalu lewatkan flag linking dengan atribut #[link] atau build.rs
      Binding bisa dibuat lebih dulu dengan crate bindgen, atau dibuat di build.rs lalu disertakan dengan include!()
      Biasanya dibuat crate -sys yang hanya berisi binding hasil generasi, lalu kode sebenarnya melakukan use pada binding dari crate sys itu seperti biasa
      Di C++ dan Objective C pun, bukan hanya perlu menyertakan header yang benar, tetapi juga harus melakukan link ke library
    • Intinya adalah Rust dapat memodelkan invarian yang tidak bisa diekspresikan dengan C
      Pemanggilan dua arah memang mungkin, tetapi jika C tidak bisa mengekspresikan apa yang dapat diekspresikan Rust, itu berdampak penting pada desain API yang harus dipakai bersama oleh kedua sisi
    • Pemanggilan C sudah sangat sederhana, jadi Rust tidak perlu diubah agar lebih mudah
      Deklarasikan fungsi C dengan extern "C" lalu panggil
      Biasanya perlu unsafe dan harus mengubah referensi menjadi raw pointer atau melakukan casting, tetapi sintaksnya sendiri sederhana
      Ada juga alat yang memindai file header C dan membuat deklarasi, dan bindgen adalah yang paling banyak dipakai
      Perdebatan dalam tulisan ini lebih dekat ke bagaimana Rust digunakan, bukan bahasa itu sendiri
      Developer Rust-for-Linux ingin memakai fitur dan type system Rust untuk mengenkode semantik pemanggilan API agar lebih aman dan lebih minim kesalahan
      Orang-orang di sisi C khawatir bahwa hal itu akan membuat perilaku dan semantik C API lebih sulit berevolusi
      Karena saat C API berubah, Rust API juga harus diperbaiki, dan mereka tidak ingin menanggung pekerjaan itu
      Alternatif yang lebih mudah diterima adalah memakai lebih sedikit fitur dan type system Rust untuk mengenkode semantik dalam Rust API
      Dengan begitu, saat C API berubah, pembaruan Rust API menjadi mekanis dan sederhana, tetapi jika Rust-for-Linux tidak bisa menggunakan fitur Rust untuk membuat API yang lebih baik dan aman, muncul pertanyaan apa makna dari pekerjaan ini
      Namun agak aneh berbicara secara definitif tentang topik ini sambil mengakui bahwa ia tidak cukup memahami bahasanya
  • Saya tidak begitu paham filesystem Linux, jadi tidak jelas apakah Rust API ini membungkus C API atau mengimplementasikannya ulang
    Jika itu implementasi ulang atau API terpisah, mempertahankan nama yang sama dengan C API tampaknya akan makin membingungkan seiring waktu
    Menurut saya begitu, meski pada awalnya mungkin membantu developer yang sudah familier memahami lebih cepat

    • Almeida menunjukkan padanan iget_locked() di Rust, dan namanya adalah get_or_create_inode()
      Jawabannya tampaknya itu adalah implementasi ulang, dan tidak memakai nama yang sama
  • Mengingat bagaimana diskusi seperti ini biasanya berjalan dan skala perubahannya, diskusi kali ini secara mengejutkan cukup sopan
    Saya tidak setuju dengan nuansa negatif di thread ini
    Saya cukup optimistis karena para pihak terkait menyampaikan titik-titik masalah utama dengan jelas tanpa omong kosong

    • Lebih daripada isinya, saya jadi terus membaca karena penyusunan catatannya yang sangat bagus
      Diskusi sebenarnya kemungkinan panas, berantakan, dan penuh cari-cari celah, layaknya debat bahasa pemrograman di antara para geek yang berpendapat kuat
      Jake Edge, yang menulis ringkasan ini, tampaknya sangat hebat dalam menyingkirkan bagian-bagian seperti itu dan hanya menuliskan intinya
  • Sebagian komentar di bawah halaman lwn.net cukup tidak sopan
    Bayangkan saja menerima komentar seperti Science advances one funeral at a time pada proyek open source yang sedang Anda kontribusikan

  • Selalu menguntungkan jika kernel Linux punya lebih banyak pilihan
    Namun Rust mungkin bukan jawaban untuk semuanya
    Rust berupaya sebaik mungkin menjamin model pemrograman yang aman, tetapi model itu pun punya batas
    Bisa saja terlihat seperti: kalau masalahnya memori, pakai Rust; kalau masalahnya konkurensi, ganti ke Rust. Namun tanpa blok unsafe, Rust tidak bisa melakukan semua hal yang dilakukan C
    Rust bisa memberi sudut pandang baru terhadap masalah-masalah ini, tetapi bukan solusi yang sepenuhnya tuntas

    • Keunggulan besar Rust dalam pekerjaan ini adalah sikapnya yang aktif untuk mengenkapsulasi masalah keselamatan semacam itu ke dalam tipe, dan tulisan ini memang membahas hal tersebut
      C, terutama C yang dipakai di kernel, melemparkan tanggung jawab kepada masing-masing orang untuk sepenuhnya memahami semua aturan implisit
      Itu tidak bisa diskalakan
      Para pengembang kernel yang memakai struktur data yang sama pun, meski berkumpul dalam satu ruangan, tidak bisa sepenuhnya sepakat soal aturan-aturan itu
      Rust kuat dalam menampakkan aturan yang perlu diketahui, dan jika orang lain bisa menjamin kepatuhan terhadap aturan tersebut, menjadikannya bukan lagi masalah kita
      Kadang hasilnya bisa kurang optimal, tetapi di kernel Linux pun default yang kurang optimal sering kali merupakan pilihan yang tepat; bagi mereka yang punya waktu mempelajari enam aturan aneh tambahan demi performa lebih baik, cukup sediakan jalan keluar berupa unsafe
    • Blok unsafe bisa digunakan
      Hanya saja harus dipakai hanya saat diperlukan
      Memakai blok unsafe dengan cakupan dampak yang sangat terbatas tidak berarti semua jaminan yang diperoleh dari sisa kode ikut hilang
    • Benar bahwa pekerjaan tingkat rendah membutuhkan kode unsafe
      Namun anggapan bahwa karena harus memakai unsafe, Rust jadi tidak cocok, adalah salah paham
      Pemisahan aman/tidak aman di Rust bertujuan menandai dengan jelas bagian mana dari kode yang tidak aman, sehingga audit dapat difokuskan pada bagian kecil itu, dan jika bagian tersebut benar, sisa kode dapat dipercaya akan berjalan
    • Saya penasaran, dari semua ini, seberapa banyak bagian yang benar-benar 100% jelas diperlukan
      Apakah ada alasan kuat mengapa kode filesystem harus selalu unsafe?
      Mungkin hanya subset yang sangat kecil yang diperlukan di beberapa tempat
    • Saya memang menyukai Rust karena ada saat-saat pemahamannya terasa sangat pas, tetapi di sisi async rasanya masih banyak bagian yang kasar
      Tidak intuitif apa yang sebenarnya terjadi di dalamnya
  • Jika melihat notulen rapat, Rust di dalam kernel tampak seperti biaya kompleksitas tambahan
    Jika menulis ulang sistem operasi dari nol, kekuatan bahasa bisa dimanfaatkan sepenuhnya
    Namun jika ditempelkan di samping codebase raksasa yang sudah ada, muncul masalah tambahan seperti yang terlihat di sini

    • Benar, tetapi biaya itu seharusnya diimbangi oleh pengembangan driver yang lebih mudah
      Lihat blog tentang driver GPU Rust Asahi Linux yang dibuat dalam satu bulan
      Cukup cari tales of the m1 gpu di Google, dan penulisnya punya pandangan yang sangat negatif terhadap Hacker News
      Kalau mau, bisa dibaca lewat tautan ini: https://asahilinux.org/2022/11/tales-of-the-m1-gpu/
      Apakah ini bisa diterapkan secara umum masih harus dilihat dalam beberapa tahun ke depan
    • Kuat sekali kesannya bahwa demi mengejar kesempurnaan, kita malah melewatkan hal yang baik
    • Saya setuju dengan keunggulan Rust, tetapi menurut saya sulit bagi nalar untuk mengalahkan hype
      Biaya itu akan dianggap perlu demi menerima masa depan dan kemajuan
      Saya penasaran mengapa tidak membatasi diri pada subset yang aman, alih-alih terjun ke arus besar yang penuh bug tak dikenal dan kompromi
    • Kalau bicara kode tambahan, bisa juga dikatakan bahwa apa pun, bukan hanya Rust, memperkenalkan kompleksitas
      Fakta bahwa semuanya sudah terlalu besar bukan berarti inovasi harus dihentikan dan masuk ke mode pemeliharaan tanpa batas
      Seperti pajak di dunia nyata, jika biaya di satu sisi dipakai untuk mengimbangi masalah lain, itu belum tentu kerugian bersih
      Mengatakan bahwa tidak akan ada masalah apa pun yang terimbangi hanya dengan melihat satu diskusi yang belum menghasilkan kesimpulan terasa seperti argumen yang pendek
  • Bagian tentang nama C API dan Rust API yang tidak selaras sehingga orang tidak bisa mengetahui pemanggilan Rust yang setara hanya dengan melihat kode C tampak seperti pertarungan melawan konvensi penamaan lama
    Ada kasus yang berjalan baik dengan mempertahankan nama yang sama, lalu ketika menginginkan nama alternatif, nama baru itu membungkus nama lama
    Meski begitu, penamaan memang sulit

    • Ini salah satu dari dua masalah besar dalam ilmu komputer
      Dua lainnya adalah konkurensi dan kesalahan off-by-one