Raku'da Özel ve Genel Nitelikleri ve Erişimcileri Birleştirmek


12
#Private attribute example
class C { 
    has $!w;                            #private attribute
    multi method w { $!w }              #getter method
    multi method w ( $_ ) {                 #setter method
        warn “Don’t go changing my w!”;   #some side action
        $!w = $_
    }  
}
my $c = C.new
$c.w( 42 )
say $c.w #prints 42
$c.w: 43
say $c.w #prints 43

#but not
$c.w = 44
Cannot modify an immutable Int (43)

şu ana kadar çok makul ve sonra

#Public attribute example
class C { 
    has $.v is rw    #public attribute with automatic accessors
}
my $c = C.new
$c.v = 42
say $c.v #prints 42

#but not
$c.v( 43 ) #or $c.v: 43
Too many positionals passed; expected 1 argument but got 2

'=' Ödevinin aciliyetini seviyorum, ancak çoklu yöntemlerin sağladığı yan eylemlerde tıkanma kolaylığına ihtiyacım var. Bunların iki farklı dünya olduğunu ve karışmadıklarını anlıyorum.

AMA - Neden sadece $ cv'ye gidemediğimi anlamıyorum (43) Genel bir özellik ayarlamak için

  1. Raku'nun bu iki modu karıştırmamam için bana yol gösterdiğini hissediyorum - bazı özellikler özel ve bazıları kamuya açık ve baskının yöntem yöntemine doğru (bazılarıyla: kolondan şeker) - Raku'nun tasarımının amacı bu mu?
  2. Bir şey mi kaçırıyorum?

Bir Proxy kullanabilirsiniz
user0721090601

Proxy'yi nasıl kullanabilirsiniz? Yani, erişimci belirtildiğinde zaten bir kap döndürür is rw. Proxy döndürmek erişimcideki izin verilen parametre sayısını değiştirmeyecektir.
Elizabeth Mattijsen

@ElizabethMattijsen Belki de soruyu yanlış anladım. Ama bu (her iki etkinleştirme ne istediğini işten görünüyor = foove .(foo): ayarlanması için) ve her iki durumda da yapılması gereken yan etkileri sağlayan (ancak yalnızca getirilen) tio.run/...
user0721090601

Yanıtlar:


13

Raku'nun tasarımının amacı bu mu?

Raku'nun bu alanda tamamen açılmamış olduğunu söylemek doğru. Sorunuz Raku'nun tasarımında, her ikisinin de küçük bir tartışmaya değer iki temasına değiniyor.

Raku birinci sınıf l değerlerine sahiptir

Raku, l-değerlerini birinci sınıf bir şey olarak bolca kullanır. Yazdığımızda:

has $.x is rw;

Oluşturulan yöntem:

method x() is rw { $!x }

is rwBurada yöntem dönen olduğunu gösterir l-değeri olduğunu, atanabilecek bir şey -. Böylece yazdığımızda:

$obj.x = 42;

Bu sözdizimsel şeker değildir: gerçekten bir yöntem çağrısıdır ve daha sonra atama operatörü sonucuna uygulanır. Yöntem çağrısı Scalarözniteliğin kapsayıcısını döndürdüğü için , daha sonra bu öğeye atanabilir. Bu, önemsiz bir sözdizimsel dönüşüm olmadığını görmek için bunu iki adıma bölmek için bağlamayı kullanabilir. Örneğin, bu:

my $target := $obj.x;
$target = 42;

Nesne özniteliğine atanır. Aynı mekanizma, liste ataması da dahil olmak üzere diğer birçok özelliğin arkasındadır. Örneğin, bu:

($x, $y) = "foo", "bar";

Bir oluşturarak çalışır Listkapları içeren $xve $yve sonra bu durumda atama operatörü atama yapmak için her yan çiftler halinde dolaşır. Bu, rworada nesne erişimcilerini kullanabileceğimiz anlamına gelir :

($obj.x, $obj.y) = "foo", "bar";

Ve hepsi doğal olarak çalışıyor. Bu aynı zamanda dizi ve karma dilimlere atamanın arkasındaki mekanizmadır.

Ayrıca Proxy, okuma ve yazma davranışının kontrolünüz altında olduğu bir l-değeri konteyneri oluşturmak için de kullanılabilir . Böylece, yan eylemleri devreye sokabilirsiniz STORE. Ancak...

Raku "ayarlayıcılar" üzerinde anlamsal yöntemleri teşvik ediyor

OO'yu tanımladığımızda, "kapsülleme" ve "veri gizleme" gibi terimler sıklıkla ortaya çıkar. Buradaki anahtar fikir, nesnenin içindeki durum modelinin - yani davranışlarını (yöntemleri) uygulamak için ihtiyaç duyduğu verileri temsil etmeyi seçme biçiminin - örneğin yeni gereksinimleri ele almak için gelişmekte özgür olmasıdır. Nesne ne kadar karmaşıksa, o kadar özgürleştirici hale gelir.

Ancak, alıcılar ve ayarlayıcılar, devletle örtülü bir bağlantısı olan yöntemlerdir. Veri gizleme gerçekleştirdiğimizi iddia edebilirsek de, doğrudan bir duruma erişemeyen bir yöntemi çağırdığımızdan, deneyimim, dış kodun bir işlemi gerçekleştirmek için ayarlayıcı çağrıları dizileri yaptığı hızlı bir şekilde sonuçlandığımızdır. özellik bir tür gıpta anti-desen. Yaptığımız Ve eğer o , biz bir operasyon gerçekleştirmek için alıcı ve ayarlayıcı operasyonların bir karışımını yapar nesnenin mantık dışı ile bitireceğiz oldukça kesin. Gerçekten, bu operasyonlar neyin başarıldığını tanımlayan bir isme sahip yöntemler olarak ortaya konmuş olmalıdır. Eğer eşzamanlı bir ortamdaysak bu daha da önemli hale gelir; iyi tasarlanmış bir nesnenin yöntem sınırında korunması genellikle oldukça kolaydır.

Bununla birlikte, birçok kullanımı classgerçekten kayıt / ürün türleridir: bir grup veri öğesini basitçe gruplamak için vardır. Bu tesadüf değil .desen sadece ayrıca bir erişimci üretmek değil,:

  • Özniteliği varsayılan nesne başlatma mantığı (yani, a class Point { has $.x; has $.y; }olarak örneklenebilir Point.new(x => 1, y => 2)) tarafından ayarlanmayı seçer ve bunu .rakudamping yönteminde de oluşturur.
  • Özniteliği varsayılan .Capturenesneye seçer , yani onu yok etme işleminde kullanabiliriz (örn. sub translated(Point (:$x, :$y)) { ... }).

Daha prosedürel veya işlevsel bir tarzda yazıyor ve classbir kayıt türü tanımlamak için bir araç olarak kullanıyorsanız , istediğiniz şeyler bunlar .

Raku tasarımı, ayarlayıcılarda akıllı şeyler yapmak için optimize edilmemiştir, çünkü bu optimize etmek için kötü bir şey olarak kabul edilir. Bir kayıt türü için gerekenin ötesinde; bazı dillerde, atananların doğrulanmasını istediğimizi iddia edebiliriz, ancak Raku'da bunun için subsettürlere başvurabiliriz . Aynı zamanda, gerçekten bir OO tasarımı yapıyorsak, konum belirleme başarısızlığına neden olan alıcılar / belirleyiciler açısından düşünmek yerine, devlet modelini gizleyen anlamlı davranışlar için bir API istiyoruz. Zaten OO yapmanın en önemli noktası olan veri ve davranış.


Proxy(Ben ha önerdi rağmen) s dikkatle üzerinde iyi bir nokta . Onları çok faydalı bulduğum tek zaman benim için LanguageTag. Dahili olarak, $tag.regiontüründe bir nesne döndürür Region(dahili olarak depolanan gibi), ama gerçek insanlar için söylemesi sonsuz daha kullanışlıdır olduğu $tag.region = "JP"üzerinde $tag.region.code = "JP". Ve bu Strtürden bir baskıyı ifade edene kadar gerçekten geçicidir , örn. has Region(Str) $.region is rw(İki ayrı planlanmış ancak düşük öncelikli özellik gerektirir)
user0721090601

@Jonathan'a tasarım mantığını hazırlamak için zaman ayırdığınız için teşekkür ederim - Bir tür yağ ve su yönünden şüphelendim ve benim gibi CS olmayan bir vücut için, gizli duruma uygun OO ile sınıf es uygulaması arasındaki farkı gerçekten alıyorum C ++ bir doktora alacak ezoterik veri sahipleri oluşturmak için daha kolay bir yol. Ve user072'ye ... Proxy s hakkındaki düşünceleriniz için. Daha önce
Proxy'leri biliyordum

p6steve: Raku gerçekten en yaygın / kolay şeyleri kolaylaştırmak için tasarlandı. Ortak modellerden saptığınızda, her zaman mümkündür (bence şimdiye kadar istediğinizi yapmak için üç farklı yol gördünüz ... ve kesinlikle daha fazlası var), ama bu sizi biraz işe yaratıyor - Yaptığın şeyin gerçekten istediğin olduğundan emin. Ancak, özellikler, proxy'ler, slangs vb.
user0721090601

7

AMA - Neden sadece $ cv'ye gidemediğimi anlamıyorum (43) Genel bir özellik ayarlamak için

Bu gerçekten mimara bağlı. Ama cidden, hayır, Raku'nun çalışma şekli standart değil.

Şimdi, Attributemodül alanında, değeri ayarlamak için tek bir değeri kabul is settableedecek alternatif bir erişimci yöntemi yaratacak bir özellik oluşturmak tamamen mümkün olacaktır . Bunu temelde yapmanın problemi, dünyada böyle bir mutatörün dönüş değeri hakkında temel olarak 2 kampın olduğudur: yeni değeri mi, yoksa eski değeri mi döndürecek ?

Modül alanında böyle bir özellik uygulamakla ilgileniyorsanız lütfen benimle iletişime geçin.


1
Teşekkürler @Elizabeth - bu ilginç bir açı - Ben sadece burada ve orada bu soruyu vurmak ve hile yapmak için bir özellik (ya da benim tarafımda) yapmak için yeterli geri ödeme yoktur. Gerçekten başımı en iyi kodlama pratiği etrafında bulmaya ve buna uyum sağlamaya çalışıyordum - ve Raku'nun tasarımının, topladığım en iyi uygulamalara uygun olmasını umuyordum.
p6steve

6

Şu anda kafanızın karıştığından şüpheleniyorum. 1 Buna dokunmadan önce, kafanızın karışmadığı şeylerle başlayalım:

=Görevin aciliyetini seviyorum , ancak çoklu yöntemlerin sağladığı yan eylemlerde tıkanma kolaylığına ihtiyacım var. ... Neden gidemediğimi anlamıyorum $c.v( 43 )Genel bir özellik ayarlamak için

Sen olabilir bütün bu şeyleri yapmak. Yani, =atama ve çoklu yöntemler kullandığınızı ve "sadece gidin $c.v( 43 )" ifadesini kullanırsınız.

class C {
  has $!v;
  multi method v                is rw {                  $!v }
  multi method v ( :$trace! )   is rw { say 'trace';     $!v }
  multi method v ( $new-value )       { say 'new-value'; $!v = $new-value }
}
my $c = C.new;
$c.v = 41;
say $c.v;            # 41
$c.v(:trace) = 42;   # trace
say $c.v;            # 42
$c.v(43);            # new-value
say $c.v;            # 43

Olası bir karışıklık kaynağı 1

Perde arkasında, has $.foo is rwaşağıdaki satırlar boyunca bir öznitelik ve tek bir yöntem oluşturur:

has $!foo;
method foo () is rw { $!foo }

Yukarıdakiler doğru değil. Gördüğümüz davranış göz önüne alındığında, derleyicinin otomatik oluşturulmuş fooyöntemi bir şekilde aynı ada sahip herhangi bir yeni yöntem sessizce gölgeleyecek şekilde ilan edilir. 2

Bu nedenle, öznitelikle aynı ada sahip bir veya daha fazla özel yöntem istiyorsanız, normalde sorumlu olacağı davranışı korumak istiyorsanız otomatik olarak oluşturulan yöntemi el ile çoğaltmanız gerekir .

Dipnotlar

1 Raku'nun özel ve kamu alıcıları / belirleyicileri hakkındaki görüşlerini ve kamu alıcılarını / belirleyicilerini (yani yazma has $.foo) beyan ettiğinizde perde arkasında ne yaptığını net, kapsamlı ve güvenilir bir şekilde açıklamak için jnthn'ın cevabına bakın .

2 Bir öznitelik için otomatik olarak oluşturulmuş bir erişimci yöntemi bildirildiyse only, Raku, aynı ada sahip bir yöntem bildirilirse bir istisna atar. Bildirildiyse multi, yeni yöntem de bildirilmişse gölgelenmemeli multive eğer değilse bir istisna atmalıdır. Böylece otomatik olarak üretilen erişimci, ne gölgede ne onlyde multibir şekilde sessiz gölgelemeye izin veren bir şekilde ilan edilir .


Aha - teşekkürler @raiph - eksik olduğunu hissettiğim şey bu. Şimdi bir şey ifade ediyor. Jnthn başına muhtemelen daha iyi bir gerçek OO kodlayıcı olmaya çalışacağım ve saf veri kapları için ayarlayıcı stilini koruyacağım. Ancak bunun araç kutusunda olduğunu bilmek güzel!
p6steve
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.