Przepraszam za gofrowny tytuł - gdybym mógł wymyślić zwięzły tytuł, nie musiałbym zadawać pytania.
Załóżmy, że mam niezmienny typ listy. Ma operację, Foo(x)
która zwraca nową niezmienną listę z określonym argumentem jako dodatkowy element na końcu. Aby stworzyć listę ciągów znaków z wartościami „Cześć”, „niezmienny”, „świat” możesz napisać:
var empty = new ImmutableList<string>();
var list1 = empty.Foo("Hello");
var list2 = list1.Foo("immutable");
var list3 = list2.Foo("word");
(To jest kod C # i najbardziej interesuje mnie sugestia C #, jeśli uważasz, że język jest ważny. Nie jest to zasadniczo pytanie językowe, ale idiomy języka mogą być ważne.)
Ważne jest to, że istniejące listy nie są zmieniane przez Foo
- więc empty.Count
nadal zwracałby 0.
Innym (bardziej idiomatycznym) sposobem dojścia do wyniku końcowego byłoby:
var list = new ImmutableList<string>().Foo("Hello")
.Foo("immutable")
.Foo("word");
Moje pytanie brzmi: jakie jest najlepsze imię dla Foo?
EDYCJA 3 : Jak ujawnię później, nazwa typu może nie być tak naprawdę ImmutableList<T>
, co wyjaśnia pozycję. Wyobraź sobie, że jest TestSuite
i jest niezmienny, ponieważ cały szkielet, którego jest częścią, jest niezmienny ...
(Koniec edycji 3)
Opcje, które do tej pory wymyśliłem:
Add
: wspólne w .NET, ale oznacza mutację oryginalnej listyCons
: Uważam, że jest to normalna nazwa w językach funkcjonalnych, ale bez znaczenia dla osób bez doświadczenia w takich językachPlus
: jak dotąd mój ulubiony, nie oznacza to dla mnie mutacji . Najwyraźniej jest to również używane w Haskell, ale z nieco innymi oczekiwaniami (programista Haskell może oczekiwać, że doda dwie listy razem zamiast dodawać jedną wartość do drugiej listy).With
: zgodny z niektórymi niezmiennymi konwencjami, ale nie ma w tym samym stopniu „dodatkowości” IMO.And
: niezbyt opisowy.- Przeciążenie operatora dla +: Naprawdę tak bardzo nie lubię; Ogólnie myślę, że operatory powinny być stosowane tylko do typów niższych poziomów. Chcę się jednak przekonać!
Kryteria, których używam do wyboru to:
- Daje prawidłowe wrażenie wyniku wywołania metody (tzn. Że jest to oryginalna lista z dodatkowym elementem)
- Wyjaśnia, jak to możliwe, że nie mutuje istniejącej listy
- Brzmi rozsądnie, gdy są połączone w łańcuch, jak w drugim przykładzie powyżej
Poproś o więcej szczegółów, jeśli nie wyrażę się wystarczająco jasno ...
EDIT 1: Oto moje rozumowanie dla preferując Plus
do Add
. Rozważ te dwa wiersze kodu:
list.Add(foo);
list.Plus(foo);
Moim zdaniem (i jest to sprawa osobista) ta ostatnia jest wyraźnie błędna - przypomina pisanie „x + 5;” jako samodzielne oświadczenie. Pierwszy wiersz wygląda, jakby był w porządku, dopóki nie przypomnisz sobie, że jest niezmienny. W rzeczywistości sposób, w jaki operator plus sam nie mutuje operandów, jest kolejnym powodem, dla którego Plus
jestem moim ulubionym. Bez lekkiej uciążliwości przeciążania operatora wciąż daje to te same konotacje, które obejmują (dla mnie) nie mutowanie operandów (w tym przypadku cel metody).
EDYCJA 2: Powody, dla których nie lubisz Dodaj.
Różne odpowiedzi są skuteczne: „Idź z Add. To właśnie DateTime
działa i String
ma Replace
metody itp., Które nie sprawiają, że niezmienność jest oczywista”. Zgadzam się - tutaj jest pierwszeństwo. Jednak widziałem mnóstwo ludzi zadzwonić DateTime.Add
albo String.Replace
i oczekiwać mutację . Istnieje mnóstwo pytań do grup dyskusyjnych (i prawdopodobnie TAK, jeśli się rozejrzę), na które odpowiada: „Ignorujesz zwracaną wartość String.Replace
; ciągi są niezmienne, zwracany jest nowy ciąg”.
Teraz powinienem ujawnić subtelność pytania - ten typ może nie być listą niezmienną, ale innym niezmiennym typem. W szczególności pracuję nad strukturą testów porównawczych, w której dodajesz testy do pakietu, a to tworzy nowy pakiet. Może być oczywiste, że:
var list = new ImmutableList<string>();
list.Add("foo");
niczego nie osiągnie, ale staje się o wiele bardziej mętny, kiedy zmienisz na:
var suite = new TestSuite<string, int>();
suite.Add(x => x.Length);
Wygląda na to, że powinno być w porządku. Tymczasem dla mnie to wyjaśnia błąd:
var suite = new TestSuite<string, int>();
suite.Plus(x => x.Length);
To po prostu błaga:
var suite = new TestSuite<string, int>().Plus(x => x.Length);
Idealnie chciałbym, aby moi użytkownicy nie musieli być informowani, że zestaw testów jest niezmienny. Chcę, żeby wpadły w pułapkę sukcesu. To może nie być możliwe, ale chciałbym spróbować.
Przepraszam za nadmierne uproszczenie pierwotnego pytania, mówiąc tylko o niezmiennym typie listy. Nie wszystkie kolekcje są tak samoopisowe jak ImmutableList<T>
:)