Değişmez bir koleksiyonda mutasyona uğramayan bir "ekleme" yöntemi için en iyi isim nedir?


229

Waffly unvanı için özür dilerim - kısa bir başlık bulabilirsem soruyu sormak zorunda kalmazdım.

Değişmez bir liste türüm olduğunu varsayalım. Sonunda Foo(x)belirtilen bağımsız değişken ile yeni bir değişmez liste döndüren bir işlem var. Yani "Merhaba", "değişmez", "dünya" değerlerine sahip dizelerin bir listesini oluşturmak için şunu yazabilirsiniz:

var empty = new ImmutableList<string>();
var list1 = empty.Foo("Hello");
var list2 = list1.Foo("immutable");
var list3 = list2.Foo("word");

(Bu C # kodudur ve dilin önemli olduğunu düşünüyorsanız en çok C # önerisiyle ilgileniyorum. Temelde bir dil sorusu değil, ancak dilin deyimleri önemli olabilir.)

Önemli olan mevcut listeleri olmasıdır değil tarafından değiştirilmiş Fooöylesine - empty.Counthala 0 döndürecektir.

Son sonuca ulaşmanın bir başka (daha deyimsel) yolu:

var list = new ImmutableList<string>().Foo("Hello")
                                      .Foo("immutable")
                                      .Foo("word");

Sorum şu: Foo'nun en iyi adı nedir?

DÜZENLEME 3 : Daha sonra açıkladığım gibi ImmutableList<T>, türün adı aslında olmayabilir , bu da konumu netleştirir. Bunun yerine TestSuiteve bunun değişmez olduğunu hayal edin çünkü bir parçası olduğu çerçevenin tamamı değişmez ...

(Düzenleme sonu 3)

Şimdiye kadar bulduğum seçenekler:

  • Add: .NET'te yaygındır, ancak orijinal listenin mutasyonunu ima eder
  • Cons: Bunun işlevsel dillerde normal ad olduğuna inanıyorum, ancak bu dillerde deneyimi olmayanlar için anlamsız
  • Plus: şimdiye kadarki favorim, bana mutasyon demek değil . Görünüşe göre bu Haskell'de de kullanılıyor, ancak biraz farklı beklentilerle (bir Haskell programcısı, diğer listeye tek bir değer eklemek yerine birlikte iki liste eklemesini bekleyebilir).
  • With: diğer bazı değişmez sözleşmelerle tutarlı olmakla birlikte, IMO'ya tamamen aynı "katılıma" sahip değildir.
  • And: çok açıklayıcı değil.
  • + İçin operatör aşırı yükü: Gerçekten bu kadar sevmiyorum; Genel olarak operatörlerin yalnızca daha düşük seviye türlerine uygulanması gerektiğini düşünüyorum. Yine de ikna olmaya hazırım!

Seçim için kullandığım kriterler:

  • Yöntem çağrısının sonucuna ilişkin doğru izlenimi verir (yani, fazladan bir öğeye sahip orijinal liste olduğu anlamına gelir)
  • Mevcut listeyi değiştirmediğini olabildiğince netleştirir
  • Yukarıdaki ikinci örnekte olduğu gibi birlikte zincirlendiğinde makul geliyor

Kendimi yeterince açıklamıyorsam lütfen daha fazla ayrıntı isteyin ...

DÜZENLEME 1: İşte tercih Plusetme nedenim Add. Şu iki kod satırını düşünün:

list.Add(foo);
list.Plus(foo);

(Ve bu benim görünümünde olan kişisel bir şey) ikincisi açıkça adamcağız - yazılı gibi "x + 5;" kendi başına bir ifade olarak. İlk satır, değişmez olduğunu hatırlayana kadar, tamam gibi görünüyor. Aslında, artı operatörün kendi başına işlenenlerini değiştirmemesi Plus, benim favorimin başka bir nedenidir . Operatörün aşırı yüklenmesi gibi hafif bir rahatsızlık olmadan, yine de (benim için) işlenenleri mutasyona uğratmamayı (veya bu durumda yöntem hedefini) içeren aynı çağrışımları verir.

DÜZENLEME 2: Add'i beğenmeme nedenleri.

Çeşitli cevaplar etkili bir şekilde: "Add ile git. Bu , değişmezliği açık hale getirmeyen yöntemlere sahiptir DateTimeve böyle." Katılıyorum - burada öncelik var. İnsanlar diyoruz Ancak, ben bol gördüm ya ve mutasyon bekliyoruz . Çok sayıda haber grubu sorusu var (ve eğer etrafta kazarsam muhtemelen SO olanlar).StringReplaceDateTime.AddString.ReplaceString.Replace ; dizeler değiştirilemez, yeni bir dize döndürülür."

Şimdi, soruya incelik açığa çıkarmalıdır - tipi olabilir değil aslında bir değişmez liste, ancak farklı bir değişmez tipte. Özellikle, bir pakete testler eklediğiniz ve bu yeni bir paket oluşturan bir karşılaştırma çerçevesi üzerinde çalışıyorum. Açıktır ki:

var list = new ImmutableList<string>();
list.Add("foo");

hiçbir şey başaramayacak, ancak şu şekilde değiştirdiğinizde çok daha karanlık oluyor:

var suite = new TestSuite<string, int>();
suite.Add(x => x.Length);

Tamam olmalı. Oysa bu benim için hatayı daha net hale getiriyor:

var suite = new TestSuite<string, int>();
suite.Plus(x => x.Length);

Bu sadece yalvarıyor:

var suite = new TestSuite<string, int>().Plus(x => x.Length);

İdeal olarak, kullanıcılarımın test paketinin değişmez olduğu söylenmemesini istiyorum. Onların başarı çukuruna düşmelerini istiyorum. Bu mümkün olmayabilir , ama denemek istiyorum.

Sadece değişmez bir liste türü hakkında konuşarak orijinal soruyu aşırı basitleştirdiğim için özür dilerim. Tüm koleksiyonlar kendileri kadar açıklayıcı değildir ImmutableList<T>:)


2
@Adam: Hayır, ikincisi açıkça buggy. İkisi de aslında buggy (sonuçta hiçbir şey yapmadıkları için) - ama ilki bana buggy görünmüyor .
Jon Skeet

36
Uncat köpek mi?
Michael Myers

7
Concat / Condog ... benim için çalışıyor! ;)
gnovice

11
Uncat - bu bir zombi kedisi olurdu.
Erik Forbes

2
@Trap: Bu, API akışkanı yapmak açısından berbat.
Jon Skeet

Yanıtlar:


130

Bu gibi durumlarda, genellikle giderim Concat. Bu genellikle bana yeni bir nesne yaratıldığını ima eder.

var p = listA.Concat(listB);
var k = listA.Concat(item);

3
Kullandığım şey bu, çünkü System.Linq.Enumerable kullanımları - karar zaten verildi. :) Eklenecek tek bir değeri kabul etmek için IEnumerable'da Concat uzantısının kendi aşırı yüklenmesini tanımlayan tek kişi olamam.
Daniel Earwicker

9
+1 Bu, çerçeve içinde adlandırma tutarlılığını korumak için doğru cevaptır.
Sam Harwell

Ben eksik sürece, System.Linq.Enumerable (ve genel olarak Linq) sadece "dizi + dizi" için asla Concat () kullanır, asla "madde + dizi". Birisinin "diğer listeye tek bir değer eklemek yerine birlikte iki liste eklemesini beklemesi" sorunu, diğer orijinal seçeneklerden birini kullanmamanın bir nedeni olarak açıkça belirtilmiştir.
Ssswift

119

Eksileriyle basit bir nedenden dolayı giderdim: tam olarak ne istediğinizi ifade eder.

  1. Tam olarak ne demek istediğimi söylemenin büyük bir hayranıyım, özellikle kaynak kodunda. Bir acemi, Eksilerin tanımını sadece bir kez aramak zorunda kalacak, ancak daha sonra bunu binlerce kez okuyup kullanacak. Uzun vadede, ön maliyet biraz daha yüksek olsa bile, ortak durumu kolaylaştıran sistemlerle çalışmak daha hoş.

  2. FP deneyimi olmayan insanlar için "anlamsız" olması aslında büyük bir avantajdır. Belirttiğiniz gibi, bulduğunuz diğer tüm kelimelerin zaten bir anlamı vardır ve bu anlam biraz farklı veya belirsizdir. Yeni bir kavramın yeni bir sözcüğü olmalıdır (ya da bu durumda eski bir sözcük). Birisinin, eklentinin ne yaptığını yanlış bildiğini varsaymak yerine, Cons'un tanımına bakmasını tercih ederim.

  3. İşlevsel dillerden ödünç alınan diğer işlemler genellikle belirgin isimleri olmadan orijinal adlarını korur. FPer olmayanlara daha tanıdık gelen "harita" ve "azaltmak" için eşanlamlılar bulmak için herhangi bir baskı görmedim, ne de bundan fayda görmüyorum.

(Tam açıklama: Lisp programcısıyım, bu yüzden Eksilerin ne anlama geldiğini zaten biliyorum.)


16
Keşfedilebilirliğin önemli olduğunu unutmayın - "testSuite" yazarsam. ve yöntemler listesine bakın, doğru olanı öneren bir yöntem görmek istiyorum. Muhtemelen bu benim için saçma sapan (bana göre) bir isim aramayacağım.
Jon Skeet

33
Eğer sersemlemiş hissettim, bir ileti = "Bir ImmutableList başa eklemek için eksilerini kullanın" ile bir istisna attı Add yöntemi yapmak istiyorum. :-)
Ken

2
Kimsenin adının neden olduğunu açıklayan birkaç yorum satırı okumak ve onları Abelson & Sussman'ın "Bilgisayar Programlarının Yapısı ve Yorumu" na yönlendirmek için kimseyi öldürmez.
John R. Strohm

16
Geleneksel olarak, eksiler sonunda değil, başlangıçta ekler. Dolayısıyla, açıklanan yöntem için potansiyel olarak yanıltıcı bir isimdir.
walkytalky

16
Sadece bir sonraki işlevsel olmayan programcıya bir tıklama veya 3 ... en.wikipedia.org/wiki/Cons "yapı" sözcüğünden kaydetmek için, "cons x to y" ifadesi ile yeni bir nesne oluşturmak anlamına gelir. cons xy)
Myster

59

Aslında And, özellikle deyimsel olarak hoşuma gidiyor. Özellikle Boş liste için statik bir salt okunur özelliğiniz varsa ve belki de her zaman boş listeden inşa etmek zorunda olduğunuzda yapıcıyı özel yapmayı sevdim.

var list = ImmutableList<string>.Empty.And("Hello")
                                      .And("Immutable")
                                      .And("Word");

Boş fikri seviyorum. Hala hakkında ikna olmadım Ve olsa. Sadece biraz falan.
Jon Skeet

Daha çok doğal dilde bir şeyler listesi oluşturmayı nasıl düşünürdüm gibi görünüyor. Yüksek sesle okursanız, Add veya Plus'tan daha sezgisel görünüyor. "liste" boş liste ve "Merhaba" ve "Değişmez" ve "Kelime" dir. Bununla birlikte, izolasyonda daha az net olduğu konusunda hemfikirim.
tvanfosson

52

Ne zaman isimlendirme ile bir reçeldeysem, iç ağlara çarptım.

thesaurus.com bunu "ekle" için döndürür:

Tanım: adjoin, artış; daha fazla yorum yap

Eşanlamlılar: ek, ek, ante, ekle, artırma, sığır eti yukarı, artırma, biriktirme, şarj etme, devam et, işaretleme, şekil verme, et dışarı, ısınma, yürüyüş, yürüyüş, takılma, bağlanma, bağlanma dahil, jack up, jazz up, birlikte katılmak, yastık, parlay, sırtlama, tak, dökmek, cevap, koşmak, daha fazla söylemek, tokat, kartopu, çorba, hızlandırmak, başak, hızlandırmak, ek, tatlandırmak, tack, etiket

Sesini seviyorum Adjoinya da daha basit olarak Join. Yaptığın şey bu, değil mi? Yöntem, diğerlerinin katılımına da uygulanabilir ImmutableList<>.


1
Ben de 'Katıl' gibi seviyorum ama çoğu durumda, 2 nesneye katıldığınızda, 1 ile sonuçlanırsınız. Bu durumda, 2 nesneye katılırsanız, aslında yeni bir nesne yaratırsınız.
Yasadışı Programcı

1
.NET, Perl, PHP ve hatta VBScript'te Join mutasyon anlamına gelen hiçbir durum bilmiyorum. Tasarım, A ve B'nin C yapmak için birleştiği şekildedir, burada C her zaman yeni bir varlıktır.
spoulson

Katılmayı seviyorum ve thesaurus.com ile tamamen aynı fikirdeyim :) Bir isim hakkında şüpheniz olduğunda her zaman kullanın.
Skurmedel

var suite = yeni TestSuite <string, int> () .Join (x => x.Length);
Sly Gryphon

3
Sırtıma git, imo. Veya HookUpWith ile.
Chris Marasti-Georg

48

Şahsen ben .With () ile seviyorum. Nesneyi kullanıyordum, belgeleri veya kod yorumlarını okuduktan sonra, ne yaptığı açıktır ve kaynak kodunda ok okur.

object.With("My new item as well");

Veya onunla birlikte "Along" ekleyin .. :)

object.AlongWith("this new item");

+1. "WITH" aynı şeyi yapan SETL'de bir infix operatörüdür. SETL kullanıyorsa doğru olmalı :-)
finnw

1
Bah ... Artık kim VB kullanıyor? :) Ah .. Opps .. Bu yüksek mi? heh .. Ama, hayır, tüm ciddiyetle, bu yüzden VB sorununu ortadan kaldıracak "AlongWith" düşündüm. Bununla gidebileceği yaklaşık bir milyon farklı yol var ... Yani, deli gibi olanlar bile: object.Plus () veya Object.ExistingPlus () ... vb ... Ancak, gönderildi ... heh ..
LarryF

33

BclExtras'taki tüm Immektif Koleksiyonlarım için Add ile devam ettim . Nedeni kolay tahmin edilebilir bir isim olmasıdır. Ben kafa karıştırıcı insanlar hakkında çok endişelenmiyorum mutasyona bir ekleme ile Add türü adı Immutable ile ön ekidir çünkü.

Bir süredir Eksileri ve diğer işlevsel stil isimlerini düşündüm. Sonunda onları indirim yaptım çünkü neredeyse çok iyi bilinmiyorlar. Elbette fonksiyonel programcılar anlayacaktır, ancak kullanıcıların çoğunluğu değildir.

Diğer İsimler: bahsettiğiniz:

  • Artı: Bunu istiyorum / yıkıyorum. Benim için bu, artık Add'den daha mutasyona uğramayan bir işlem olarak ayırt edilmiyor
  • İle: VB ile ilgili sorunlara neden olur (pun amaçlı)
  • Operatör aşırı yüklenmesi: Keşfedilebilirlik bir sorun olurdu

Düşündüğüm seçenekler:

  • Concat: String'ler Değişmezdir ve bunu kullanırlar. Ne yazık ki sonuna kadar eklemek gerçekten çok iyi
  • CopyAdd: Ne kopyalansın? Kaynak, liste?
  • AddToNewList: Liste için iyi olabilir. Ama bir Koleksiyon, Yığın, Sıra vb.

Ne yazık ki bir kelime var gibi gözükmüyor

  1. Kesinlikle değişmez bir operasyon
  2. Kullanıcıların çoğunluğu tarafından anlaşılabilir
  3. 4 kelimeden az temsil edilebilir

Liste dışındaki koleksiyonları düşündüğünüzde daha da garipleşir. Örneğin Stack'i ele alalım. İlk yıl programcıları bile Stacks'ın bir Push / Pop çifti yöntemine sahip olduğunu söyleyebilir. Bir ImmutableStack oluşturursanız ve ona tamamen farklı bir ad verirseniz, buna Foo / Fop diyelim, koleksiyonunuzu kullanmaları için daha fazla iş eklediniz.

Düzenleme: Artı Düzenleme'ye Yanıt

Plus ile nereye gittiğini görüyorum. Bence daha güçlü bir dava aslında kaldırılması için Eksi olurdu. Eğer aşağıdakileri görürsem kesinlikle programcının ne düşündüğünü merak ederdim

list.Minus(obj);

Artı / Eksi veya yeni bir eşleştirme ile ilgili en büyük sorun, aşırıya kaçma gibi hissetmek. Koleksiyonun zaten ayırt edici bir adı var, Immutable öneki. Niçin Değiştirilebilir önek ile aynı ayrımı eklemek olan kelime dağarcığını ekleyerek neden daha ileri gidelim.

Çağrı sitesi argümanını görebiliyorum. Tek bir ifade açısından onu daha net hale getirir. Ancak tüm fonksiyon bağlamında gereksiz görünüyor.

Düzenle 2

İnsanların String.Concat ve DateTime.Add tarafından kesinlikle karıştırıldığını kabul edin. Birkaç parlak programcının bu soruna çarptığını gördüm.

Ancak ImmutableList'in farklı bir argüman olduğunu düşünüyorum. String veya DateTime ile ilgili olarak onu programcıya bağdaşmaz olarak belirleyen hiçbir şey yoktur. Sadece bilmelisin bazı diğer kaynak yoluyla değişmez olduğunu. Yani karışıklık beklenmedik değil.

ImmutableList'in adı bu davranışı tanımladığı için bu sorunu yaşamaz. İnsanların Dokunulmaz'ın ne olduğunu bilmediğini ve bence bu da geçerli. Kesinlikle üniversitede yaklaşık 2 yıla kadar bilmiyordum. Ancak, Ekle yerine seçtiğiniz adla aynı sorunu yaşarsınız.

Düzenleme 3: TestSuite gibi değişmeyen ancak kelimeyi içermeyen türler ne olacak?

Sanırım bu, yeni yöntem isimleri icat etmemeniz gerektiği fikrini eve getiriyor. Diğer bir deyişle, paralel işlemleri kolaylaştırmak için türleri değişmez kılmak için açıkça bir dürtü vardır. Koleksiyonlar için yöntemlerin adını değiştirmeye odaklanırsanız, bir sonraki adım, kullandığınız her türde değiştirilemeyen mutasyon yöntem adları olacaktır.

Bunun yerine türleri Değişmez olarak tanımlanabilir hale getirmeye odaklanmanın daha değerli bir çaba olacağını düşünüyorum. Bu şekilde, orada her mutasyon yöntemini yeniden düşünmeden sorunu çözebilirsiniz.

Şimdi TestSuite'i Bağlanabilir olarak nasıl tanımlayabilirsiniz? Bugünün ortamında bence birkaç yol var

  1. Immutable ile Önek: ImmutableTestSuite
  2. Immutablitiy seviyesini tanımlayan bir Nitelik ekleyin. Bu kesinlikle daha az keşfedilebilir
  3. Çok fazla değil.

Tahminim / umudum, geliştirme araçlarının değişmez türleri kolayca görerek (farklı renk, daha güçlü yazı tipi, vb ...) tanımlamayı kolaylaştırarak bu soruna yardımcı olmaya başlayacağıdır. Ama bence bu, tüm yöntem adlarını değiştirmenin cevabı.


Soruya ekle için Plus over tercihimin nedenlerini ekledim. Bu muhakeme hakkındaki yorumları memnuniyetle karşılarız. Ben gerçekten ben aptal oluyorum fikrine açık.
Jon Skeet

@JaredPar: Tür TestSuite olarak adlandırılırsa ne olur?
Jon Skeet

Düzenleme 3 için başka bir +1 vermek isterdim, ancak belli ki yapamazsınız. (Benim durumumda paralellik elde etmeye çalışmıyorum - değişmezliğin akıl yürütmesi daha kolay olan koda yol açtığına inanıyorum.) Hala değilim oldukça Ekle gitmek için yol olduğuna ikna, ama burada cevapları için destek ikna edicidir.
Jon Skeet

Bu soruyu işyerinde konuşmaya bırakabilirseniz, bu da harika olurdu, btw. Bir C # listesinde tartışmaya başladım, bu yüzden bazı meslektaşlar zaten dahil olabilir. Google'da da dahili olarak
sorulabilir

@Jon, sanırım bu soruyu iş yerinde bırakmak için iyi bir yer biliyorum :)
JaredPar

27

Bence bu, +operatöre aşırı yüklenmenin kabul edilebilir olduğu nadir durumlardan biri olabilir . Matematik terminolojisinde bunun +başka bir şeyin sonuna bir şey eklemediğini biliyoruz . Her zaman iki değeri bir araya getirir ve yeni bir sonuç değeri döndürür.

Örneğin, sezgisel olarak açıktır ki,

x = 2 + 2;

elde edilen x değeri 22 değil 4'tür.

Benzer şekilde,

var empty = new ImmutableList<string>();
var list1 = empty + "Hello";
var list2 = list1 + "immutable";
var list3 = list2 + "word";

her değişkenin ne tutacağını netleştirmelidir. O açık olmalıdır list2değildir değişti son satırında, ancak bunun yerine o list3kadar "sözcüğü" ekleyerek sonucu atanır list2.

Aksi takdirde, sadece Plus () işlevini adlandırırdım.


Meşru bir şekilde bir tam sayı (örneğin) veya başka bir tam sayı listesi ekleyebileceğiniz genel bir listeniz varsa ne olur ? Sonra bu + kullanımı birleştirme ile çakışacaktır.
finnw

@finnw: Ne demek istediğini anlamıyorum. Bir liste veya bir öğe ekleseniz de her zaman + işaretinin eklenmesini beklerim.
Kertenkele Bill

4
Yeniden kullanılabilir bir API için, birinin sınıfınızı operatör aşırı yüklemesi olmadan bir dilden kullanması durumunda, adlandırılmış bir yönteme sahip olmak iyi bir fikirdir.
Neil

"ister bir öğe ister çok sayıda ekleyin," - ya listeyi tek bir öğe olarak eklemek isterseniz ne olur? yani, [1] + 2 = [1,2]ama [1] + [2] = [1,[2]]. Önerdiğiniz şey tutarsız davranış. Muhtemelen Python bu şekilde bir eleman eklemenize izin vermiyordur .
Ağustos'ta 1:25 1:25

C # gibi statik olarak yazılmış bir dilde, liste öğelerinin türünü, liste listesi veya öğe listesi olup olmadığını söyleyebilir, böylece liste olan veya birleştirilmiş bir öğe eklemeye veya birleştirmeye karar vermek için türü kullanabilirsiniz iki liste.
Dobes Vandermeer

22

Mümkün olduğunca açık olmak için, wordier CopyAndAddveya benzeri bir şeyle gitmek isteyebilirsiniz .


Tüm değişmez koleksiyonlar eklemek için bir kopya gerektirmez. Değişmez ağaçları düşünün, sadece yeni bir düğüme ihtiyaçları var ve mevcut ağacı bir yaprak olarak kullanabilirler.
JaredPar

BTW, profilinizi okudum, sonra sırayla yaşlandım ve kaç yaşında olduğunuza hayran kaldım. Akıl sağlığından kısa bir süre sonra başladı.
JaredPar

İlk yorum: Ağaçları o kadar nadir kullanıyorum ki bu düşünce hiç aklıma gelmedi. Bu iyi bir nokta.
Michael Myers

İkinci yorum: İtiraf ediyorum, rozet için yaptım! Sadece yaşımı vermek istemiyorum. (Aslında senden daha gencim, ama ihtiyacım olursa crotchety eski zamanlayıcıyı oldukça iyi oynayabilirim. Ve yaşı 89 olarak listelenen tek kişi ben değilim.)
Michael Myers

Değişmez ağaçlar argümanı güçlü, iyi bir noktadır. O zaman EquivalentReferenceWith Added (x) bu argümanla savaşacak, ama kulağa aptalca ve çıkarılması zor geliyor.
TheBlastOne

21

Ben bunu Extend () veya belki ExtendWith ()Eğer gerçekten ayrıntılı gibi hissediyorum .

Genişletme, değiştirmeden başka bir şeye bir şey eklemek anlamına gelir. Bu uzatma yöntemleri kavramına benzer çünkü bu C # 'da çok ilgili bir terminoloji olduğunu düşünüyorum - onlar sınıf "kendisi" dokunmadan "bir sınıfa yeni bir yöntem" eklemek ".

Aksi takdirde, orijinal nesneyi hiç değiştirmediğinizi gerçekten vurgulamak istiyorsanız, Get- gibi bir önek kullanmak benim için kaçınılmaz gibi görünüyor.


1
Hala temel nesneye bir şey yapmayı ima ediyor.
kaos

18

Eklendi (), Eklendi ()

Geçmiş zamanı, değişmeyen nesneler üzerindeki işlemler için kullanmayı seviyorum. Orijinal nesneyi değiştirmediğiniz fikrini aktarır ve gördüğünüzde kolayca fark edebilirsiniz.

Ayrıca, mutasyon yöntemi adları genellikle gergin fiiller olduğundan, karşılaştığınız değişmez yöntem-adı gerekli durumların çoğuna uygulanır. Örneğin, değişmez bir yığın "itilmiş" ve "atmış" yöntemlere sahiptir.


1
Python da bu sözleşmeyi kullanır. Örneğin, yerleşik işlevler tersine çevrilmiş () ve sıralanmış ().
Joe

18

Mmyers CopyAndAdd önerisini seviyorum . Bir "mutasyon" temasına uygun olarak, belki Bud (aseksüel üreme), Büyümek , Çoğaltmak veya Evrimleşmekle gidebilirsin ? =)

DÜZENLEME: Genetik temamla devam etmek için, bir öncekine dayanan, ancak yeni bir şey eklenmiş yeni bir nesnenin yapıldığını ima eden Procreate'ye ne dersiniz .


14

Bu muhtemelen bir esnektir, ancak Ruby'de ayrım için yaygın olarak kullanılan bir gösterim vardır: addmutasyon yapmaz; add!mutasyona uğradığında. Bu projenizde yaygın bir sorunsa, bunu da yapabilirsiniz (alfabetik olmayan karakterlerle değil, sürekli olarak mutasyona uğrayan / mutasyona uğramayan yöntemleri belirtmek için bir gösterim kullanarak).


+1. bu dil tarafından zorunlu kılınmaz, ancak bir sözleşme olarak kabul edilir. Bunu sevdim.
oma


13

Belki de kafa karışıklığı bir arada iki işlem yapmaktan kaynaklanıyor. Neden onları ayırmıyorsunuz? DSL tarzı:

var list = new ImmutableList<string>("Hello");
var list2 = list.Copy().With("World!");

Copybir ara nesne döndürür, bu orijinal listenin değiştirilebilir bir kopyasıdır. Withyeni bir değişmez liste döndürür.

Güncelleme:

Ancak, orta ve değişken bir koleksiyona sahip olmak iyi bir yaklaşım değildir. Ara nesne Copyoperasyonda bulunmalıdır :

var list1 = new ImmutableList<string>("Hello");
var list2 = list1.Copy(list => list.Add("World!"));

Şimdi, Copyişlem, değiştirilebilir bir liste alan bir temsilci alır, böylece kopya sonucunu kontrol edebilir. Öğeleri kaldırmak veya listeyi sıralamak gibi bir öğeyi eklemekten çok daha fazlasını yapabilir. Ayrıca, ImmutableListyapıcıda, ara değişmez listeler olmadan ilk listeyi birleştirmek için de kullanılabilir .

public ImmutableList<T> Copy(Action<IList<T>> mutate) {
  if (mutate == null) return this;
  var list = new List<T>(this);
  mutate(list);
  return new ImmutableList<T>(list);
}

Artık kullanıcılar tarafından yanlış yorumlanma imkanı yok, doğal olarak başarı çukuruna düşecekler .

Yine başka bir güncelleme:

Değişken listeden bahsetmeyi hala sevmiyorsanız, şimdi içerdiğine rağmen , kopyalama işleminin listeyi nasıl dönüştüreceğini belirleyecek bir özellik nesnesi veya komut dosyası tasarlayabilirsiniz . Kullanım aynı olacaktır:

var list1 = new ImmutableList<string>("Hello");
// rules is a specification object, that takes commands to run in the copied collection
var list2 = list1.Copy(rules => rules.Append("World!"));

Artık kural adlarıyla yaratıcı olabilirsiniz ve yalnızca Copydesteklemek istediğiniz işlevselliği açığa çıkarabilirsiniz IList.

Zincirleme kullanımı için makul bir kurucu (elbette zincirleme kullanmayacak) oluşturabilirsiniz:

public ImmutableList(params T[] elements) ...

...

var list = new ImmutableList<string>("Hello", "immutable", "World");

Veya başka bir kurucuda aynı temsilciyi kullanın:

var list = new ImmutableList<string>(rules => 
  rules
    .Append("Hello")
    .Append("immutable")
    .Append("World")
);

Bu rules.Appendyöntemin döndürdüğünü varsayarthis .

En son örneğinizle böyle görünecektir:

var suite = new TestSuite<string, int>(x => x.Length);
var otherSuite = suite.Copy(rules => 
  rules
    .Append(x => Int32.Parse(x))
    .Append(x => x.GetHashCode())
);

@Jordao: Çünkü bu tür bir kompozisyon çok daha basit bir inisalizasyon formuna yol açar. Sadece bir tane istediğimde neden iki ayrı değişken var? Benzer şekilde, değişebilir bir kopya oluşturmak istemiyorum - IMO'nun mantığı daha kolay olan kodlara yol açtığı için her şeyin değişmez olmasını istiyorum.
Jon Skeet

Bunların hepsi hala "Artı" vb. Den daha kötü. Mutasyon içeren fikirler için teşekkürler, ama kesinlikle "değişmez tutmak" yaklaşımını tercih ederim.
Jon Skeet

Belki de operasyonun gerçek anlambiliminin ne olduğu konusunda daima yanlış yorumlar olacaktır. Belirtim nesnesi yolunu izlerseniz, herhangi bir mutasyon olmaz (en azından harici olarak değil), nesne yalnızca yeni değiştirilemez nesnenin nasıl görüneceğini belirtir. Sahip olduğunuz şey, değişmez bir nesneden diğerine geçen bir işlemdir ve buna Kopyalama adı verildiğinden, yanlış anlamalara yer yoktur.
Jordão

Sizin için işe yarayacak tek isimler, CopyAndAppend, CopyAndAdd, vb. Gibi bileşik isimler gibi görünmektedir
Jordão

1
Aslında değişmez koleksiyonlar için bir API olarak (tüm düzenlemelerle birlikte) bu yaklaşımı merak ediyorum. Ancak, bu yaklaşımı Concat gibi varsayılan özellikler için yardımcı yöntemlerle birleştirmenin her iki dünyanın da en iyisini sunduğunu iddia ediyorum .
kenevir

11

Birkaç rastgele düşünce:

  • ImmutableAdd ()
  • Ekleme ()
  • ImmutableList <T> (ImmutableList <T> originalList, T newItem) Yapıcı

1
ImmutableAdd için +1; Append (mutasyon yapan StringBuilder.Append gibi) ve yapıcı sürümü zincirleme açısından bir acıdır.
Jon Skeet

10

C # 'da DateTime Ekle kullanır. Öyleyse neden aynı adı kullanmıyorsunuz? Sınıfınızın kullanıcıları sınıfın değişmez olduğunu anladığı sürece.


DateTime.Add'ın insanları karıştırdığı biliniyor ... ama bunun öncelik gösterdiğine katılıyorum.
Jon Skeet

1
Tıpkı bir dizeyi mutasyona geçirme yöntemleri yeni geliştiriciler için kafa karıştırıcıdır. Ama yakında herkes "dizelerin değişmez" olduğunu öğrenir
Tundey

9

Sanırım elde etmeye çalıştığınız anahtar şeyin ifade edilmemesi zor, bu yüzden belki de içinde üretken bir kelime olan bir şey, CopyWith () veya InstancePlus () gibi bir şey.


9

İngilizce dilinin, "Ekle" ile aynı anlama gelen bir fiil kullanırken, değişmez bir şekilde imkansızlığı ima etmesine izin vereceğini sanmıyorum. "Artı" neredeyse bunu yapar, ancak insanlar yine de hata yapabilir.

Kullanıcılarınızın nesneyi değiştirilebilir bir şey için yanlış kullanmasını engellemenin tek yolu, nesnenin kendisi veya yöntemin adı aracılığıyla ("GetCopyWith" gibi ayrıntılı seçeneklerle veya ) "CopyAndAdd".

En sevdiğiniz "Artı" ile gidin.


9

İlk olarak, ilginç bir başlangıç ​​noktası: http://en.wikipedia.org/wiki/Naming_conventions_(programming) ... Özellikle, alttaki "Ayrıca Bkz" bağlantılarını kontrol edin.

Artı ya da And'ı etkin bir şekilde eşit şekilde destekliyorum.

Artı ve Ve ikisi de etimolojide matematik tabanlıdır. Bu nedenle, her ikisi de matematiksel işlemi ifade eder; her ikisi de doğal olarak bir değere dönüşebilen ve bir dönüş değerine sahip yönteme uyan ifadeler olarak okuyan bir ifade verir. Andek mantık çağrışımı taşır, ancak her iki kelime de sezgisel olarak listelere uygulanır. Addbir nesnede gerçekleştirilen ve yöntemin değişmez semantiği ile çelişen eylemi ifade eder.

Her ikisi de kısa, bu da operasyonun ilkelliği göz önüne alındığında özellikle önemlidir. Basit, sık gerçekleştirilen işlemler daha kısa isimleri hak eder.

Değişmez anlambilimi ifade etmek, bağlam yoluyla yapmayı tercih ettiğim bir şeydir. Yani, sadece bu kod bloğunun işlevsel bir hissi olduğunu ima ederim; her şeyin değişmez olduğunu varsayalım. Ancak bu sadece ben olabilirim. Değişmezliğin kural olmasını tercih ederim; eğer yapılırsa, aynı yerde çok şey yapılır; değişebilirlik istisnadır.


8

Chain () veya Attach () ne dersiniz?


1
Kesinlikle mutasyona uğramış gibi geliyor. Belki WithAttached daha akıllıca olurdu, ancak yukarıda tartışılan With Added'a çok yakın.
TheBlastOne

Bununla ne yapılmaya çalışıldığını açıklarken kaç kez "zincirleme" den bahsedildiği komik. (5 kez), ancak öneri olarak sunulmuyor! Arama visualthesaurus.comyaptığımda ortaya çıkan ilk şey (bağlantı yok) concatenate.
cod3monk3y

7

Artı (ve Eksi) tercih ederim. Kolayca anlaşılabilirler ve doğrudan iyi bilinen değişmez türleri (sayılar) içeren operasyonlarla eşleşirler. 2 + 2, 2 değerini değiştirmez, yeni, eşit olarak değiştirilemez bir değer döndürür.

Diğer bazı olasılıklar:

Ekleme ()

Greft ()

Çoğalmasına ()


6

Peki arkadaşı , mateWith veya cinsel birleşme ? Üreme açısından memeliler genellikle değişmez olarak kabul edilir.

Atacak Birliği de orada. SQL'den ödünç alındı.


2
Birlik için +1. Ancak, bunu doğrudan set teorisinden ödünç alıyorum. :-)
Christoffer Lette

SQL terminolojisinin çoğunu küme teorisinden almıyor mu?
Jason D

1
Ayrıca, Union ayrımı ifade eder .. Yinelenenleri (en azından TSQL'de) dahil etmek istiyorsanız, Union All'i açıkça kullanmanız gerekir.
kenevir

6

Görünüşe göre bu soruya cevap veren ilk Obj-C / Cocoa kişisiyim.

NNString *empty = [[NSString alloc] init];
NSString *list1 = [empty stringByAppendingString:@"Hello"];
NSString *list2 = [list1 stringByAppendingString:@"immutable"];
NSString *list3 = [list2 stringByAppendingString:@"word"];

Bununla herhangi bir kod golf oyunu kazanamayacaksınız.


[object]By[Verb]ing[Object]:Metodun öneki +1, basitçe aksine yeni bir dizenin döndürüleceğini ima eder [verb][Object]:, bu da nesneyi yerinde değiştirir.
Dave DeLong

3
+1. İnsanların ayrıntılara karşı duydukları isteksizliği anlamıyorum (kendi kendini belgeleme).
hatfinch

5

Bence "Ekle" ya da "Artı" kulağa hoş geliyor. Listenin kendisi, listenin değişmezliğini iletmek için yeterli olmalıdır.


Liste yok, bir test takımı.
tstenner

5

Belki de kopyayı yaptığımı daha çok hatırlayan ve örneği mutasyona uğratmak yerine buna bir şeyler ekleyen bazı kelimeler vardır ("Concatenate" gibi). Ama bence bu kelimeler için başka eylemler için biraz simetriye sahip olmak da iyi olur. Ben "Concatenate" gibi aynı tür düşünüyorum "Kaldır" için benzer bir kelime bilmiyorum. "Artı" bana biraz garip geliyor. Sayısal olmayan bir bağlamda kullanılmasını beklemezdim. Ama bu benim ingilizce olmayan geçmişimden de gelebilir.

Belki bu şemayı kullanırdım

AddToCopy
RemoveFromCopy
InsertIntoCopy

Bunları düşündüğümde, kendi sorunları var. Kişi bir şeyi kaldırdıklarını ya da verilen bir argümana bir şeyler eklediklerini düşünebilir. Hiç emin değilim. Bu kelimeler de zincirleme konusunda iyi oynamıyor sanırım. Yazmak için çok garip.

Belki de sadece düz "Ekle" ve arkadaşlar kullanmak istiyorum. Matematikte nasıl kullanıldığını seviyorum

Add 1 to 2 and you get 3

Elbette, 2 2 kalır ve yeni bir sayı alırsınız. Bu iki sayı hakkında ve bir liste ve bir öğe hakkında değil, ama bazı benzetme olduğunu düşünüyorum. Bana göre, bir addşeyi değiştirdiğiniz anlamına gelmez. Kesinlikle sadece bir içeren yalnız bir ifade olması addve döndürülen yeni nesneyi kullanmıyorum buggy görünmüyor olduğunu düşünüyorum. Ama şimdi de "eklemek" dışında başka bir ad kullanma fikri hakkında biraz zaman düşündüm ama sadece "hmm bana düşündürmeden başka bir isim ile gelemiyorum, ne bilmek için belgelere bakmak gerekir "hakkında" adı "beklemek" ne beklenir farklıdır çünkü. Bu konuda biraz garip düşündüm, hiç mantıklı olmadığından emin değilim :)


Ancak değişmez bir koleksiyonda her zaman bir kopya gerekli değildir. Örneğin bir ikili ağaç alın. Yeni bir kök eklemek kopyalama gerektirmez, sadece yapraklardan birinin yaşlı ağaç olduğu yeni bir değer vardır
JaredPar

KISS - Adlandırma uygulama ayrıntılarını eklemeye başlarsa, tüm yöntem adları aşırı uzun olur. "add" yeterince basittir ve işi yapar.
mP.

1
mP: Yine "uygulama detayı" ifadesini uygun olmadığına inandığım bir şekilde kullanıyorsunuz. Bağlantılı bir liste veya başlık altında bir dizi olsun, bir uygulama ayrıntısıdır. Ben değişebilir uygulanmasını API değiştirmeden. Değişmez boyut bir uygulama detayı değildir .
Jon Skeet

1
sağ. JaredPar, ama aslında ağacı kopyalamasının veya sadece mevcut ağacı kullanmasının ve geri dönen yeni ağaç için bir yaprak olarak kullanmasının da önemli olmadığını düşünüyorum . yani bu sadece bir uygulama detayı. Java'nın dize sınıfı için alt dize işlemi için (i inanıyorum) aynıdır.
Johannes Schaub - litb


5

Ben düşünüyorum Plus()ve Minus()ya alternatif olarak Including(), Excluding()en makul ima değişmez davranış.

Ancak, hiçbir adlandırma seçeneği hiç herkes için mükemmel açık hale getirecek, bu yüzden ben şahsen iyi bir xml doc yorum burada çok uzun bir yol gidecek inanıyoruz. IDE'de kod yazarken VS bunları yüzünüze doğru atar - görmezden gelmek zordur.


4

Append - çünkü, System.String yöntemlerin örneği değiştirdiklerini önerdiklerini, ancak değiştirmediklerini unutmayın.

Yoksa oldukça beğendim AfterAppending:

void test()
{
  Bar bar = new Bar();
  List list = bar.AfterAppending("foo");
}

O kadar çok programcılar gerçeği olmasaydı DateTime argümanı önceki gibi, ben önceliği hak verirdim do dize yöntemleri şeyler bekliyoruz. Onlara (bazen tekrar tekrar) dizelerin değişmez olduğu söylenmelidir. Müşteri geliştiricilerimi başarı çukuruna çekmek istiyorum :)
Jon Skeet

Ben daha fazla ve daha fazla ekle seviyorum. Koleksiyonu mutasyona uğratmadığınızı, ona katıldığınızı ayırt eder.

4

list.CopyWith(element)

Smalltalk gibi :)

Ve ayrıca list.copyWithout(element), bir öğenin tüm oluşumlarını kaldırır; bu, list.copyWithout(null)ayarlanmamış öğeleri kaldırmak için kullanıldığında en kullanışlıdır .


3

Daha iyi bir adın faydasını görebildiğim için Add'i seçerdim, ancak sorun, bu mantıklıysa sınıfı oldukça tanıdık kılabilecek diğer her değişmez işlem için farklı adlar bulmak olacaktır.


Evet, ne demek istediğini anlıyorum. Sanırım hala Plus'ı tercih ediyorum, ama dikkate değer bir nokta.
Jon Skeet

Teşekkürler Jon. Çerçevenizi kullanmayı dört gözle bekliyorum. Sadece okudum ve çok iyi görünüyor. Tekrar teşekkürler.
Joan Venge
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.