Ruby yaratıcısı neden Semboller kavramını kullanmayı seçti?


15

tl; dr: Sembollerin dile özgü olmayan bir tanımı ve diğer dillerde bulunması için bir sebep var mı?

Peki, Ruby yaratıcısı neden symbolsdilde kavramını kullandı ?

Bunu yakut olmayan bir programcı açısından soruyorum. Birçok başka dil öğrendim ve bunların hiçbirinde Ruby'nin dediği şeyle ilgilenip ilgilenmediğimi belirtmem gerek symbols.

Ana soru, symbolsRuby'deki kavramı performans için var mı, yoksa sadece dilin yazılma şekli nedeniyle gerekli olan bir şey mi?

Ruby'deki bir program, Python veya Javascript muadili olandan daha hafif ve / veya daha hızlı olur mu? Eğer öyleyse, bunun nedeni olabilir symbolsmi?

Ruby'nin amacından biri insanlar için okunması ve yazılması kolay olduğundan, yaratıcılarının, bu geliştirmeleri tercümanın kendisinde (diğer dillerde olduğu gibi) uygulayarak kodlama sürecini kolaylaştıramaz mı?

Görünüşe göre herkes sadece neyin symbolsnasıl ve nasıl kullanılacağını bilmek istiyor , neden orada olduklarını değil.


Scala'nın kafamın üstünde semboller var. Bence birçok Lisps yapıyor.
D. Ben Knoble

Yanıtlar:


17

Ruby'nin yaratıcısı Yukihiro "Matz" Matsumoto, Ruby'nin Lisp, Smalltalk, Perl'den nasıl etkilendiğine dair bir açıklama yayınladı (ve Wikipedia Ada ve Eiffel'i de söylüyor):

Ruby, aşağıdaki adımlarda tasarlanmış bir dildir:

  • basit lisp dili al (CL'den önceki gibi).
  • makroları kaldır, s-ifadesi.
  • basit nesne sistemi ekleyin (CLOS'tan çok daha basit).
  • daha üst düzey işlevlerden esinlenerek bloklar ekleyin.
  • Smalltalk içinde bulunan yöntemleri ekleyin.
  • Perl'de bulunan işlevselliği ekleyin (OO yolunda).

Yani, Ruby teoride aslında bir Lisp'ti.

Bundan böyle MatzLisp diyelim. ;-)

Herhangi bir derleyicide, işlevler, değişkenler, adlandırılmış bloklar, türler vb. İçin tanımlayıcıları yöneteceksiniz. Genellikle bunları derleyicide saklar ve hata ayıklama bilgileri eklemeniz dışında üretilen yürütülebilir dosyada unutursunuz.

Lisp'de bu tür semboller, farklı paketlerde barındırılan birinci sınıf kaynaklardır, bu da çalışma zamanında yeni semboller ekleyebileceğiniz, bunları farklı tür nesnelere bağlayabileceğiniz anlamına gelir. Bu, meta programlama sırasında kullanışlıdır, çünkü kodun diğer bölümleriyle adlandırma çakışmaları olmayacağından emin olabilirsiniz.

Ayrıca, semboller okuma zamanında staj yapar ve yeni tür değerlere (sayılar gibi, ancak soyut) sahip olmanın etkili bir yolu olan kimlik ile karşılaştırılabilir . Bu, tamsayıların desteklediği kendi numaralandırma türlerinizi tanımlamak yerine doğrudan sembolik değerleri kullandığınız kod yazmanıza yardımcı olur. Ayrıca, her sembol ek veri tutabilir. Örneğin Emacs / Slime, Emacs'tan meta verileri doğrudan bir sembolün özellik listesine ekleyebilir.

Sembol kavramı Lisp'te merkezidir. Ayrıntılı örnekler için örneğin PAIP'e (Yapay Zeka Programlama Paradigmaları: Common Lisp, Norvig'de Örnek Olaylar) bir göz atın .


5
İyi cevap. Ancak Matz'a katılmıyorum: Makrolar olmadan lisp lehçesi olmadan bir dil çağırmayı asla düşünmezdim. Lisp'in çalışma zamanı metaprogramlama olanakları tam olarak bu dile muhteşem gücünü veren şeydir ve uçsuz bucaksız, ifade edici gramerini telafi eder.
cmaster - eski haline monica

11

Peki, Ruby içerik oluşturucuları neden symbolsdilde kavramını kullanmak zorunda kaldı ?

Tamamen “yapmak zorunda değiller”, seçtiler. Ayrıca, kesinlikle konuşmanın Symboldilin bir parçası olmadığını, çekirdek kütüphanenin bir parçası olduğunu unutmayın . Onlar do dil düzeyinde değişmez sözdizimini var, ancak arayarak bunları inşa etmek olsaydı onlar sadece de çalışmak Symbol::new.

Bunu anlamaya çalışan yakut olmayan bir programcının bakış açısından soruyorum. Başka birçok dil öğrendim ve hiçbirinde Ruby'nin dediği şeyle ilgilenip ilgilenmediğimi belirtmem gerekmedi symbols.

Bu "diğer birçok dillerin" ne olduğunu söylemediniz, ama işte SymbolRuby'nin veri tipine sahip küçük bir dil alıntısı :

Ayrıca Symbols'nin özelliklerini farklı bir biçimde sağlayan başka diller de vardır . Örneğin Java'da Ruby'nin özelliklerinin özellikleri Stringiki (aslında üç) türe ayrılır: Stringve StringBuilder/ StringBuffer. Öte yandan, Ruby'nin özellikleri Symboltürü Java içine katlanır Stringtip: Java Stringler edilebilir enterne , edebi dizeleri ve Stringdeğerlendirilir sabit ifadeler otomatik olarak enterne edilmiştir derleme zamanında sonucudur ler, dinamik olarak oluşturulmuş Stringler arayarak staj edilebilir String.internyöntemi. StringJava'da bir stajyer , SymbolRuby'de olduğu gibi , ancak ayrı bir tür olarak uygulanmaz, bir Java'nınString(Not: Ruby'nin önceki sürümlerinde, önceden String#to_symçağrılmıştı String#internve bu yöntem bugün eski bir takma ad olarak varlığını sürdürüyor.)

Ana soru şu olabilir: symbolsRuby'deki kavram, kendisi ve diğer diller üzerinde bir performans niyeti olarak var mı ,

Symbols her şeyden önce belirli semantiğe sahip bir veri tipidir . Bu semantik ayrıca bazı performans işlemlerinin (örneğin hızlı O (1) eşitlik testi) uygulanmasını mümkün kılar, ancak bu temel amaç değildir.

ya da sadece dilin yazılma şekli nedeniyle var olması gereken bir şey mi?

SymbolRuby dilinde hiç gerekli değildir, Ruby onlarsız iyi çalışır. Bunlar tamamen bir kütüphane özelliğidir. D'de Symbols'ye bağlı tam olarak bir yer vardır : bir defyöntem tanımı ifadesi Symbol, tanımlanmakta olan yöntemin adını göstererek değerlendirilir . Ancak, bu oldukça yeni bir değişikliktir, bundan önce dönüş değeri basitçe belirtilmemiş olarak bırakılmıştır. MRG basitçe değerlendirdi nil, Rubinius bir Rubinius::CompiledMethodnesneyi değerlendirdi, vs. Ayrıca bir UnboundMethod… ya da sadece a'yı değerlendirmek de mümkün olacaktır String.

Ruby'deki bir program, Python veya Node muadili olandan daha hafif ve / veya daha hızlı olur mu? Eğer öyleyse, bunun nedeni olabilir symbolsmi?

Burada ne istediğini bilmiyorum. Performans, dil değil, çoğunlukla uygulama kalitesi meselesidir. Ayrıca, Düğüm bir dil bile değil, ECMAScript için olaylı bir G / Ç çerçevesi. IronPython ve MRI'da eşdeğer bir komut dosyası çalıştıran IronPython'un daha hızlı olması muhtemeldir. CPython ve JRuby + Truffle'da eşdeğer bir komut dosyası çalıştıran JRuby + Truffle muhtemelen daha hızlı olacaktır. Bunun Symbols ile ilgisi yok ama uygulamanın kalitesi ile: JRuby + Truffle agresif bir şekilde optimize eden bir derleyiciye ve yüksek performanslı bir JVM'nin tüm optimizasyon makinelerine sahiptir, CPython basit bir yorumlayıcıdır.

Ruby'nin amacından biri insanlar için okunması ve yazılması kolay olduğundan, yaratıcıları bu geliştirmeleri yorumlayıcının kendisinde (diğer dillerde olduğu gibi) uygulayarak kodlama sürecini kolaylaştıramaz mı?

Hayır Symbol. Derleyici optimizasyonu değildir. Belirli semantiğe sahip ayrı bir veri türüdür. YARV'nin s için özel bir iç optimizasyon olan flonumları gibi değiller Float. Durum için aynı değildir Integer, Bignumve Fixnum, hangi olmalıdır görünmez bir özel iç optimizasyon detay, ama ne yazık ki değil. (Bu nihayet hangi kaldırır, Ruby 2.4 sabit olacak Fixnumve Bignumsadece ve yapraklar Integer.)

Java'nın bunu yaptığı gibi, normalin özel bir durumu olarak, bu özel durumda olup olmamaları ve hangi koşullarda otomatik olarak bu özel durumda Stringolup olmadıkları konusunda her zaman dikkatli olmanız gerektiği anlamına gelir String. Bu, ayrı bir veri tipine sahip olmaktan çok daha yüksek bir yüktür.

Sembollerin dile özgü olmayan bir tanımı ve diğer dillerde bulunması için bir neden var mı?

Symbolad veya etiket kavramını gösteren bir veri türüdür . Symbols değer nesneleridir , değişmezdir, genellikle derhal (dil böyle bir şeyi ayırt ederse), vatansızdır ve kimliği yoktur. SymbolEşit olan iki kişinin özdeş olduğu garanti edilir, diğer bir deyişle, Symboleşit olan iki s aslında aynıdır Symbol. Bu, değer eşitliği ve referans eşitliğinin aynı şey olduğu ve dolayısıyla eşitliğin etkili olduğu ve O (1) anlamına gelir.

Onları bir dilde bulundurma nedenleri, dilden bağımsız olarak gerçekten aynıdır. Bazı diller onlara diğerlerinden daha fazla güvenir.

Örneğin Lisp ailesinde "değişken" kavramı yoktur. Bunun yerine, Symboldeğerlerle ilişkilendirilmişsinizdir.

Yansıtıcı veya özeleştirisel yeteneklere sahip dillerde, Symbols genellikle Ruby, yansıma API'leri örn yansıyan kişilerin isimlerini belirtmek için kullanılır Object#methods, Object#singleton_methods, Object#public_methods, Object#protected_methods, ve Object#public_methodsbir dönüş Arrayiçinde Symbol(onlar sadece yanı bir geri dönebilirler rağmen s Arrayarasında Methods). Object#public_sendBir sürer Symbol(aynı zamanda kabul etse bir argüman olarak göndermek için mesajın adını gösteren String, hem de Symboldaha anlam doğrudur).

ECMAScript'e olarak, Symbols olan temel gelecekte ECMAScript yeteneği-kasa yapma yapı taşı. Ayrıca yansımada büyük rol oynarlar.


Erlang atomları doğrudan Prolog'dan alınmıştır (Robert Virding bir noktada bunu söyledi)
Zachary K

2

Semboller Ruby'de kullanışlıdır ve her bir referansta her sembol yeniden kullanıldığından, bunları Ruby kodunun her yerinde görürsünüz. Bu, dizeler üzerinde yapılan bir performans geliştirmesidir, çünkü bir değişkende kaydedilmeyen bir dizenin her kullanımı bellekte yeni bir nesne oluşturur. Örneğin, bir karma anahtarıyla aynı dizeyi birden çok kez kullanırsam:

my_hash = {"a" => 1, "b" => 2, "c" => 3}
100_000.times { |i| puts my_hash["a"] }

"A" dizesi bellekte 101.000 kez oluşturulur. Bunun yerine bir sembol kullandıysam:

my_hash = {a: 1, b: 2, c: 3}
100_000.times { |i| puts my_hash[:a] }

Sembol :ahala bellekteki bir nesnedir. Bu, sembolleri dizelerden çok daha verimli hale getirir.

GÜNCELLEME Performans farkını gösteren bir karşılaştırma ölçütü ( Codecademy'den alınmıştır ):

require 'benchmark'

string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]

string_time = Benchmark.realtime do
  100_000.times { string_AZ["r"] }
end

symbol_time = Benchmark.realtime do
  100_000.times { symbol_AZ[:r] }
end

puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."

İşte MBP'm için sonuçlarım:

String time: 0.1254125550040044 seconds.
Symbol time: 0.07360960397636518 seconds.

Yalnızca bir karmadaki tuşları tanımlamak için dizeler ve semboller kullanmanın açık bir farkı vardır.


Durumun bu olup olmadığından emin değilim. Ruby uygulaması aynı kodu birden çok kez yürütmek, her yineleme için kodu tekrar tekrar ayrıştırma beklenir. Her sözcüksel oluşum "a"gerçekten yeni bir dize olsa bile , örneğinizde tam olarak iki tane olacağını düşünüyorum "a"(ve bir uygulama mutasyona uğrayana kadar hafızayı bile paylaşabilir). Milyonlarca dize oluşturmak için muhtemelen String.new ("a") kullanmanız gerekir. Ama Ruby'de iyi bilgili değilim, bu yüzden belki de yanılıyorum.
coredump

1
Codecademy'nin derslerinden birinde, örneğim gibi, dizeler ve semboller için bir kıyaslama oluşturuyorlar. Cevaba ekleyeceğim.
Keith Mattix

1
Karşılaştırmayı eklediğiniz için teşekkür ederiz. Testiniz, hashtable'daki daha hızlı test (kimlik ile string karşılaştırması) nedeniyle dizeler yerine semboller kullanarak elde edilen beklenen kazancı gösterir, ancak her yinelemede dizelerin tahsis edildiğini belirleyememizin hiçbir yolu yoktur. Bunun string_AZ[String.new("r")]bir fark yaratıp yaratmadığını görmek için ile bir sürüm ekledim . Her seferinde dizeler için 21ms (orijinal sürüm), sembollerle 7ms ve taze dizelerle 50ms alıyorum. Bu yüzden dizelerin gerçek "r"sürümle ayrılmadığını söyleyebilirim .
coredump

1
Ah, bu yüzden biraz daha kazma yaptım ve Ruby 2.1'de dizeler aslında paylaşılıyor. Görünüşe göre bu güncellemeyi kaçırdım; işaret ettiğin için teşekkürler. Orijinal soruya dönersek, her iki ölçütün de sembollerin dizelere karşı faydasını gösterdiğini düşünüyorum.
Keith Mattix
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.