- Ante, referans sayımının esnekliği ile ödünç denetiminin güvenliğini birlikte kullanırken Rust tarzı çalışma zamanı panic’lerinden veya Swift tarzı münhasır erişim denetimi ek yükünden kaçınmayı amaçlayan bir sistem dili tasarımıdır
- Temel mekanizmalar shape-stability ve temporary uniq conversion’dır; bunlar referans sayımlı değerlerin alanları üzerinde güvenli biçimde değiştirilebilir ödünçler oluşturmayı ve union içindeki değerleri yalnızca sınırlı kapsamda
uniqolarak ele almayı sağlar - Rust’taki
Rc<RefCell<T>>yanlış kullanıldığında çalışma zamanında panic üretebilir ve Swift’in borrowing system’i çalışma zamanında münhasır erişim denetimleri içerir; Ante ise bazı durumları derleme zamanı kurallarıyla ele almaya çalışır - Hâlâ kısmen uygulanmış bir work-in-progress tasarımdır ve belirli bir nesneye türleri özyinelemeli olarak analiz ederek ulaşılıp ulaşılamayacağını belirlemek gerektiğinden, alan eklemek breaking API change olabilir
- Bu yaklaşım, shared mutable borrowing’in her zaman imkânsız olduğu varsayımını zayıflatıyor ve Vale, group borrowing, Rust GhostCell gibi tekniklerle birlikte bellek güvenliği tasarımındaki istisna alanını genişletiyor
Ante’nin hedeflediği birleşim
- Ante, bellek güvenliği ve iş parçacığı güvenliği olan daha basit bir Rust olmayı hedefleyen bir sistem programlama dilidir
- Temel model tek sahiplik ve ödünç denetimidir; değerler stack üzerinde ya da onları içeren struct ve array’lerin içinde inline olarak bulunur
- Basitliğe öncelik vermek istendiğinde, türe
sharedanahtar sözcüğü eklenerek referans sayımı seçilebilir shared type Color,shared type RbTree tkullanan red-black treebalancefonksiyonu, Python örneği kadar kısa ve C++ ile Rust örneklerinden daha küçüktür- Asıl ilgi noktası, referans sayımlı veriyi değiştirilebilir olarak ödünç alırken Rust’taki
borrow_mut()panic riski veya Swift’teki çalışma zamanı münhasır erişim denetimleri olmadan bunun nasıl yapılacağıdır - Ante hâlâ work-in-progress durumundadır; bazı kısımları uygulanmıştır, bazıları teoriktir ve tasarım hâlâ değişmektedir
- İlerleme durumu Ante sitesi ve Discord üzerinden takip edilebilir
shape-stability ve birden çok değiştirilebilir referans
- Ante’deki shape-stability, “kararlı şekle sahip bir hedefe verilen referans, başka yerde hangi değişiklik olursa olsun her zaman geçerlidir” fikridir
- Bu kavram sayesinde aynı struct için aynı anda birden fazla değiştirilebilir ödünç referansa sahip olunabilir
heal (healer: mut Entity) (target: mut Entity)örneğinde, aynıEntity’yi iki argüman olarak geçirip kendini iyileştirenself_healçağrısı yapılabilirhealeriletargetaynıEntity’yi gösterse bile, bu koddaEntityyok edilemeyeceği için iki referans da geçerliliğini korur
- Struct’ın kendisine, alanlarına ve alanların alanlarına yönelik değiştirilebilir referanslar da aynı anda izinli olabilir
ship: mut Spaceshipileengine_alias: mut Engine = ship.engineaynı anda kullanılsa bile, fonksiyon çalışırkenshipve içindekiengine’in yok edilmeyeceği kabul edilir
- Rust ve Swift, aynı veriye aynı anda yönelen birden fazla
&mutreferansına izin vermez
Referans sayımlı değerlerin alanlarını değiştirilebilir ödünç almak
- Ante’de tür tanımının önüne
sharedkonursa o tür otomatik olarak referans sayımlı olur shared mut type Spaceshipörneğindelaunch,Rckarşılığı olanSpaceship’i elinde tutarkenmut ship.engineifadesiniset_fuel’e geçirirlaunchkapsayıcı nesne olanSpaceship’i tuttuğu için, onun alanı olanengine’in de yaşadığı sonucuna varılabilir- Genel kural,
shared muttürlerin alanları için her zamanmutödünç referansı oluşturulabilmesidir- Ancak bu, o alanların içindeki tüm hedefler için her zaman değiştirilebilir ödünç oluşturulabileceği anlamına gelmez; ek kurallar gerekir
- Sonraki örneklerde sugar syntax olan
shared mut type Spaceshipyerine daha açıkRc Spaceshipgösterimi kullanılırshared mut type Spaceship,type Spaceshipolur;var ship: Spaceshipisevar ship: Rc Spaceshipanlamına gelir
Union’ların güvenlik sorunu yarattığı nokta
- Union’lar içeriği inline tuttuğu için pointer takibini ve cache miss’leri azaltabilir; bu da hız avantajı sağlar
struct Spaceshipiçindeki C tarzıunion Engine,StringTheoryEngineveImpulseEnginedeğerleriniSpaceshipbelleğinin içinde tutar- Bu, Java’daki interface ve pointer kullanılan yaklaşımla karşılaştırılır
- Sorun, bellek güvenli dillerde union’ları güvenli biçimde desteklemenin zor olmasıdır
Engine’inStringTheoryEngine(str: String)veyaImpulseEngine(fuel: I32)olduğu örnekte,shipileother_shipaynıSpaceship’i gösterdiğinde segfault oluşabilirmatch uniq ship.engineile string’in iç kısmına referans alındıktan sonraother_ship.engine := ImpulseEngine 0x42ile aynı motor başka bir varyanta çevrilir ve ardından- eski
strdeğiştirilirse, kapsayıcı yok edildikten sonra iç kısmını kullanma sorunu doğar
- Bu yüzden Ante, değiştirilebilir ödünç referans bir union’ı gösterdiğinde, onun varyantlarından birinin içine değiştirilebilir ödünç referansı oluşturulmasına izin vermemelidir
- Bu, struct kurallarının tersidir
- Bir struct’a
mutreferansı varsa alanlarınamutreferansları üretilebilir - Bir union’a
mutreferansı varsa varyantın içinemutreferansı üretilemez
- Bir struct’a
uniq ve temporary uniq conversion
uniq, exclusive mutable reference, yani münhasır değiştirilebilir referans anlamına gelir- Bir değişken
uniq Spaceshiptutuyorsa, bu oSpaceshipiçin kullanılabilir tek referanstır- Kavram olarak Rust’taki
&mut Spaceshipe benzer
- Kavram olarak Rust’taki
- Ante, union içini güvenli biçimde ele almak için temporary uniq conversion kullanır
- Temel kural şudur: Belirli bir kapsam boyunca başka olası takma adlı referanslar kullanılmıyorsa geçici olarak
uniqreferansı alınabilirmatch uniq ship.enginebloğundaship.engine,uniqgibi ele alınır- Bu kapsam boyunca derleyici,
Spaceship’i dolaylı olarak içerebilecek diğer mevcut değişkenlerin kullanılmasına izin vermez
- Rust, “başka referanslar bir yerlerde bulunuyor olabilir” diye
uniqvarlığının kendisini engellerken, Ante bu referanslar o kapsamda kullanılmadığı süreceuniqe izin verir - Bu durumda
uniq Spaceship, gerçekte küresel olarak tek referans değil; yalnızca o kapsam içinde kullanılabilen tek referanstır- Bu, C’deki
restrictpointer’ına benzer bir nüans taşır
- Bu, C’deki
İzin verilen ve reddedilen erişimler
match uniq ship.enginekapsamı içindeother_ship: Rc Spaceshiperişimi bir derleme hatası üretmelidir- çünkü
other_ship.engine,ship.engineile alias olabilir ve ship.enginekullanılırkenother_ship.engineüzerinde yapılacak değişiklik drop’a yol açabilir
- çünkü
HasAShipgibiRc Spaceshipalanı olan başka struct’lar da aynı nedenle reddedilir- çünkü
other.ship.enginede dolaylı olarak aynıSpaceship’e ulaşabilir
- çünkü
- Buna karşılık
new_fuel: I32gibi tamsayılar kullanılabilir- çünkü
I32,Spaceshipe referans içeremez
- çünkü
Spaceship’in kendisindefollow_ship: Rc Spaceshipgibi alanlar varsa bu da reddedilir- çünkü bu durumda
uniq Spaceship, kendi iç yolundan tekrar erişilebilir hâle gelir; dolayısıyla genel olarak özyinelemeli türlerdemut -> uniqdönüşümü yapılamaz
- çünkü bu durumda
Fonksiyon çağrıları ve dönüşlerdeki kısıtlar
mut -> uniqdönüşümü fonksiyon çağrılarında da olabilirfoo (var ship: Rc Spaceship) (new_res: Resonator)fonksiyonumaybe_use_resonator ship new_resçağrısı yaptığında, çağrı noktasındashipbiruniq Spaceshipe dönüştürülür- Derleyicinin yalnızca diğer argümanların
Spaceshipreferansı içerebilip içermediğini kontrol etmesi gerekir - Örnekteki
Resonatorböyle bir referans içermediği için buna izin verilir
- Derleyicinin yalnızca diğer argümanların
- Dönüşte, dönüştürülmüş
uniqreferansı normaluniqolarak geri döndürülemez- çünkü dönüşten sonra “bu kapsamda alias olabilecek değişkenler kullanılmıyor” denetimi artık uygulanamaz
- Bunun yerine dönüş tipi
local uniq Fooolarak belirtilebilir- Dahili olarak,
mut reftenuniq refe dönüştürülürken gerçekte her zaman local uniq üretilir - Çoğu durumda normal
uniqgibi kullanılabilir, ancak döndürülürken bunun açıkça belirtilmesi gerekir
- Dahili olarak,
Tasarım maliyetleri ve alternatifler
- Ante,
Rc Spaceshipgibi referans sayımlı referansları çalışma zamanı hatası olmadan geçiciuniq Spaceshipe çevirebilir - Dezavantajı, derleyicinin “
EngineiçindenSpaceship’e ulaşılabilir mi?” gibi soruları yanıtlamak için türleri özyinelemeli olarak incelemek zorunda olmasıdır - Bu tür analizler kırılgan olabilir
- Bir struct’a alan eklemek breaking API change olabilir
- Ante’nin yaratıcısı Jake, bu garantiyi korumanın daha iyi yollarını arıyor
- group borrowing ve Flix references benzeri şekilde, her paylaşımlı değiştirilebilir türe anonim ve benzersiz bir brand type ekleme yaklaşımı
- Paylaşımlı tür değiştiğinde
Mutates 'agibi bir effect ekleyerek tür analizini ortadan kaldırma yaklaşımı - İki referansın farklı nesneleri gösterip göstermediğini kullanıcının çalışma zamanında denetlemesi veya unsafe denetimi safe API ile sarmalama yaklaşımı
- Derleyicinin,
Rciçinde dolaylı saklanmadığı için alias olamayacak değerleri izlemesi yaklaşımı
- Pony’nin iso permission yaklaşımına benzer fikirler ya da struct’ın içini görüp dışarıyı gösteren referansların kullanımını engelleyen geçici izinler de olası seçenekler arasında
- Zor olan nokta, bu esnekliği korurken Ante’nin hedeflediği kullanılabilirlik, okunabilirlik ve basitlik özelliklerini sürdürmektir
Daha geniş bellek güvenliği eğilimi
- shared mutable borrowing, eskiden imkânsız sayılıyordu ve Rust’ın da bu inanç üzerine kurulduğu varsayımı burada arka planda yer alıyor
- Ancak çeşitli istisnalar birikiyor
- Ante, local uniqueness kurallarıyla shared-mutable veriden
uniqödünç referansı elde edebiliyor - Vale, pure function yoluyla shared-mutable veriden değiştirilemez ödünç referansı elde edebiliyor
- group borrowing, shape-stable olmasa bile shared-mutable ödünç referansları oluşturabiliyor
- Rust’ın GhostCell yaklaşımı, nesne grafiklerinin birbirini serbestçe göstermesine izin verirken belirli bir anda bunlardan yalnızca biri için tek bir değiştirilebilir referans tutulmasına izin veriyor
- Ante, local uniqueness kurallarıyla shared-mutable veriden
- Bu eğilim, bellek güvenliği tasarımında shared mutable borrowing’i ele alan daha genel bir ilke olabileceğine işaret ediyor
Rust Cell ile karşılaştırma
- Rust kullanıcıları, struct alanlarına
Cellkoyma yaklaşımı ile Ante’nin yaklaşımı arasındaki farkı sorabilir - Ante örneğinde,
Rc Spaceshipiçindenstatus: Stringalanınamut Stringreferansı alınıp doğrudan" (refueling)"eklenebilir - Rust’taki
Cell<String>yaklaşımındaRc<Spaceship>içinden&mut Stringalınamaz- Bunun yerine
status_ref.replace(String::new())ile geçici varsayılan değer konur - Çıkarılan
Stringdeğiştirilir ve - Son olarak
replace(status)ile geri konur
- Bunun yerine
- Bu yaklaşımın bazı dezavantajları vardır
""gibi bir varsayılan örnek oluşturmak gerekir- Son
replaceçağrısını unutma riski vardır - Değer değiştirilmiş durumdayken bir başkasının
statusalanını okuma riski vardır
- Ante, geçici olarak
statusstring’ine referans alınmasına izin verir ve bu sırada başka kodların erişimini derleyici zorunlu olarak engeller
1 yorum
Lobste.rs yorumları
“Paylaşılan değiştirilebilir ödünç alma”nın imkânsız sayılması, Rust’ın hedefine ulaşmak için katlandığı basit bir fedakârlık değil; Rust’ın temel hedefinin kendisine oldukça yakın bir şey
Çünkü paylaşılan değiştirilebilir durum, kod hakkında yerel akıl yürütmeyi zorlaştırır
withoutboats tarafından yazılan "References are like jumps" bu noktayı iyi ele alıyor. Alias’ı olan durumun kazara değiştirilmesini engellemenin, doğru çalışan sistemler kurmayı kolaylaştırmanın anahtarı olduğu; Rust’ın yaşam süresi kurallarının ise yalnızca çöp toplamadan kaçınmaya yarayan bir mekanizma değil, değiştirilebilir durum ile alias’lı durumu birlikte kabul eden bir dilde akıl yürütülebilirliği sağlayan daha derin bir yapı olduğu savunuluyor
Oldukça iyi görünüyor
Doğru anladıysam, paylaşılan referanstan değiştirilebilir referansa geçişteki sihir, iş parçacıkları arasında paylaşılmayan tiplerle sınırlı olduğu için mümkün;
Rc’nin benzersizliği de aynı tipteki tüm nesneleri aynı yaşam süresiyle ödünç alınmış gibi ele alarak garanti ediliyor gibiAçık söz dizimi mi doğal söz dizimi mi daha iyi, bu bir zevk meselesi olabilir; ancak derleyicinin
Cellhakkında daha fazla şey bilmesi durumunda ona yönelik değiştirilebilir referanslara daha esnek biçimde izin verebileceğini gösteriyorAyrıca Rust’ta
mutun değiştirilebilir değil dışlayıcı/benzersiz anlamına geliyormuş gibi kullanılmasından doğan kafa karıştırıcı terminolojiden de kaçınıyoruniqyükseltmesi kilit edinme anlamına mı geliyor?” gibi bir soruydu; ama karşılaştırılan şeyinArcdeğilRcolduğu anlamına geldiğini anlıyorummutun dışlayıcı/benzersiz anlamına geldiği kısmı biraz daha açıklayabilir misin?Son kısımda ima edilen birleştirici ilkenin ne olabileceğine dair tahmini olan var mı, merak ediyorum
antelang.org blog yazılarına ilişkin önceki tartışmalar da bakmaya değer
Bunun nasıl çalıştığını pek anlayamadım. “Bir nesneye yönelik değiştirilebilir bir işaretçiniz varsa, o nesnenin bir dilimine yönelik değiştirilebilir bir referans elde edebilirsiniz” demek gibi görünüyor
Ama öyleyse örneğin
mutref someobjext = …,mutref subfield = someobjext.a.b,someobjext.a = somethingelsegibi bir şey mümkün görünüyor; bu durumdasubfieldgeçersiz hâle gelebilir ya da değeri değişip bozulabilirYazıda açıklama, başka dillerle karşılaştırma ve kod örneği çoktu; ancak bu davranışın adım adım semantiğini temel düzeyde düzenli biçimde anlatan kısmı bulmakta zorlandım